# Modules.py -- Pamhyr
# Copyright (C) 2024-2025  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 <https://www.gnu.org/licenses/>.

# -*- coding: utf-8 -*-

import logging

from enum import Flag, auto

logger = logging.getLogger()


class IterableFlag(Flag):
    def __iter__(self):
        all = filter(
            lambda v: v in self,
            type(self).values()
        )
        return all

    @classmethod
    def values(cls):
        raise Exception("Not implemented yet")


class Modules(IterableFlag):
    NONE = 0

    # General
    STUDY = auto()
    CONFIG = auto()
    SCENARIOS = auto()

    # Modelling
    NETWORK = auto()
    GEOMETRY = auto()
    BOUNDARY_CONDITION = auto()
    LATERAL_CONTRIBUTION = auto()
    FRICTION = auto()
    INITIAL_CONDITION = auto()
    HYDRAULIC_STRUCTURES = auto()
    RESERVOIR = auto()
    SEDIMENT_LAYER = auto()
    ADDITIONAL_FILES = auto()
    OUTPUT_RK = auto()
    GEOTIFF = auto()

    # Results
    RESULTS = auto()

    # Display
    WINDOW_LIST = auto()

    @classmethod
    def values(cls):
        return [
            cls.STUDY, cls.CONFIG,
            cls.SCENARIOS,
            cls.NETWORK,
            cls.GEOMETRY,
            cls.BOUNDARY_CONDITION,
            cls.LATERAL_CONTRIBUTION,
            cls.FRICTION,
            cls.INITIAL_CONDITION,
            cls.HYDRAULIC_STRUCTURES,
            cls.RESERVOIR,
            cls.SEDIMENT_LAYER,
            cls.ADDITIONAL_FILES,
            cls.RESULTS,
            cls.WINDOW_LIST,
            cls.OUTPUT_RK,
            cls.GEOTIFF
        ]

    @classmethod
    def all(cls):
        return ~cls.NONE

    @classmethod
    def modelling(cls):
        return (
            cls.NETWORK
            | cls.GEOMETRY
            | cls.BOUNDARY_CONDITION
            | cls.LATERAL_CONTRIBUTION
            | cls.FRICTION
            | cls.INITIAL_CONDITION
            | cls.HYDRAULIC_STRUCTURES
            | cls.RESERVOIR
            | cls.SEDIMENT_LAYER
            | cls.GEOTIFF
        )

    @classmethod
    def modelling_list(cls):
        return [
            cls.SCENARIOS,
            cls.NETWORK,
            cls.GEOMETRY,
            cls.BOUNDARY_CONDITION,
            cls.LATERAL_CONTRIBUTION,
            cls.FRICTION,
            cls.INITIAL_CONDITION,
            cls.HYDRAULIC_STRUCTURES,
            cls.RESERVOIR,
            cls.SEDIMENT_LAYER,
            cls.GEOTIFF,
        ]

    @classmethod
    def modelling_display_name(cls):
        return {
            cls.SCENARIOS: "Scenarios",
            cls.NETWORK: "Network",
            cls.GEOMETRY: "Geometry",
            cls.BOUNDARY_CONDITION: "Boundary condition",
            cls.LATERAL_CONTRIBUTION: "Lateral contribution",
            cls.FRICTION: "Friction",
            cls.INITIAL_CONDITION: "Initial condition",
            cls.HYDRAULIC_STRUCTURES: "Hydraulic structures",
            cls.RESERVOIR: "Reservoir",
            cls.SEDIMENT_LAYER: "Sediment layer",
            cls.GEOTIFF: "GeoTIFF",
        }

    def impact(self):
        res = Modules(0)
        for mod in self:
            if mod in _impact:
                for i in _impact[mod]:
                    res |= i
        return res

    def impact_set(self):
        res = []
        for mod in self:
            if mod in _impact:
                res += _impact[mod]

        return set(res)


_impact = {
    Modules.SCENARIOS: Modules.values(),
    Modules.NETWORK: [
        Modules.GEOMETRY, Modules.BOUNDARY_CONDITION,
        Modules.LATERAL_CONTRIBUTION, Modules.FRICTION,
        Modules.RESERVOIR, Modules.SEDIMENT_LAYER,
    ],
    Modules.GEOMETRY: [
        Modules.LATERAL_CONTRIBUTION, Modules.FRICTION,
        Modules.INITIAL_CONDITION, Modules.SEDIMENT_LAYER,
    ],
    Modules.BOUNDARY_CONDITION: [
        Modules.SEDIMENT_LAYER
    ],
    Modules.LATERAL_CONTRIBUTION: [],
    Modules.FRICTION: [],
    Modules.INITIAL_CONDITION: [],
    Modules.HYDRAULIC_STRUCTURES: [],
    Modules.RESERVOIR: [],
    Modules.SEDIMENT_LAYER: [],
    Modules.GEOTIFF: [],
}
