from pathlib import Path import json import shutil from datetime import datetime from warchron.model.player import Player from warchron.model.war import War, Objective, WarParticipant from warchron.model.campaign import Campaign from warchron.model.round import Round class Model: def __init__(self): self.players: dict[str, Player] = {} self.wars: dict[str, War] = {} # File management methods def new(self): self.players.clear() self.wars.clear() def load(self, path: Path): self.players.clear() self.wars.clear() self._load_data(path) def save(self, path: Path): self._save_data(path) def _load_data(self, path: Path): if not path.exists() or path.stat().st_size == 0: return # Start empty try: with open(path, "r", encoding="utf-8") as f: data = json.load(f) self.players.clear() self.wars.clear() for p in data.get("players", []): player = Player.fromDict(p) self.players[player.id] = player for w in data.get("wars", []): war = War.fromDict(w) self.wars[war.id] = war except json.JSONDecodeError: raise RuntimeError("Data file is corrupted") def _save_data(self, path: Path): if path.exists(): shutil.copy(path, path.with_suffix(".json.bak")) data = { "version": "1.0", "players": [p.toDict() for p in self.players.values()], "wars": [w.toDict() for w in self.wars.values()] } with open(path, "w", encoding="utf-8") as f: json.dump(data, f, indent=2) # Player methods def add_player(self, name): player = Player(name) self.players[player.id] = player return player def get_player(self, id): return self.players[id] def get_player_name(self, player_id: str) -> str: return self.players[player_id].name def update_player(self, player_id: str, *, name: str): player = self.get_player(player_id) player.set_name(name) def get_all_players(self) -> list[Player]: return list(self.players.values()) def remove_player(self, player_id: str): del self.players[player_id] # War methods def get_default_war_values(self) -> dict: return { "year": datetime.now().year } def add_war(self, name: str, year: int) -> War: war = War(name, year) self.wars[war.id] = war return war def get_war(self, id) -> War: return self.wars[id] def get_war_by_campaign(self, campaign_id: str) -> War: for war in self.wars.values(): for camp in war.campaigns: if camp.id == campaign_id: return war raise KeyError(f"Campaign {campaign_id} not found in any War") def get_war_by_objective(self, objective_id: str) -> War: for war in self.wars.values(): for obj in war.objectives.values(): if obj.id == objective_id: return war raise KeyError(f"Objective {objective_id} not found in any War") def get_war_by_war_participant(self, participant_id: str) -> War: for war in self.wars.values(): for part in war.participants.values(): if part.id == participant_id: return war raise KeyError(f"Participant {participant_id} not found in any War") def update_war(self, war_id: str, *, name: str, year: int): war = self.get_war(war_id) war.set_name(name) war.set_year(year) def get_all_wars(self) -> list[War]: return list(self.wars.values()) def remove_war(self, war_id: str): del self.wars[war_id] # Objective methods def add_objective(self, war_id: str, name: str, description: str) -> Objective: war = self.get_war(war_id) return war.add_objective(name, description) def get_objective(self, objective_id) -> Objective: for war in self.wars.values(): for obj in war.objectives.values(): if obj.id == objective_id: return obj raise KeyError("Objective not found") def update_objective(self, objective_id: str, *, name: str, description: str): war = self.get_war_by_objective(objective_id) war.update_objective(objective_id, name=name, description=description) def remove_objective(self, objective_id: str): war = self.get_war_by_objective(objective_id) war.remove_objective(objective_id) # War participant methods def get_available_players(self, war_id: str) -> list[Player]: war = self.get_war(war_id) return [ player for player in self.players.values() if not war.has_participant(player.id) ] def add_war_participant(self, war_id: str, player_id: str, faction: str) -> Objective: war = self.get_war(war_id) return war.add_war_participant(player_id, faction) def get_war_participant(self, participant_id) -> WarParticipant: for war in self.wars.values(): for part in war.participants.values(): if part.id == participant_id: return part raise KeyError("Participant not found") def update_war_participant(self, participant_id: str, *, faction: str): war = self.get_war_by_war_participant(participant_id) war.update_war_participant(participant_id, faction=faction) def remove_war_participant(self, participant_id: str): war = self.get_war_by_war_participant(participant_id) war.remove_war_participant(participant_id) # Campaign methods def get_default_campaign_values(self, war_id: str) -> dict: war = self.get_war(war_id) return war.get_default_campaign_values() def add_campaign(self, war_id: str, name: str, month: int) -> Campaign: war = self.get_war(war_id) return war.add_campaign(name, month) def get_campaign(self, campaign_id) -> Campaign: for war in self.wars.values(): for campaign in war.campaigns: if campaign.id == campaign_id: return campaign raise KeyError("Campaign not found") def get_campaign_by_round(self, round_id: str) -> Campaign: for war in self.wars.values(): camp = war.get_campaign_by_round(round_id) if camp is not None: return camp raise KeyError(f"Round {round_id} not found") def update_campaign(self, campaign_id: str, *, name: str, month: int): war = self.get_war_by_campaign(campaign_id) war.update_campaign(campaign_id, name=name, month=month) def remove_campaign(self, campaign_id: str): war = self.get_war_by_campaign(campaign_id) war.remove_campaign(campaign_id) # Round methods def add_round(self, campaign_id: str) -> Round: campaign = self.get_campaign(campaign_id) return campaign.add_round() def get_round(self, round_id: str) -> Round: for war in self.wars.values(): for campaign in war.campaigns: for rnd in campaign.rounds: if rnd.id == round_id: return rnd raise KeyError("Round not found") def get_round_index(self, round_id: str) -> int: camp = self.get_campaign_by_round(round_id) return camp.get_round_index(round_id) def remove_round(self, round_id: str): camp = self.get_campaign_by_round(round_id) camp.remove_round(round_id)