CREATE TABLE projects (
    id INTEGER NOT NULL PRIMARY KEY,
    hub_id INTEGER,
    parent_id INTEGER,
    name VARCHAR(40) NOT NULL,
    title VARCHAR(1024) NOT NULL,
    path VARCHAR UNIQUE NOT NULL,
    project_status_id INTEGER NOT NULL DEFAULT -1,
    local INTEGER NOT NULL DEFAULT 0,
    num_changes INTEGER,
    UNIQUE(hub_id,id),
    CONSTRAINT valid_name CHECK(replace(name,'/','') = name),
    FOREIGN KEY(id) REFERENCES topics(id)
        ON DELETE CASCADE,
    FOREIGN KEY(hub_id) REFERENCES hubs(id)
        ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
    FOREIGN KEY(hub_id,parent_id) REFERENCES projects(hub_id,id)
        ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
    FOREIGN KEY(parent_id) REFERENCES projects(id)
        ON DELETE CASCADE,
    FOREIGN KEY(project_status_id,id) REFERENCES project_status(id,project_id)
        DEFERRABLE INITIALLY DEFERRED
);


CREATE TRIGGER
    projects_ai_tree_1
AFTER INSERT ON
    projects
FOR EACH ROW
BEGIN

    /*
     Insert a matching row in projects_tree where both parent and child
     are set to the id of the newly inserted object. Depth is set to 0
     as both child and parent are on the same level.
     */

    INSERT INTO
        projects_tree (
            parent,
            child,
            depth
        )
    VALUES (
        NEW.id,
        NEW.id,
        0
    );

    /*
     Copy all rows that our parent had as its parents, but we modify
     the child id in these rows to be the id of currently inserted row,
     and increase depth by one.
     */

    INSERT INTO
        projects_tree (
            parent,
            child,
            depth
        )
    SELECT
        x.parent,
        NEW.id,
        x.depth + 1
    FROM
        projects_tree x
    WHERE
        x.child = NEW.parent_id
    ;

END;

/*
    Handle parent_id changes

    3. Insert the new tree data relating to the new parent
*/

CREATE TRIGGER
    projects_au_tree_4
AFTER UPDATE OF
    parent_id
ON
    projects
FOR EACH ROW WHEN
    NEW.parent_id IS NOT NULL AND
    ( OLD.parent_id IS NULL OR NEW.parent_id != OLD.parent_id )
BEGIN

    INSERT INTO
        projects_tree (parent, child, depth)
    SELECT
        r1.parent, r2.child, r1.depth + r2.depth + 1
    FROM
        projects_tree r1
    INNER JOIN
        projects_tree r2
    ON
        r2.parent = NEW.id
    WHERE
        r1.child = NEW.parent_id
    ;

END;

/*
    Handle parent_id changes

    2. Remove the tree data relating to the old parent
*/

CREATE TRIGGER
    projects_au_tree_3
AFTER UPDATE OF
    parent_id
ON
    projects
FOR EACH ROW WHEN
    OLD.parent_id IS NOT NULL AND
    ( NEW.parent_id IS NULL OR NEW.parent_id != OLD.parent_id)
BEGIN
    DELETE FROM
        projects_tree
    WHERE
        treeid IN (
            SELECT
                r2.treeid
            FROM
                projects_tree r1
            INNER JOIN
                projects_tree r2
            ON
                r1.child = r2.child AND r2.depth > r1.depth
            WHERE
                r1.parent = NEW.id
        )
    ;
END;


/*
 Handle changes to the name column
*/

CREATE TRIGGER
    projects_au_tree_1
AFTER UPDATE OF
    name,parent_id
ON
    projects
FOR EACH ROW
BEGIN

    /*
        First of all the current row
    */

    UPDATE
        projects
    SET
        path =
            CASE WHEN
                NEW.parent_id IS NOT NULL
            THEN
                (SELECT
                    pp.path
                 FROM
                    projects pp
                 WHERE
                    pp.id = NEW.parent_id
                ) || '/' || name
            WHEN
                NEW.hub_id IS NULL
            THEN
                'local/' || name
            ELSE
                name
            END
    WHERE
        id = OLD.id
    ;

    /*
        Trigger an update to our children
    */
    UPDATE
        projects
    SET
        name = name
    WHERE
        parent_id = NEW.id
    ;

END;


CREATE TRIGGER
    projects_au_tree_0
AFTER UPDATE OF
    parent_id
ON
    projects
FOR EACH ROW
BEGIN

    UPDATE
        projects
    SET
        hub_id = (
            SELECT
                pp.hub_id
            FROM
                projects pp
            WHERE
                pp.id = NEW.parent_id
        )
    WHERE
        id IN (
            SELECT
                child
            FROM
                projects_tree
            WHERE
                parent = NEW.id
        )
    ;

END;

-- TODO: some of hrp is covered by projects_tree since hubs became
-- projects
CREATE TRIGGER
    projects_au_hub_id_1
AFTER UPDATE OF
    hub_id
ON
    projects
FOR EACH ROW WHEN
    NEW.hub_id IS NOT NULL
BEGIN

    INSERT INTO
        hub_related_projects(
            hub_id,
            project_id
        )
    SELECT
        NEW.hub_id,
        NEW.id
    ;

END;



/*
 Forbid moves that would create loops:
*/

CREATE TRIGGER
    projects_bu_tree_2
BEFORE UPDATE OF
    parent_id
ON
    projects
FOR EACH ROW WHEN
    NEW.parent_id IS NOT NULL AND
    (SELECT
        COUNT(child) > 0
     FROM
        projects_tree
     WHERE
        child = NEW.parent_id AND parent = NEW.id
    )
BEGIN
    SELECT RAISE (ABORT,
        'Change blocked, because it would create loop in tree.');
END;

/*
 This implementation doesn't support changes to the primary key
*/

CREATE TRIGGER
    projects_bu_tree_1
BEFORE UPDATE OF
    id
ON
    projects
FOR EACH ROW WHEN
    OLD.id != NEW.id
BEGIN
    SELECT RAISE (ABORT, 'Changing ids is forbidden.');
END;


CREATE TRIGGER
    projects_bd_1
BEFORE DELETE ON
    projects
FOR EACH ROW
BEGIN
    SELECT debug(
        OLD.id
    );


    /*
        Any issues that were created in this project need to go, even
        if they have been pushed to other projects because a) they
        won't make sense without the original history, and be not
        deleting them can cause issue.title to be set to undef.
    */

    DELETE FROM
        issues
    WHERE
        id IN (
            SELECT
                i.id
            FROM
                issues i
            WHERE
                i.project_id = OLD.id
        )
    ;

    /*
        The following is necessary, because although FK relationships
        do result in the remove of rows from [project_]issues_tomerge,
        the deletion of rows from project/issue_deltas just inserts
        more rows. So we remove those trigger-happy rows first.
    */

    DELETE FROM
        project_deltas
    WHERE
        project_id = OLD.id
    ;


END;

CREATE TRIGGER
    projects_ad_1
AFTER DELETE ON
    projects
FOR EACH ROW
BEGIN
    SELECT debug(
        OLD.id
    );

    DELETE FROM
        topics
    WHERE
        id = OLD.id
    ;

END;

