from json import loads


class BaseModel(object):

    @classmethod
    def from_json(cls, json):
        return cls.from_dict(loads(json))

    @classmethod
    def from_dict(cls, dict_):
        instance = cls()
        for key in dict_:
            setattr(instance, key, dict_[key])
        return instance

    @classmethod
    def from_list(cls, list_):
        model_list = None
        if list_ is not None:
            model_list = []
            for item in list_:
                model_list.append(cls.from_dict(item))
        return model_list

    @classmethod
    def from_json_list(cls, json_list):
        return cls.from_list(loads(json_list))

    @staticmethod
    def _model_list(class_):
        """
        :param class_: The class that elements should be an instance of.
        :return: A decorator that ensures the assigning value is a list of `class_` instances.
        """
        assert issubclass(class_, BaseModel)

        def decorator(f):
            def wrapper(self, list_):
                if isinstance(list_, list):
                    model_list = []
                    for item in list_:
                        if isinstance(item, class_):
                            model_list.append(item)
                        elif isinstance(item, dict):
                            model_list.append(class_.from_dict(item))
                        else:
                            raise HawkIOException(u'Invalid element type.')
                    f(self, model_list)
                else:
                    f(self, [])
            return wrapper
        return decorator

    @staticmethod
    def _model(class_):
        """
        :param class_: The class that the value should be an instance of.
        :return: A decorator that ensures the assigning value is of `class_` instances.
        """
        assert issubclass(class_, BaseModel)

        def decorator(f):
            def wrapper(self, model):
                if isinstance(model, class_):
                    f(self, model)
                elif isinstance(model, dict):
                    f(self, class_.from_dict(model))
                elif model is None:
                    f(self, None)
                else:
                    raise HawkIOException(u'Invalid value type.')
            return wrapper
        return decorator

    # def as_payload(self, filter_=None):
        # return payload_filter(self.__dict__, filter_)


class Filter(BaseModel):

    def __init__(
            self,
            operators=None,
            control=None,
            name=None,
            readable_name=None
    ):
        self.operators = operators
        self.control = control
        self.name = name
        self.readable_name = readable_name


class Filters(BaseModel):

    def __init__(
            self,
            filters=None,
            sort=None,
            wildcard_fields=None
    ):
        self._filters = None
        self.filters = filters
        self.sort = sort
        self.wildcard_fields = wildcard_fields

    @property
    def filters(self):
        return self._filters

    @filters.setter
    @BaseModel._model_list(Filter)
    def filters(self, filters):
        self._filters = filters


class FilterSort(BaseModel):

    def __init__(
            self,
            name=None,
            order=None
    ):
        self.name = name
        self.order = order


class FilterPagination(BaseModel):

    def __init__(
            self,
            total=None,
            offset=None,
            limit=None,
            sort=None
    ):
        self._sort = None
        self.total = total
        self.offset = offset
        self.limit = limit
        self.sort = sort

    @property
    def sort(self):
        return self._sort

    @sort.setter
    @BaseModel._model_list(FilterSort)
    def sort(self, sorts):
        self._sort = sorts


# utility #wait/sleep #add to enrichment list.
