#
# Copyright (C) 2019-Present A-Team Digital Solutions
#
"""
Project State Manager

Stores all information about the currently
selected ROM, device and build options.

No GTK code belongs in this file.
"""

from dataclasses import dataclass, field
import os
import re

@dataclass
class Project:
    #
    # Project Profile
    #
    profile_name: str = ""
    profile_modified: bool = False
    #
    # Build Host
    #
    host_name: str = "Local"
    #
    # Device
    #
    device_name: str = ""
    #
    # ROM
    #
    rom_name: str = ""
    rom_branch: str = ""
    #
    # Android
    #
    android_version: str = "16"
    #
    # Paths
    #
    rom_path: str = ""
    #
    # Build
    #
    build_variant: str = "userdebug"
    build_command: str = ""
    gapps_variant: str = "vanilla"
    clean_variant: str = "full"
    installer_variant: str = "custom"
    build_jobs: int = 6
    use_ccache: bool = True
    custom_apn: bool = False
    #
    # Config Variables
    #
    device_vars: dict = field(default_factory=dict)
    rom_vars: dict = field(default_factory=dict)
    rom_config_path: str = ""
    setup_vars: dict = field(default_factory=dict)
    upload_vars: dict = field(default_factory=dict)
    #
    # Helper Methods
    #
    def set_device(self, device):
        self.device_name = device
    def set_rom_path(self, path):
        self.rom_path = path
        if path:
            import os
            self.rom_branch = os.path.basename(path)
            self.rom_name = os.path.basename(
                os.path.dirname(path)
            )
    @staticmethod
    def _resolve_variables(env):
        resolved = dict(env)
        pattern = re.compile(
            r"\$(\{([A-Za-z_][A-Za-z0-9_]*)\}|([A-Za-z_][A-Za-z0-9_]*))"
        )
        for _ in range(10):
            changed = False
            for key, value in resolved.items():
                if not isinstance(value, str):
                    continue
                def replace(match):
                    variable = match.group(2) or match.group(3)
                    return str(
                        resolved.get(
                            variable,
                            match.group(0)
                        )
                    )
                new_value = pattern.sub(replace, value)
                if new_value != value:
                    resolved[key] = new_value
                    changed = True
            if not changed:
                break
        return resolved
    def as_environment(self):
        env = {
            "DEVICE_NAME":
                self.device_name,
            "ROM_NAME":
                self.rom_name,
            "ROM_BRANCH":
                self.rom_branch,
            "ROM_PATH":
                self.rom_path,
            "ANDROID_VERSION":
                self.android_version,
            "BUILD_VARIANT":
                self.build_variant,
            "BUILD_COMMAND":
                self.build_command,
            "GAPPS_VARIANT":
                self.gapps_variant,
            "CLEAN_VARIANT":
                self.clean_variant,
            "INSTALLER_VARIANT":
                self.installer_variant,
            "BUILD_JOBS":
                str(self.build_jobs),
            "USE_CCACHE":
                "1" if self.use_ccache else "2",
            "APN_VARIANT":
                "1" if self.custom_apn else "2"
        }
        env.update(self.device_vars)
        env.update(self.rom_vars)
        env.update(self.setup_vars)
        env.update(self.upload_vars)
        #
        # Resolve variables referenced by config values.
        #
        # Supports:
        #
        # $DEVICE_CODENAME
        # ${DEVICE_CODENAME}
        #
        # and nested references.
        #
        return self._resolve_variables(env)
    def debug_dump(self):
        print()
        print("========== PROJECT ==========")
        print(f"Device        : {self.device_name}")
        print(f"ROM           : {self.rom_name}")
        print(f"Branch        : {self.rom_branch}")
        print(f"Android       : {self.android_version}")
        print(f"ROM Path      : {self.rom_path}")
        print(f"Variant       : {self.build_variant}")
        print(f"Jobs          : {self.build_jobs}")
        print(f"Ccache        : {self.use_ccache}")
        print()
        print("Device Vars")
        for k, v in self.device_vars.items():
            print(f"  {k}={v}")
        print()
        print("ROM Vars")
        for k, v in self.rom_vars.items():
            print(f"  {k}={v}")
        print("=============================")
        print()
