# Scenario.py -- Pamhyr # Copyright (C) 2024 INRAE # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -*- coding: utf-8 -*- from tools import logger_exception from Model.Tools.PamhyrDB import SQLSubModel class Scenario(SQLSubModel): _id_cnt = 0 _sub_classes = [] def __init__(self, id: int = -1, name: str = "", description: str = "", x: int = 0.0, y: int = 0.0, revision: int = 0, parent=None): super(Scenario, self).__init__() self._set_id(id) self._x, self._y = x, y self._name = name self._description = description self._revision = revision self._parent = parent def _set_id(self, id): if id == -1: self._id = Scenario._id_cnt else: self._id = id Scenario._id_cnt = max( self._id + 1, Scenario._id_cnt + 1 ) @classmethod def _db_create(cls, execute): execute(""" CREATE TABLE scenario( id INTEGER PRIMARY KEY, x REAL NOT NULL DEFAULT 1000, y REAL NOT NULL DEFAULT 1000, name TEXT NOT NULL, description TEXT NOT NULL, revision INTEGER NOT NULL, parent_id INTEGER REFERENCES scenario(id) ) """) cls._create_submodel(execute) return True @classmethod def _db_add_default(cls, execute): execute( "INSERT OR REPLACE INTO " + "scenario(id, x, y, name, description, revision, parent_id) " + "VALUES (\n" + " 0, 1000, 1000, 'default', 'Default scenario',\n" + " 0, NULL\n" + ")" ) @classmethod def create_db_add_scenario(cls): return "scenario INTEGER NOT NULL DEFAULT 0" @classmethod def create_db_add_scenario_fk(cls): return "FOREIGN KEY(scenario) REFERENCES scenario(id)" @classmethod def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == minor == "0": if int(release) < 12: cls._db_create(execute) cls._db_add_default(execute) if major == "0" and minor == "1": if int(release) < 2: execute( "ALTER TABLE scenario " + "ADD COLUMN x REAL NOT NULL DEFAULT 1000" ) execute( f"ALTER TABLE scenario " + "ADD COLUMN y REAL NOT NULL DEFAULT 1000" ) return True @classmethod def update_db_add_scenario(cls, execute, table): execute( f"ALTER TABLE {table} " + "ADD COLUMN scenario INTEGER NOT NULL DEFAULT 0" ) # execute( # f"ALTER TABLE {table} " + # "ADD CONSTRAINT fk_scenario FOREIGN KEY (scenario) " + # "REFERENCES scenario(id)" # ) @classmethod def _db_load(cls, execute, data=None): scenarios = {} table = execute( "SELECT id, x, y, name, description, revision, parent_id " + "FROM scenario " + "ORDER BY id ASC" ) for row in table: it = iter(row) id = next(it) x, y = next(it), next(it) name = next(it) desc = next(it) revi = next(it) parent = next(it) if parent is not None: parent = scenarios[parent] new = cls( id=id, x=x, y=y, name=name, description=desc, revision=revi, parent=parent ) scenarios[id] = new return scenarios def _db_save(self, execute, data=None): parent = 'NULL' if self.parent is not None: parent = self.parent._id execute( "INSERT OR REPLACE INTO " + "scenario(id, x, y, name, description, revision, parent_id) " + "VALUES (" + f"{self._id}, " + f"{self.x}, {self.y}, " + f"'{self._db_format(self.name)}', " + f"'{self._db_format(self.description)}', " + f"{self._revision}, " + f"{parent}" + ")" ) return True @property def id(self): return self._id @property def x(self): return self._x @property def y(self): return self._y @property def name(self): if self._name == "": return f"Child of '{self._parent.name}'" return self._name @name.setter def name(self, name): self._name = name # self.modified() @property def description(self): if self._description == "": return f"Child of '{self._parent.name}'" return self._description @description.setter def description(self, description): self._description = description # self.modified() @property def revision(self): return self._revision @revision.setter def revision(self, revision): self._revision = revision # self.modified() @property def parent(self): return self._parent def set_pos(self, x, y): self._x = x self._y = y # self.modified() def __setitem__(self, key, value): if key == "name": self.name = value elif key == "description": self.description = value # self.modified() def __getitem__(self, key): if key == "name": return self.name if key == "description": return self.description if key == "parent": return self.parent return None