from contextlib import closing


class Label:
    """
    database class for labels
    """

    def __init__(self, database, row):
        self.database = database

        self.identifier = row[0]
        self.project_id = row[1]
        self.parent_id = row[2]
        self.created = row[3]
        self.reference = row[4]
        self.name = row[5]

    def project(self):
        """
        get the project this label is associated with

        :return: project
        """
        return self.database.project(self.project_id)

    def set_name(self, name: str):
        """
        set this labels name

        :param name: new name
        :return:
        """
        with closing(self.database.con.cursor()) as cursor:
            cursor.execute('UPDATE labels SET name = ? WHERE id = ?', (name, self.identifier))
            self.name = name

    def set_parent(self, parent_id: int):
        """
        set this labels parent

        :param parent_id: parent's id
        :return:
        """

        # check for cyclic relationships
        def compare_children(label, identifier):
            if label.identifier == identifier:
                return False

            for child in label.children():
                if not compare_children(child, identifier):
                    return False

            return True

        if not compare_children(self, parent_id):
            raise ValueError('parent_id')

        # insert parent id
        with closing(self.database.con.cursor()) as cursor:
            cursor.execute('UPDATE labels SET parent = ? WHERE id = ?',
                           (parent_id, self.identifier))
            self.parent_id = parent_id

    def remove(self):
        """
        remove this label from the database

        :return:
        """
        with closing(self.database.con.cursor()) as cursor:
            cursor.execute('DELETE FROM labels WHERE id = ?', [self.identifier])

    def parent(self):
        """
        get this labels parent from the database

        :return: parent or None
        """
        if self.parent_id is None:
            return None

        with closing(self.database.con.cursor()) as cursor:
            cursor.execute('SELECT * FROM labels WHERE id = ? AND project = ?',
                           (self.parent_id, self.project_id))
            row = cursor.fetchone()

            if row is not None:
                return Label(self.database, row)

        return None

    def children(self):
        """
        get this labels children from the database

        :return: list of children
        """
        with closing(self.database.con.cursor()) as cursor:
            cursor.execute('SELECT * FROM labels WHERE parent = ? AND project = ?',
                           (self.identifier, self.project_id))
            return list(map(
                lambda row: Label(self.database, row),
                cursor.fetchall()
            ))
