from toolz.functoolz import compose
from yankee.util import inflect
from yankee import settings
from .accessor import python_accessor

class DefaultMeta:
    accessor_function = python_accessor
    infer_keys = True
    output_style = "python"

class Deserializer(object):
    Meta = DefaultMeta


    def __init__(self, data_key=None, many=False, required=False):
        self.data_key = data_key
        self.required = required
        self.many = many
        self.name = None
        self._build_meta()
        self.bind()

    def _build_meta(self):
        for c in self.__class__.mro():
            if not hasattr(c, "Meta"):
                continue
            for k in filter(lambda k: not k.startswith("_"), c.Meta.__dict__.keys()):
                if not hasattr(self.Meta, k):
                    setattr(self.Meta, k, getattr(c.Meta, k))
                
    def bind(self, name=None, parent=None, meta=None):
        self.name = name
        self.parent = parent
        # Update Meta object
        if meta:
            self.Meta = meta
        elif self.parent is not None:
            self.Meta = self.parent.Meta
        # Regenerate Accessor
        self.make_accessor()
        # Set Output Name
        if self.name is not None:
            self.output_name = inflect(self.name, style=self.Meta.output_style)
        if settings.use_model:
            self._load_func = compose(self.load_model, self.post_load, self.deserialize, self.pre_load)
        else:
            self._load_func = compose(self.post_load, self.deserialize, self.pre_load)
        return self

    def make_accessor(self):
        self.accessor = self.Meta.accessor_function(self.data_key, self.name, self.many, self.Meta)

    def load(self, obj):
        self.raw = obj
        return self._load_func(obj)

    def pre_load(self, obj):
        return obj

    def load_model(self, obj):
        return obj
    
    def deserialize(self, obj):
        return self.accessor(obj)

    def post_load(self, obj):
        return obj
