# -*- coding: utf-8 -*-
"""
Module with information about the supported geofiletypes.
"""

import ast
import csv
from dataclasses import dataclass
import enum
from pathlib import Path
from typing import List, Optional, Union

geofiletypes = {}

@dataclass
class GeofileTypeInfo:
    """
    Class with properties of a GeofileType.
    """
    geofiletype: str
    ogrdriver: str
    suffixes: Optional[List[str]]
    is_spatialite_based: bool
    suffixes_extrafiles: Optional[List[str]]

def init_geofiletypes():
    geofiletypes_path = Path(__file__).resolve().parent / 'geofiletypes.csv'
    with open(geofiletypes_path, 'r') as file:
        # Set skipinitialspace to True so the csv can be formatted for readability
        csv.register_dialect('geofiletype_dialect', skipinitialspace=True, strict=True)
        reader = csv.DictReader(file, dialect='geofiletype_dialect')

        for row in reader:
            # Prepare optional values that need eval first  
            suffixes = None
            if row['suffixes'] is not None and row['suffixes'] != '':
                suffixes = ast.literal_eval(row['suffixes'])
            suffixes_extrafiles = None
            if row['suffixes_extrafiles'] is not None and row['suffixes_extrafiles'] != '':
                suffixes_extrafiles = ast.literal_eval(row['suffixes_extrafiles'])
            
            # Add geofiletype
            geofiletypes[row['geofiletype']] = GeofileTypeInfo(
                    geofiletype=row['geofiletype'],
                    ogrdriver=row['ogrdriver'],
                    suffixes=suffixes,
                    is_spatialite_based=ast.literal_eval(row['is_spatialite_based']),
                    suffixes_extrafiles=suffixes_extrafiles)

class GeofileType(enum.Enum):
    ESRIShapefile = enum.auto()
    GeoJSON = enum.auto()
    GPKG = enum.auto()
    SQLite = enum.auto()

    @classmethod
    def _missing_(cls, value: Union[str, int, Path]):
        """
        Expand options in the Driver() constructor.
        
        Args:
            value (Union[str, int, Driver]): 
                * string: lookup using case insensitive name
                * GeofileType: create the same GeometryType as the one passed in

        Returns:
            [GeofileType]: The corresponding GeometryType.
        """
        def get_geofiletype_for_suffix(suffix: str):
            suffix_lower = suffix.lower()
            for geofiletype in geofiletypes:
                suffixes = geofiletypes[geofiletype].suffixes
                if suffixes is not None and suffix_lower in suffixes:
                    return GeofileType[geofiletype]
            raise Exception(f"Not implemented for extension {suffix}")
        
        def get_geofiletype_for_ogrdriver(ogrdriver: str):
            for geofiletype in geofiletypes:
                driver = geofiletypes[geofiletype].ogrdriver
                if driver is not None and driver == ogrdriver:
                    return GeofileType[geofiletype]
            raise Exception(f"Not implemented for ogr driver {ogrdriver}")

        if value is None:
            return None
        elif isinstance(value, Path):
            # If it is a Path, return Driver based on the suffix
            return get_geofiletype_for_suffix(value.suffix)
        elif isinstance(value, str):
            if value.startswith('.'):
                # If it start with a point, it is a suffix
                return get_geofiletype_for_suffix(value)
            else:
                # it's probably an ogr driver
                return get_geofiletype_for_ogrdriver(value)
        elif isinstance(value, GeofileType):
            # If a GeofileType is passed in, return same GeofileType.
            # TODO: why create a new one?
            return cls(value.value)
        # Default behaviour (= lookup based on int value)
        return super()._missing_(value)

    @property
    def is_spatialite_based(self):
        return geofiletypes[self.name].is_spatialite_based

    @property
    def ogrdriver(self):
        return geofiletypes[self.name].ogrdriver

    @property
    def suffixes_extrafiles(self):
        return geofiletypes[self.name].suffixes_extrafiles

# Init!
init_geofiletypes()

if __name__ == '__main__':
    None
