import copy
import json
from functools import update_wrapper

MINIMUM_COMPATIBILITY_MODE = '8.10'


def ensure_string_list(list_to_convert):
    return [str(potential_integer) for potential_integer in list_to_convert]


def version_str_as_tuple(version_str):
    return tuple([int(v) for v in version_str.split('.')])


def _noop_decorator(*args, **kwargs):

    def wrap(function):

        def do_nothing(*args, **kwargs):
            return function(*args, **kwargs)

        return update_wrapper(do_nothing, function)

    return wrap


class ModelEncoder(json.JSONEncoder):
    """ModelEncoder Class"""

    def default(self, obj):
        if isinstance(obj, BaseModel):
            return obj.as_dict()
        else:
            return json.JSONEncoder.default(self, obj)


class BaseModel(object):
    _fields = []

    def as_dict(self):
        """
        :return: The instance as a dict
        """
        data = {}
        for field in self._fields:
            method = 'serialize_{0}'.format(field)
            if hasattr(self, method):
                value = getattr(self, method)()
            else:
                value = getattr(self, field)

            data[field] = value

        return data

    def as_json(self, **kwargs):
        """
        :return: The instance as a Json string
        """
        return json.dumps(self.as_dict(), **kwargs)

    @staticmethod
    def as_list(models):
        return [model.as_dict() for model in models or []]

    @classmethod
    def from_dict(cls, data):
        local_data = {}
        for field in cls._fields:
            if field in data:
                field_data = copy.deepcopy(data[field])
                method = 'deserialize_{0}'.format(field)
                if hasattr(cls, method):
                    local_data[field] = getattr(cls, method)(field_data)
                else:
                    local_data[field] = field_data
        return cls(**local_data)

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

    @classmethod
    def from_list(cls, arr):
        return [cls.from_dict(elem) for elem in arr]

    def __repr__(self):
        return "{}({})".format(
            self.__class__.__name__,
            ", ".join(["{}={}".format(field, getattr(self, field)) for field in self._fields]))
