SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO

IF OBJECT_ID(N'dbo.LocationTypes', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.LocationTypes
    (
        LocationTypeID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_LocationTypes PRIMARY KEY,
        TypeName nvarchar(100) NOT NULL,
        SortOrder int NOT NULL,
        IsActive bit NOT NULL CONSTRAINT DF_LocationTypes_IsActive DEFAULT 1,
        CONSTRAINT UQ_LocationTypes_TypeName UNIQUE (TypeName)
    );
END;
GO

IF OBJECT_ID(N'dbo.Locations', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.Locations
    (
        LocationID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Locations PRIMARY KEY,
        ProjectID int NOT NULL,
        ParentLocationID int NULL,
        LocationName nvarchar(200) NOT NULL,
        LocationTypeID int NULL,
        Description nvarchar(max) NULL,
        CreatedDate datetime2 NOT NULL CONSTRAINT DF_Locations_CreatedDate DEFAULT SYSUTCDATETIME(),
        UpdatedDate datetime2 NOT NULL CONSTRAINT DF_Locations_UpdatedDate DEFAULT SYSUTCDATETIME(),
        IsArchived bit NOT NULL CONSTRAINT DF_Locations_IsArchived DEFAULT 0,
        CONSTRAINT FK_Locations_Projects FOREIGN KEY (ProjectID) REFERENCES dbo.Projects(ProjectID),
        CONSTRAINT FK_Locations_Parent FOREIGN KEY (ParentLocationID) REFERENCES dbo.Locations(LocationID),
        CONSTRAINT FK_Locations_Types FOREIGN KEY (LocationTypeID) REFERENCES dbo.LocationTypes(LocationTypeID)
    );
END;
GO

IF OBJECT_ID(N'dbo.LocationRelationshipTypes', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.LocationRelationshipTypes
    (
        LocationRelationshipTypeID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_LocationRelationshipTypes PRIMARY KEY,
        TypeName nvarchar(100) NOT NULL,
        SortOrder int NOT NULL,
        IsActive bit NOT NULL CONSTRAINT DF_LocationRelationshipTypes_IsActive DEFAULT 1,
        CONSTRAINT UQ_LocationRelationshipTypes_TypeName UNIQUE (TypeName)
    );
END;
GO

IF OBJECT_ID(N'dbo.LocationRelationships', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.LocationRelationships
    (
        LocationRelationshipID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_LocationRelationships PRIMARY KEY,
        FromLocationID int NOT NULL,
        ToLocationID int NOT NULL,
        LocationRelationshipTypeID int NOT NULL,
        IsBidirectional bit NOT NULL CONSTRAINT DF_LocationRelationships_IsBidirectional DEFAULT 0,
        Strength int NULL,
        CanHearNormalSpeech bit NOT NULL CONSTRAINT DF_LocationRelationships_CanHearNormalSpeech DEFAULT 0,
        CanHearLoudNoise bit NOT NULL CONSTRAINT DF_LocationRelationships_CanHearLoudNoise DEFAULT 0,
        CanSeeMovement bit NOT NULL CONSTRAINT DF_LocationRelationships_CanSeeMovement DEFAULT 0,
        CanSeeClearly bit NOT NULL CONSTRAINT DF_LocationRelationships_CanSeeClearly DEFAULT 0,
        CanTravelDirectly bit NOT NULL CONSTRAINT DF_LocationRelationships_CanTravelDirectly DEFAULT 0,
        Notes nvarchar(max) NULL,
        CreatedDate datetime2 NOT NULL CONSTRAINT DF_LocationRelationships_CreatedDate DEFAULT SYSUTCDATETIME(),
        UpdatedDate datetime2 NOT NULL CONSTRAINT DF_LocationRelationships_UpdatedDate DEFAULT SYSUTCDATETIME(),
        IsArchived bit NOT NULL CONSTRAINT DF_LocationRelationships_IsArchived DEFAULT 0,
        CONSTRAINT FK_LocationRelationships_From FOREIGN KEY (FromLocationID) REFERENCES dbo.Locations(LocationID),
        CONSTRAINT FK_LocationRelationships_To FOREIGN KEY (ToLocationID) REFERENCES dbo.Locations(LocationID),
        CONSTRAINT FK_LocationRelationships_Types FOREIGN KEY (LocationRelationshipTypeID) REFERENCES dbo.LocationRelationshipTypes(LocationRelationshipTypeID)
    );
END;
GO

IF OBJECT_ID(N'dbo.SceneAssetLocations', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.SceneAssetLocations
    (
        SceneAssetLocationID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_SceneAssetLocations PRIMARY KEY,
        SceneID int NOT NULL,
        StoryAssetID int NOT NULL,
        LocationID int NOT NULL,
        Description nvarchar(max) NULL,
        CreatedDate datetime2 NOT NULL CONSTRAINT DF_SceneAssetLocations_CreatedDate DEFAULT SYSUTCDATETIME(),
        UpdatedDate datetime2 NOT NULL CONSTRAINT DF_SceneAssetLocations_UpdatedDate DEFAULT SYSUTCDATETIME(),
        CONSTRAINT FK_SceneAssetLocations_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID),
        CONSTRAINT FK_SceneAssetLocations_StoryAssets FOREIGN KEY (StoryAssetID) REFERENCES dbo.StoryAssets(StoryAssetID),
        CONSTRAINT FK_SceneAssetLocations_Locations FOREIGN KEY (LocationID) REFERENCES dbo.Locations(LocationID)
    );
END;
GO

MERGE dbo.LocationTypes AS target
USING (VALUES
    (N'Country', 10), (N'Region', 20), (N'Town', 30), (N'Village', 40), (N'Street', 50),
    (N'Building', 60), (N'Floor', 70), (N'Room', 80), (N'Outdoor Area', 90), (N'Vehicle Interior', 100),
    (N'Landmark', 110), (N'Other', 120)
) AS source (TypeName, SortOrder)
ON target.TypeName = source.TypeName
WHEN NOT MATCHED THEN INSERT (TypeName, SortOrder) VALUES (source.TypeName, source.SortOrder);
GO

MERGE dbo.LocationRelationshipTypes AS target
USING (VALUES
    (N'Adjacent To', 10), (N'Above', 20), (N'Below', 30), (N'Connected To', 40), (N'Visible From', 50),
    (N'Audible From', 60), (N'Near', 70), (N'Leads To', 80), (N'Overlooks', 90),
    (N'Same Building As', 100), (N'Same Area As', 110), (N'Secret Passage', 120), (N'Road Connection', 130)
) AS source (TypeName, SortOrder)
ON target.TypeName = source.TypeName
WHEN NOT MATCHED THEN INSERT (TypeName, SortOrder) VALUES (source.TypeName, source.SortOrder);
GO

CREATE OR ALTER VIEW dbo.LocationPaths
AS
WITH LocationTree AS
(
    SELECT LocationID, ProjectID, ParentLocationID, LocationName, LocationTypeID, Description,
        CAST(LocationName AS nvarchar(max)) AS LocationPath,
        CAST(RIGHT('000000' + CAST(LocationID AS varchar(6)), 6) AS nvarchar(max)) AS SortPath,
        0 AS Depth
    FROM dbo.Locations
    WHERE ParentLocationID IS NULL AND IsArchived = 0
    UNION ALL
    SELECT child.LocationID, child.ProjectID, child.ParentLocationID, child.LocationName, child.LocationTypeID, child.Description,
        CAST(parent.LocationPath + N' > ' + child.LocationName AS nvarchar(max)),
        CAST(parent.SortPath + N'.' + RIGHT('000000' + CAST(child.LocationID AS varchar(6)), 6) AS nvarchar(max)),
        parent.Depth + 1
    FROM dbo.Locations child
    INNER JOIN LocationTree parent ON parent.LocationID = child.ParentLocationID
    WHERE child.IsArchived = 0
)
SELECT LocationID, ProjectID, ParentLocationID, LocationName, LocationTypeID, Description, LocationPath, SortPath, Depth
FROM LocationTree;
GO

CREATE OR ALTER PROCEDURE dbo.LocationLookup_All
AS
BEGIN
    SET NOCOUNT ON;
    SELECT LocationTypeID, TypeName, SortOrder, IsActive FROM dbo.LocationTypes WHERE IsActive = 1 ORDER BY SortOrder;
    SELECT LocationRelationshipTypeID, TypeName, SortOrder, IsActive FROM dbo.LocationRelationshipTypes WHERE IsActive = 1 ORDER BY SortOrder;
END;
GO

CREATE OR ALTER PROCEDURE dbo.Location_ListByProject
    @ProjectID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT lp.LocationID, lp.ProjectID, lp.ParentLocationID, lp.LocationName, lp.LocationTypeID, lt.TypeName AS LocationTypeName,
        lp.Description, lp.LocationPath, lp.Depth, l.CreatedDate, l.UpdatedDate, l.IsArchived
    FROM dbo.LocationPaths lp
    INNER JOIN dbo.Locations l ON l.LocationID = lp.LocationID
    LEFT JOIN dbo.LocationTypes lt ON lt.LocationTypeID = lp.LocationTypeID
    WHERE lp.ProjectID = @ProjectID
    ORDER BY lp.SortPath;
END;
GO

CREATE OR ALTER PROCEDURE dbo.LocationTree_GetByProject
    @ProjectID int
AS
BEGIN
    SET NOCOUNT ON;
    EXEC dbo.Location_ListByProject @ProjectID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.Location_Get
    @LocationID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT lp.LocationID, lp.ProjectID, lp.ParentLocationID, parent.LocationName AS ParentLocationName,
        lp.LocationName, lp.LocationTypeID, lt.TypeName AS LocationTypeName, lp.Description, lp.LocationPath, lp.Depth,
        l.CreatedDate, l.UpdatedDate, l.IsArchived
    FROM dbo.LocationPaths lp
    INNER JOIN dbo.Locations l ON l.LocationID = lp.LocationID
    LEFT JOIN dbo.Locations parent ON parent.LocationID = lp.ParentLocationID
    LEFT JOIN dbo.LocationTypes lt ON lt.LocationTypeID = lp.LocationTypeID
    WHERE lp.LocationID = @LocationID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.Location_Save
    @LocationID int = NULL,
    @ProjectID int,
    @ParentLocationID int = NULL,
    @LocationName nvarchar(200),
    @LocationTypeID int = NULL,
    @Description nvarchar(max) = NULL
AS
BEGIN
    SET NOCOUNT ON;
    IF @LocationID IS NULL OR @LocationID = 0
    BEGIN
        INSERT dbo.Locations (ProjectID, ParentLocationID, LocationName, LocationTypeID, Description)
        VALUES (@ProjectID, @ParentLocationID, @LocationName, @LocationTypeID, @Description);
        SET @LocationID = CAST(SCOPE_IDENTITY() AS int);
    END
    ELSE
    BEGIN
        UPDATE dbo.Locations
        SET ParentLocationID = @ParentLocationID, LocationName = @LocationName, LocationTypeID = @LocationTypeID,
            Description = @Description, UpdatedDate = SYSUTCDATETIME()
        WHERE LocationID = @LocationID;
    END
    SELECT @LocationID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.Location_Archive
    @LocationID int
AS
BEGIN
    SET NOCOUNT ON;
    UPDATE dbo.Locations SET IsArchived = 1, UpdatedDate = SYSUTCDATETIME() WHERE LocationID = @LocationID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.LocationRelationship_ListByLocation
    @LocationID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT lr.LocationRelationshipID, lr.FromLocationID, fromLocation.LocationName AS FromLocationName,
        lr.ToLocationID, toLocation.LocationName AS ToLocationName, lr.LocationRelationshipTypeID,
        lrt.TypeName AS RelationshipTypeName, lr.IsBidirectional, lr.Strength,
        lr.CanHearNormalSpeech, lr.CanHearLoudNoise, lr.CanSeeMovement, lr.CanSeeClearly, lr.CanTravelDirectly,
        lr.Notes, lr.CreatedDate, lr.UpdatedDate, lr.IsArchived
    FROM dbo.LocationRelationships lr
    INNER JOIN dbo.Locations fromLocation ON fromLocation.LocationID = lr.FromLocationID
    INNER JOIN dbo.Locations toLocation ON toLocation.LocationID = lr.ToLocationID
    INNER JOIN dbo.LocationRelationshipTypes lrt ON lrt.LocationRelationshipTypeID = lr.LocationRelationshipTypeID
    WHERE lr.IsArchived = 0 AND @LocationID IN (lr.FromLocationID, lr.ToLocationID)
    ORDER BY lrt.SortOrder, fromLocation.LocationName, toLocation.LocationName;
END;
GO

CREATE OR ALTER PROCEDURE dbo.LocationRelationship_Save
    @LocationRelationshipID int = NULL,
    @FromLocationID int,
    @ToLocationID int,
    @LocationRelationshipTypeID int,
    @IsBidirectional bit,
    @Strength int = NULL,
    @CanHearNormalSpeech bit,
    @CanHearLoudNoise bit,
    @CanSeeMovement bit,
    @CanSeeClearly bit,
    @CanTravelDirectly bit,
    @Notes nvarchar(max) = NULL
AS
BEGIN
    SET NOCOUNT ON;
    IF @LocationRelationshipID IS NULL OR @LocationRelationshipID = 0
    BEGIN
        INSERT dbo.LocationRelationships (FromLocationID, ToLocationID, LocationRelationshipTypeID, IsBidirectional, Strength,
            CanHearNormalSpeech, CanHearLoudNoise, CanSeeMovement, CanSeeClearly, CanTravelDirectly, Notes)
        VALUES (@FromLocationID, @ToLocationID, @LocationRelationshipTypeID, @IsBidirectional, @Strength,
            @CanHearNormalSpeech, @CanHearLoudNoise, @CanSeeMovement, @CanSeeClearly, @CanTravelDirectly, @Notes);
        SET @LocationRelationshipID = CAST(SCOPE_IDENTITY() AS int);
    END
    ELSE
    BEGIN
        UPDATE dbo.LocationRelationships
        SET FromLocationID = @FromLocationID, ToLocationID = @ToLocationID,
            LocationRelationshipTypeID = @LocationRelationshipTypeID, IsBidirectional = @IsBidirectional,
            Strength = @Strength, CanHearNormalSpeech = @CanHearNormalSpeech, CanHearLoudNoise = @CanHearLoudNoise,
            CanSeeMovement = @CanSeeMovement, CanSeeClearly = @CanSeeClearly, CanTravelDirectly = @CanTravelDirectly,
            Notes = @Notes, UpdatedDate = SYSUTCDATETIME()
        WHERE LocationRelationshipID = @LocationRelationshipID;
    END
    SELECT @LocationRelationshipID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.Scene_Save
    @SceneID int = NULL, @ChapterID int, @SceneNumber decimal(10,2), @SceneTitle nvarchar(200), @Summary nvarchar(max) = NULL,
    @TimeModeID int, @StartDateTime datetime2 = NULL, @EndDateTime datetime2 = NULL, @DurationAmount decimal(10,2) = NULL,
    @DurationUnitID int = NULL, @RelativeTimeText nvarchar(200) = NULL, @TimeConfidenceID int,
    @ScenePurposeNotes nvarchar(max) = NULL, @SceneOutcomeNotes nvarchar(max) = NULL, @RevisionStatusID int,
    @PrimaryLocationID int = NULL
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @NextSortOrder int;
    IF @SceneID IS NULL OR @SceneID = 0
    BEGIN
        SELECT @NextSortOrder = ISNULL(MAX(SortOrder), 0) + 10 FROM dbo.Scenes WHERE ChapterID = @ChapterID;
        INSERT dbo.Scenes (ChapterID, SceneNumber, SceneTitle, Summary, SortOrder, TimeModeID, StartDateTime, EndDateTime,
            DurationAmount, DurationUnitID, RelativeTimeText, TimeConfidenceID, ScenePurposeNotes, SceneOutcomeNotes, RevisionStatusID, PrimaryLocationID)
        VALUES (@ChapterID, @SceneNumber, @SceneTitle, @Summary, @NextSortOrder, @TimeModeID, @StartDateTime, @EndDateTime,
            @DurationAmount, @DurationUnitID, @RelativeTimeText, @TimeConfidenceID, @ScenePurposeNotes, @SceneOutcomeNotes, @RevisionStatusID, @PrimaryLocationID);
        SET @SceneID = CAST(SCOPE_IDENTITY() AS int);
    END
    ELSE
    BEGIN
        UPDATE dbo.Scenes
        SET SceneNumber = @SceneNumber, SceneTitle = @SceneTitle, Summary = @Summary, TimeModeID = @TimeModeID,
            StartDateTime = @StartDateTime, EndDateTime = @EndDateTime, DurationAmount = @DurationAmount, DurationUnitID = @DurationUnitID,
            RelativeTimeText = @RelativeTimeText, TimeConfidenceID = @TimeConfidenceID, ScenePurposeNotes = @ScenePurposeNotes,
            SceneOutcomeNotes = @SceneOutcomeNotes, RevisionStatusID = @RevisionStatusID, PrimaryLocationID = @PrimaryLocationID,
            UpdatedDate = SYSUTCDATETIME()
        WHERE SceneID = @SceneID;
    END
    SELECT @SceneID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.SceneLocation_SavePrimary
    @SceneID int,
    @PrimaryLocationID int = NULL
AS
BEGIN
    SET NOCOUNT ON;
    UPDATE dbo.Scenes
    SET PrimaryLocationID = @PrimaryLocationID, UpdatedDate = SYSUTCDATETIME()
    WHERE SceneID = @SceneID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.Scene_Get
    @SceneID int
AS
BEGIN
    SET NOCOUNT ON;
    EXEC dbo.SceneMetric_EnsureDefaults @SceneID;
    SELECT s.SceneID, s.ChapterID, s.SceneNumber, s.SceneTitle, s.Summary, s.POVCharacterID, s.PrimaryLocationID,
        location.LocationName AS PrimaryLocationName, location.LocationPath AS PrimaryLocationPath,
        s.SortOrder, s.TimeModeID, tm.TimeModeName, s.StartDateTime, s.EndDateTime, s.DurationAmount, s.DurationUnitID,
        du.DurationUnitName, s.RelativeTimeText, s.TimeConfidenceID, tc.TimeConfidenceName, s.ScenePurposeNotes,
        s.SceneOutcomeNotes, s.RevisionStatusID, rs.StatusName AS RevisionStatusName, s.CreatedDate, s.UpdatedDate, s.IsArchived
    FROM dbo.Scenes s
    INNER JOIN dbo.TimeModes tm ON tm.TimeModeID = s.TimeModeID
    INNER JOIN dbo.TimeConfidences tc ON tc.TimeConfidenceID = s.TimeConfidenceID
    INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = s.RevisionStatusID
    LEFT JOIN dbo.DurationUnits du ON du.DurationUnitID = s.DurationUnitID
    LEFT JOIN dbo.LocationPaths location ON location.LocationID = s.PrimaryLocationID
    WHERE s.SceneID = @SceneID AND s.IsArchived = 0;
    SELECT ScenePurposeTypeID FROM dbo.ScenePurposes WHERE SceneID = @SceneID;
    EXEC dbo.SceneMetric_ListByScene @SceneID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.SceneCharacter_Save
    @SceneCharacterID int = NULL, @SceneID int, @CharacterID int, @RoleInSceneTypeID int = NULL, @PresenceTypeID int = NULL,
    @LocationID int = NULL, @EntryLocationID int = NULL, @ExitLocationID int = NULL,
    @AppearanceNotes nvarchar(max) = NULL, @OutfitDescription nvarchar(max) = NULL, @PhysicalCondition nvarchar(max) = NULL,
    @EmotionalState nvarchar(max) = NULL, @KnowledgeNotes nvarchar(max) = NULL
AS
BEGIN
    SET NOCOUNT ON;
    IF @SceneCharacterID IS NULL OR @SceneCharacterID = 0
        SELECT @SceneCharacterID = SceneCharacterID FROM dbo.SceneCharacters WHERE SceneID = @SceneID AND CharacterID = @CharacterID;
    IF @SceneCharacterID IS NULL OR @SceneCharacterID = 0
    BEGIN
        INSERT dbo.SceneCharacters (SceneID, CharacterID, RoleInSceneTypeID, PresenceTypeID, LocationID, EntryLocationID, ExitLocationID,
            AppearanceNotes, OutfitDescription, PhysicalCondition, EmotionalState, KnowledgeNotes)
        VALUES (@SceneID, @CharacterID, @RoleInSceneTypeID, @PresenceTypeID, @LocationID, @EntryLocationID, @ExitLocationID,
            @AppearanceNotes, @OutfitDescription, @PhysicalCondition, @EmotionalState, @KnowledgeNotes);
        SET @SceneCharacterID = CAST(SCOPE_IDENTITY() AS int);
    END
    ELSE
    BEGIN
        UPDATE dbo.SceneCharacters
        SET CharacterID = @CharacterID, RoleInSceneTypeID = @RoleInSceneTypeID, PresenceTypeID = @PresenceTypeID,
            LocationID = @LocationID, EntryLocationID = @EntryLocationID, ExitLocationID = @ExitLocationID,
            AppearanceNotes = @AppearanceNotes, OutfitDescription = @OutfitDescription, PhysicalCondition = @PhysicalCondition,
            EmotionalState = @EmotionalState, KnowledgeNotes = @KnowledgeNotes, UpdatedDate = SYSUTCDATETIME()
        WHERE SceneCharacterID = @SceneCharacterID;
    END
    SELECT @SceneCharacterID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.SceneCharacter_ListByScene
    @SceneID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT sc.SceneCharacterID, sc.SceneID, sc.CharacterID, c.ProjectID, c.CharacterName, c.ShortName, c.BirthDate, c.AgeAtSeriesStart,
        sc.RoleInSceneTypeID, role.TypeName AS RoleInSceneTypeName, sc.PresenceTypeID, presence.TypeName AS PresenceTypeName,
        sc.LocationID, location.LocationName, location.LocationPath, sc.EntryLocationID, entry.LocationName AS EntryLocationName,
        sc.ExitLocationID, exitLocation.LocationName AS ExitLocationName, sc.AppearanceNotes, sc.OutfitDescription,
        sc.PhysicalCondition, sc.EmotionalState, sc.KnowledgeNotes, sc.CreatedDate, sc.UpdatedDate
    FROM dbo.SceneCharacters sc
    INNER JOIN dbo.Characters c ON c.CharacterID = sc.CharacterID
    LEFT JOIN dbo.CharacterRoleInSceneTypes role ON role.CharacterRoleInSceneTypeID = sc.RoleInSceneTypeID
    LEFT JOIN dbo.PresenceTypes presence ON presence.PresenceTypeID = sc.PresenceTypeID
    LEFT JOIN dbo.LocationPaths location ON location.LocationID = sc.LocationID
    LEFT JOIN dbo.LocationPaths entry ON entry.LocationID = sc.EntryLocationID
    LEFT JOIN dbo.LocationPaths exitLocation ON exitLocation.LocationID = sc.ExitLocationID
    WHERE sc.SceneID = @SceneID AND c.IsArchived = 0
    ORDER BY role.SortOrder, c.CharacterName;
END;
GO

CREATE OR ALTER PROCEDURE dbo.StoryAsset_Save
    @StoryAssetID int = NULL, @ProjectID int, @AssetName nvarchar(200), @AssetKindID int, @Description nvarchar(max) = NULL,
    @Importance int, @CurrentStateID int = NULL, @CurrentLocationID int = NULL, @IsResolved bit
AS
BEGIN
    SET NOCOUNT ON;
    IF @StoryAssetID IS NULL OR @StoryAssetID = 0
    BEGIN
        INSERT dbo.StoryAssets (ProjectID, AssetName, AssetKindID, Description, Importance, CurrentStateID, CurrentLocationID, IsResolved)
        VALUES (@ProjectID, @AssetName, @AssetKindID, @Description, @Importance, @CurrentStateID, @CurrentLocationID, @IsResolved);
        SET @StoryAssetID = CAST(SCOPE_IDENTITY() AS int);
    END
    ELSE
    BEGIN
        UPDATE dbo.StoryAssets
        SET AssetName = @AssetName, AssetKindID = @AssetKindID, Description = @Description, Importance = @Importance,
            CurrentStateID = @CurrentStateID, CurrentLocationID = @CurrentLocationID, IsResolved = @IsResolved, UpdatedDate = SYSUTCDATETIME()
        WHERE StoryAssetID = @StoryAssetID;
    END
    SELECT @StoryAssetID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.SceneAssetLocation_Save
    @SceneAssetLocationID int = NULL,
    @SceneID int,
    @StoryAssetID int,
    @LocationID int,
    @Description nvarchar(max) = NULL,
    @UpdateCurrentLocation bit = 1
AS
BEGIN
    SET NOCOUNT ON;
    IF @SceneAssetLocationID IS NULL OR @SceneAssetLocationID = 0
        SELECT @SceneAssetLocationID = SceneAssetLocationID FROM dbo.SceneAssetLocations WHERE SceneID = @SceneID AND StoryAssetID = @StoryAssetID;
    IF @SceneAssetLocationID IS NULL OR @SceneAssetLocationID = 0
    BEGIN
        INSERT dbo.SceneAssetLocations (SceneID, StoryAssetID, LocationID, Description)
        VALUES (@SceneID, @StoryAssetID, @LocationID, @Description);
        SET @SceneAssetLocationID = CAST(SCOPE_IDENTITY() AS int);
    END
    ELSE
    BEGIN
        UPDATE dbo.SceneAssetLocations SET LocationID = @LocationID, Description = @Description, UpdatedDate = SYSUTCDATETIME()
        WHERE SceneAssetLocationID = @SceneAssetLocationID;
    END
    IF @UpdateCurrentLocation = 1
        UPDATE dbo.StoryAssets SET CurrentLocationID = @LocationID, UpdatedDate = SYSUTCDATETIME() WHERE StoryAssetID = @StoryAssetID;
    SELECT @SceneAssetLocationID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.SceneAssetLocation_ListByScene
    @SceneID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT sal.SceneAssetLocationID, sal.SceneID, sal.StoryAssetID, sa.AssetName, sal.LocationID,
        location.LocationName, location.LocationPath, sal.Description, sal.CreatedDate, sal.UpdatedDate
    FROM dbo.SceneAssetLocations sal
    INNER JOIN dbo.StoryAssets sa ON sa.StoryAssetID = sal.StoryAssetID
    INNER JOIN dbo.LocationPaths location ON location.LocationID = sal.LocationID
    WHERE sal.SceneID = @SceneID
    ORDER BY location.LocationPath, sa.AssetName;
END;
GO

CREATE OR ALTER PROCEDURE dbo.Timeline_GetByProject
    @ProjectID int,
    @BookID int = NULL
AS
BEGIN
    SET NOCOUNT ON;
    SELECT ProjectID, ProjectName, Description, CreatedDate, UpdatedDate, IsArchived FROM dbo.Projects WHERE ProjectID = @ProjectID AND IsArchived = 0;
    SELECT BookID, ProjectID, BookTitle, BookNumber, Description, SortOrder, CreatedDate, UpdatedDate, IsArchived
    FROM dbo.Books WHERE ProjectID = @ProjectID AND IsArchived = 0 AND (@BookID IS NULL OR BookID = @BookID) ORDER BY SortOrder, BookNumber;
    SELECT c.ChapterID, c.BookID, c.ChapterNumber, c.ChapterTitle, c.POVCharacterID, c.Summary, c.SortOrder,
        c.RevisionStatusID, rs.StatusName AS RevisionStatusName, c.CreatedDate, c.UpdatedDate, c.IsArchived
    FROM dbo.Chapters c INNER JOIN dbo.Books b ON b.BookID = c.BookID INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = c.RevisionStatusID
    WHERE b.ProjectID = @ProjectID AND c.IsArchived = 0 AND b.IsArchived = 0 AND (@BookID IS NULL OR b.BookID = @BookID)
    ORDER BY b.SortOrder, c.SortOrder;
    SELECT s.SceneID, s.ChapterID, s.SceneNumber, s.SceneTitle, s.Summary, s.POVCharacterID, s.PrimaryLocationID,
        location.LocationName AS PrimaryLocationName, location.LocationPath AS PrimaryLocationPath,
        s.SortOrder, s.TimeModeID, tm.TimeModeName, s.StartDateTime, s.EndDateTime, s.DurationAmount, s.DurationUnitID,
        du.DurationUnitName, s.RelativeTimeText, s.TimeConfidenceID, tc.TimeConfidenceName, s.ScenePurposeNotes,
        s.SceneOutcomeNotes, s.RevisionStatusID, rs.StatusName AS RevisionStatusName, s.CreatedDate, s.UpdatedDate, s.IsArchived
    FROM dbo.Scenes s
    INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID
    INNER JOIN dbo.Books b ON b.BookID = c.BookID
    INNER JOIN dbo.TimeModes tm ON tm.TimeModeID = s.TimeModeID
    INNER JOIN dbo.TimeConfidences tc ON tc.TimeConfidenceID = s.TimeConfidenceID
    INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = s.RevisionStatusID
    LEFT JOIN dbo.DurationUnits du ON du.DurationUnitID = s.DurationUnitID
    LEFT JOIN dbo.LocationPaths location ON location.LocationID = s.PrimaryLocationID
    WHERE b.ProjectID = @ProjectID AND s.IsArchived = 0 AND c.IsArchived = 0 AND b.IsArchived = 0 AND (@BookID IS NULL OR b.BookID = @BookID)
    ORDER BY b.SortOrder, c.SortOrder, s.SortOrder;
    SELECT sp.SceneID, spt.ScenePurposeTypeID, spt.PurposeName, spt.SortOrder
    FROM dbo.ScenePurposes sp INNER JOIN dbo.ScenePurposeTypes spt ON spt.ScenePurposeTypeID = sp.ScenePurposeTypeID
    INNER JOIN dbo.Scenes s ON s.SceneID = sp.SceneID INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID INNER JOIN dbo.Books b ON b.BookID = c.BookID
    WHERE b.ProjectID = @ProjectID AND (@BookID IS NULL OR b.BookID = @BookID)
    ORDER BY spt.SortOrder;
    SELECT MetricTypeID, ProjectID, MetricName, Description, MinValue, MaxValue, DefaultValue, SortOrder, IsActive FROM dbo.SceneMetricTypes WHERE IsActive = 1 AND (ProjectID IS NULL OR ProjectID = @ProjectID) ORDER BY SortOrder;
    SELECT smv.SceneID, smv.MetricTypeID, smt.MetricName, smv.Value, smv.Notes
    FROM dbo.SceneMetricValues smv INNER JOIN dbo.SceneMetricTypes smt ON smt.MetricTypeID = smv.MetricTypeID
    INNER JOIN dbo.Scenes s ON s.SceneID = smv.SceneID INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID INNER JOIN dbo.Books b ON b.BookID = c.BookID
    WHERE b.ProjectID = @ProjectID AND (@BookID IS NULL OR b.BookID = @BookID);
    SELECT pl.PlotLineID, pl.ProjectID, pl.BookID, b.BookTitle, pl.PlotLineName, pl.PlotLineTypeID, plt.TypeName AS PlotLineTypeName,
        pl.Description, pl.ParentPlotLineID, parent.PlotLineName AS ParentPlotLineName, pl.SortOrder, pl.Colour, pl.IsMainPlot, pl.IsVisibleOnTimeline,
        pl.CreatedDate, pl.UpdatedDate, pl.IsArchived
    FROM dbo.PlotLines pl INNER JOIN dbo.PlotLineTypes plt ON plt.PlotLineTypeID = pl.PlotLineTypeID LEFT JOIN dbo.Books b ON b.BookID = pl.BookID LEFT JOIN dbo.PlotLines parent ON parent.PlotLineID = pl.ParentPlotLineID
    WHERE pl.ProjectID = @ProjectID AND pl.IsArchived = 0 AND pl.IsVisibleOnTimeline = 1 AND (@BookID IS NULL OR pl.BookID IS NULL OR pl.BookID = @BookID)
    ORDER BY pl.SortOrder, pl.PlotLineName;
    SELECT te.ThreadEventID, te.PlotThreadID, pt.ThreadTitle, pt.PlotLineID, pl.PlotLineName, pl.Colour, te.SceneID, te.EventTypeID,
        tet.TypeName AS EventTypeName, tet.MarkerText, te.EventTitle, te.EventDescription, te.CreatedDate, te.UpdatedDate
    FROM dbo.ThreadEvents te INNER JOIN dbo.PlotThreads pt ON pt.PlotThreadID = te.PlotThreadID INNER JOIN dbo.PlotLines pl ON pl.PlotLineID = pt.PlotLineID
    INNER JOIN dbo.ThreadEventTypes tet ON tet.ThreadEventTypeID = te.EventTypeID INNER JOIN dbo.Scenes s ON s.SceneID = te.SceneID
    INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID INNER JOIN dbo.Books b ON b.BookID = c.BookID
    WHERE b.ProjectID = @ProjectID AND pl.IsArchived = 0 AND pt.IsArchived = 0 AND (@BookID IS NULL OR b.BookID = @BookID)
    ORDER BY pl.SortOrder, pt.ThreadTitle, b.SortOrder, c.SortOrder, s.SortOrder;
END;
GO

CREATE OR ALTER PROCEDURE dbo.LocationRelationship_ListByProject
    @ProjectID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT lr.LocationRelationshipID, lr.FromLocationID, fromLocation.LocationName AS FromLocationName,
        lr.ToLocationID, toLocation.LocationName AS ToLocationName, lr.LocationRelationshipTypeID,
        lrt.TypeName AS RelationshipTypeName, lr.IsBidirectional, lr.Strength,
        lr.CanHearNormalSpeech, lr.CanHearLoudNoise, lr.CanSeeMovement, lr.CanSeeClearly, lr.CanTravelDirectly,
        lr.Notes, lr.CreatedDate, lr.UpdatedDate, lr.IsArchived
    FROM dbo.LocationRelationships lr
    INNER JOIN dbo.Locations fromLocation ON fromLocation.LocationID = lr.FromLocationID
    INNER JOIN dbo.Locations toLocation ON toLocation.LocationID = lr.ToLocationID
    INNER JOIN dbo.LocationRelationshipTypes lrt ON lrt.LocationRelationshipTypeID = lr.LocationRelationshipTypeID
    WHERE lr.IsArchived = 0 AND fromLocation.ProjectID = @ProjectID
    ORDER BY lrt.SortOrder, fromLocation.LocationName, toLocation.LocationName;
END;
GO

CREATE OR ALTER PROCEDURE dbo.LocationRelationship_Archive
    @LocationRelationshipID int
AS
BEGIN
    SET NOCOUNT ON;
    UPDATE dbo.LocationRelationships
    SET IsArchived = 1, UpdatedDate = SYSUTCDATETIME()
    WHERE LocationRelationshipID = @LocationRelationshipID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.SceneAssetLocation_Delete
    @SceneAssetLocationID int
AS
BEGIN
    SET NOCOUNT ON;
    DELETE dbo.SceneAssetLocations WHERE SceneAssetLocationID = @SceneAssetLocationID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.SceneAssetLocation_ListByLocation
    @LocationID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT sal.SceneAssetLocationID, sal.SceneID, sal.StoryAssetID, sa.AssetName, sal.LocationID,
        location.LocationName, location.LocationPath, sal.Description, sal.CreatedDate, sal.UpdatedDate
    FROM dbo.SceneAssetLocations sal
    INNER JOIN dbo.StoryAssets sa ON sa.StoryAssetID = sal.StoryAssetID
    INNER JOIN dbo.LocationPaths location ON location.LocationID = sal.LocationID
    WHERE sal.LocationID = @LocationID
    ORDER BY sa.AssetName;
END;
GO

CREATE OR ALTER PROCEDURE dbo.LocationScene_ListByLocation
    @LocationID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT s.SceneID, s.ChapterID, s.SceneNumber, s.SceneTitle, s.Summary, s.POVCharacterID, s.PrimaryLocationID,
        location.LocationName AS PrimaryLocationName, location.LocationPath AS PrimaryLocationPath,
        s.SortOrder, s.TimeModeID, tm.TimeModeName, s.StartDateTime, s.EndDateTime, s.DurationAmount, s.DurationUnitID,
        du.DurationUnitName, s.RelativeTimeText, s.TimeConfidenceID, tc.TimeConfidenceName, s.ScenePurposeNotes,
        s.SceneOutcomeNotes, s.RevisionStatusID, rs.StatusName AS RevisionStatusName, s.CreatedDate, s.UpdatedDate, s.IsArchived
    FROM dbo.Scenes s
    INNER JOIN dbo.TimeModes tm ON tm.TimeModeID = s.TimeModeID
    INNER JOIN dbo.TimeConfidences tc ON tc.TimeConfidenceID = s.TimeConfidenceID
    INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = s.RevisionStatusID
    LEFT JOIN dbo.DurationUnits du ON du.DurationUnitID = s.DurationUnitID
    LEFT JOIN dbo.LocationPaths location ON location.LocationID = s.PrimaryLocationID
    WHERE s.PrimaryLocationID = @LocationID AND s.IsArchived = 0
    ORDER BY s.SortOrder;
END;
GO

CREATE OR ALTER PROCEDURE dbo.LocationCharacter_ListByLocation
    @LocationID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT sc.SceneCharacterID, sc.SceneID, sc.CharacterID, c.ProjectID, c.CharacterName, c.ShortName, c.BirthDate, c.AgeAtSeriesStart,
        sc.RoleInSceneTypeID, role.TypeName AS RoleInSceneTypeName, sc.PresenceTypeID, presence.TypeName AS PresenceTypeName,
        sc.LocationID, location.LocationName, location.LocationPath, sc.EntryLocationID, entry.LocationName AS EntryLocationName,
        sc.ExitLocationID, exitLocation.LocationName AS ExitLocationName, sc.AppearanceNotes, sc.OutfitDescription,
        sc.PhysicalCondition, sc.EmotionalState, sc.KnowledgeNotes, s.SceneNumber, s.SceneTitle, ch.ChapterNumber, b.BookTitle,
        sc.CreatedDate, sc.UpdatedDate
    FROM dbo.SceneCharacters sc
    INNER JOIN dbo.Characters c ON c.CharacterID = sc.CharacterID
    INNER JOIN dbo.Scenes s ON s.SceneID = sc.SceneID
    INNER JOIN dbo.Chapters ch ON ch.ChapterID = s.ChapterID
    INNER JOIN dbo.Books b ON b.BookID = ch.BookID
    LEFT JOIN dbo.CharacterRoleInSceneTypes role ON role.CharacterRoleInSceneTypeID = sc.RoleInSceneTypeID
    LEFT JOIN dbo.PresenceTypes presence ON presence.PresenceTypeID = sc.PresenceTypeID
    LEFT JOIN dbo.LocationPaths location ON location.LocationID = sc.LocationID
    LEFT JOIN dbo.LocationPaths entry ON entry.LocationID = sc.EntryLocationID
    LEFT JOIN dbo.LocationPaths exitLocation ON exitLocation.LocationID = sc.ExitLocationID
    WHERE sc.LocationID = @LocationID AND c.IsArchived = 0
    ORDER BY b.SortOrder, ch.SortOrder, s.SortOrder, c.CharacterName;
END;
GO

CREATE OR ALTER PROCEDURE dbo.LocationCharacter_ListByScene
    @SceneID int,
    @LocationID int = NULL
AS
BEGIN
    SET NOCOUNT ON;
    SELECT sc.SceneCharacterID, sc.SceneID, sc.CharacterID, c.ProjectID, c.CharacterName, c.ShortName, c.BirthDate, c.AgeAtSeriesStart,
        sc.RoleInSceneTypeID, role.TypeName AS RoleInSceneTypeName, sc.PresenceTypeID, presence.TypeName AS PresenceTypeName,
        sc.LocationID, location.LocationName, location.LocationPath, sc.EntryLocationID, entry.LocationName AS EntryLocationName,
        sc.ExitLocationID, exitLocation.LocationName AS ExitLocationName, sc.AppearanceNotes, sc.OutfitDescription,
        sc.PhysicalCondition, sc.EmotionalState, sc.KnowledgeNotes, sc.CreatedDate, sc.UpdatedDate
    FROM dbo.SceneCharacters sc
    INNER JOIN dbo.Characters c ON c.CharacterID = sc.CharacterID
    LEFT JOIN dbo.CharacterRoleInSceneTypes role ON role.CharacterRoleInSceneTypeID = sc.RoleInSceneTypeID
    LEFT JOIN dbo.PresenceTypes presence ON presence.PresenceTypeID = sc.PresenceTypeID
    LEFT JOIN dbo.LocationPaths location ON location.LocationID = sc.LocationID
    LEFT JOIN dbo.LocationPaths entry ON entry.LocationID = sc.EntryLocationID
    LEFT JOIN dbo.LocationPaths exitLocation ON exitLocation.LocationID = sc.ExitLocationID
    WHERE sc.SceneID = @SceneID AND (@LocationID IS NULL OR sc.LocationID = @LocationID) AND c.IsArchived = 0
    ORDER BY role.SortOrder, c.CharacterName;
END;
GO

CREATE OR ALTER PROCEDURE dbo.SceneAssetLocation_ListBySceneLocation
    @SceneID int,
    @LocationID int = NULL
AS
BEGIN
    SET NOCOUNT ON;
    SELECT sal.SceneAssetLocationID, sal.SceneID, sal.StoryAssetID, sa.AssetName, sal.LocationID,
        location.LocationName, location.LocationPath, sal.Description, sal.CreatedDate, sal.UpdatedDate
    FROM dbo.SceneAssetLocations sal
    INNER JOIN dbo.StoryAssets sa ON sa.StoryAssetID = sal.StoryAssetID
    INNER JOIN dbo.LocationPaths location ON location.LocationID = sal.LocationID
    WHERE sal.SceneID = @SceneID AND (@LocationID IS NULL OR sal.LocationID = @LocationID)
    ORDER BY location.LocationPath, sa.AssetName;
END;
GO

CREATE OR ALTER PROCEDURE dbo.StoryAsset_ListByProject
    @ProjectID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT sa.StoryAssetID, sa.ProjectID, sa.AssetName, sa.AssetKindID, ak.KindName, sa.Description, sa.Importance,
        sa.CurrentStateID, ast.StateName AS CurrentStateName, sa.CurrentLocationID,
        location.LocationName AS CurrentLocationName, location.LocationPath AS CurrentLocationPath,
        sa.IsResolved, sa.CreatedDate, sa.UpdatedDate, sa.IsArchived
    FROM dbo.StoryAssets sa
    INNER JOIN dbo.AssetKinds ak ON ak.AssetKindID = sa.AssetKindID
    LEFT JOIN dbo.AssetStates ast ON ast.AssetStateID = sa.CurrentStateID
    LEFT JOIN dbo.LocationPaths location ON location.LocationID = sa.CurrentLocationID
    WHERE sa.ProjectID = @ProjectID AND sa.IsArchived = 0
    ORDER BY sa.Importance DESC, sa.AssetName;
END;
GO

CREATE OR ALTER PROCEDURE dbo.StoryAsset_Get
    @StoryAssetID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT sa.StoryAssetID, sa.ProjectID, sa.AssetName, sa.AssetKindID, ak.KindName, sa.Description, sa.Importance,
        sa.CurrentStateID, ast.StateName AS CurrentStateName, sa.CurrentLocationID,
        location.LocationName AS CurrentLocationName, location.LocationPath AS CurrentLocationPath,
        sa.IsResolved, sa.CreatedDate, sa.UpdatedDate, sa.IsArchived
    FROM dbo.StoryAssets sa
    INNER JOIN dbo.AssetKinds ak ON ak.AssetKindID = sa.AssetKindID
    LEFT JOIN dbo.AssetStates ast ON ast.AssetStateID = sa.CurrentStateID
    LEFT JOIN dbo.LocationPaths location ON location.LocationID = sa.CurrentLocationID
    WHERE sa.StoryAssetID = @StoryAssetID AND sa.IsArchived = 0;
END;
GO

CREATE OR ALTER PROCEDURE dbo.AssetTimeline_GetByProject
    @ProjectID int,
    @BookID int = NULL
AS
BEGIN
    SET NOCOUNT ON;
    SELECT sa.StoryAssetID, sa.ProjectID, sa.AssetName, sa.AssetKindID, ak.KindName, sa.Description, sa.Importance,
        sa.CurrentStateID, ast.StateName AS CurrentStateName, sa.CurrentLocationID,
        location.LocationName AS CurrentLocationName, location.LocationPath AS CurrentLocationPath,
        sa.IsResolved, sa.CreatedDate, sa.UpdatedDate, sa.IsArchived
    FROM dbo.StoryAssets sa
    INNER JOIN dbo.AssetKinds ak ON ak.AssetKindID = sa.AssetKindID
    LEFT JOIN dbo.AssetStates ast ON ast.AssetStateID = sa.CurrentStateID
    LEFT JOIN dbo.LocationPaths location ON location.LocationID = sa.CurrentLocationID
    WHERE sa.ProjectID = @ProjectID AND sa.IsArchived = 0 AND (sa.Importance >= 5 OR sa.IsResolved = 0)
    ORDER BY sa.Importance DESC, sa.AssetName;

    SELECT ae.AssetEventID, ae.StoryAssetID, sa.ProjectID, sa.AssetName, sa.AssetKindID, ak.KindName,
        ae.SceneID, ae.AssetEventTypeID, aet.TypeName AS AssetEventTypeName, aet.MarkerText,
        ae.FromStateID, fs.StateName AS FromStateName, ae.ToStateID, ts.StateName AS ToStateName,
        ae.EventTitle, ae.EventDescription, ae.CreatedDate, ae.UpdatedDate
    FROM dbo.AssetEvents ae
    INNER JOIN dbo.StoryAssets sa ON sa.StoryAssetID = ae.StoryAssetID
    INNER JOIN dbo.AssetKinds ak ON ak.AssetKindID = sa.AssetKindID
    INNER JOIN dbo.AssetEventTypes aet ON aet.AssetEventTypeID = ae.AssetEventTypeID
    INNER JOIN dbo.Scenes s ON s.SceneID = ae.SceneID
    INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID
    INNER JOIN dbo.Books b ON b.BookID = c.BookID
    LEFT JOIN dbo.AssetStates fs ON fs.AssetStateID = ae.FromStateID
    LEFT JOIN dbo.AssetStates ts ON ts.AssetStateID = ae.ToStateID
    WHERE sa.ProjectID = @ProjectID AND sa.IsArchived = 0 AND (@BookID IS NULL OR b.BookID = @BookID)
    ORDER BY b.SortOrder, c.SortOrder, s.SortOrder, sa.AssetName;
END;
GO
