from __future__ import unicode_literals, absolute_import, print_function

import json


class ServiceModelBase(object):

    def to_json(self):
        data = self.to_dict()
        return json.dumps(data)

    def to_dict(self):
        data = {}
        for k in self.__slots__:
            value = getattr(self, k)
            if isinstance(value, self.__class__.__bases__):
                data[k] = value.to_dict()
            else:
                data[k] = value
        return data

    @classmethod
    def validate_jsonstr(cls, jsonstr):
        obj = json.loads(jsonstr)
        return cls._check_dict(obj)

    @classmethod
    def validate_dict(cls, dt):
        return cls._check_dict(dt)

    @classmethod
    def _check_dict(cls, dt):
        nf = cls._necessary_fields()
        for attr in nf:
            if attr not in dt:
                return False

        return True

    @classmethod
    def _necessary_fields(cls):
        if hasattr(cls, '_auto_type_map_'):
            default_keys = [m[0] for m in cls._auto_type_map_]
            d_set = set(default_keys)
            s_set = set(cls.__slots__)
            assert d_set.issubset(s_set)
            diff_set = s_set.difference(d_set)
            return list(diff_set)
        else:
            return cls.__slots__

    @classmethod
    def from_dict(cls, d):
        if not cls.validate_dict(d):
            return None

        kw = {}
        if hasattr(cls, '_auto_type_map_'):
            for k, convert_func, default_value in cls._auto_type_map_:
                kw[k] = k in d and d[k] and convert_func(d[k]) or default_value

            for k in cls._necessary_fields():
                kw[k] = d[k]
        else:
            for k in cls.__slots__:
                kw[k] = d[k]

        return cls(**kw)
