'''


    @author: olivier.massot, févr. 2018
'''
import csv
from datetime import datetime
import logging

import dateutil.parser

from core.sqlformatter import SqlFormatter


logger = logging.getLogger("model")

Sql = SqlFormatter()

csv.register_dialect('tsv', delimiter='\t', quotechar='', quoting=csv.QUOTE_NONE)

class Model():
    _mapping = {}

    def __setattr__(self, name, value):

        try:
            val, type_ = value
            if not type_ in (int, float, bool, str, datetime):
                raise TypeError("Type de donnée invalide pour une propriété de 'Model' ('{}')".format(type(val)))
            self.__class__._mapping[name] = type_
        except (TypeError, ValueError):
            val = value
            if val is None:
                super().__setattr__(name, val)
                return
            try:
                type_ = self.__class__._mapping[name]
            except KeyError:
                super().__setattr__(name, val)
                return

        val = Model._cast(val, type_)

        super().__setattr__(name, val)

    @staticmethod
    def _cast(value, type_):
        if value is None:
            return value
        if type_ == datetime:
            if type(value) is str:
                return dateutil.parser.parse(value)
            elif type(value) is datetime:
                return value
            else:
                raise ValueError("'{}' ne peut pas être converti en date".format(value))
        if type_ is bool and value in ("True", "False"):
            return (value == "True")
        else:
            return type_(value)

    @property
    def _fields(self):
        return list(self.__dict__.keys())

    @property
    def data(self):
        return self.__dict__

    def __repr__(self):
        return "<{} => {}>".format(self.__class__.__name__, ",".join(["{}={}".format(field, value) for field, value in self.__dict__.items()]))

    @classmethod
    def from_dict(cls, data):
        """ Retourne un objet à partir d'un dictionnaire de données """
        model = cls()
        for key, value in data.items():
            setattr(model, key, value)
        return model

    @classmethod
    def _parse(cls, field, value):
        if value == 'None':
            value = None
        try:
            return Model._cast(value, cls._mapping[field])
        except KeyError:
            return value

