import datetime
import decimal
import json as jsonlib

from .._compat import PY2, integer_types

long = integer_types[-1]


class Serializers(object):
    _custom_ = {}

    def _json_parse(self, o):
        if hasattr(o, "custom_json") and callable(o.custom_json):
            return o.custom_json()
        if isinstance(o, (datetime.date, datetime.datetime, datetime.time)):
            return o.isoformat()[:19].replace("T", " ")
        elif isinstance(o, long):
            return int(o)
        elif isinstance(o, decimal.Decimal):
            return str(o)
        elif isinstance(o, set):
            return list(o)
        elif hasattr(o, "as_list") and callable(o.as_list):
            return o.as_list()
        elif hasattr(o, "as_dict") and callable(o.as_dict):
            return o.as_dict()
        if self._custom_.get("json") is not None:
            return self._custom_["json"](o)
        raise TypeError(repr(o) + " is not JSON serializable")

    def __getattr__(self, name):
        if self._custom_.get(name) is not None:
            return self._custom_[name]
        raise NotImplementedError("No " + str(name) + " serializer available.")

    def json(self, value):
        value = jsonlib.dumps(value, default=self._json_parse)
        rep28 = r"\u2028"
        rep29 = r"\2029"
        if PY2:
            rep28 = rep28.decode("raw_unicode_escape")
            rep29 = rep29.decode("raw_unicode_escape")
        return value.replace(rep28, "\\u2028").replace(rep29, "\\u2029")

    def yaml(self, value):
        if self._custom_.get("yaml") is not None:
            return self._custom_.get("yaml")(value)
        try:
            from yaml import dump
        except ImportError:
            raise NotImplementedError("No yaml serializer available.")
        return dump(value)


serializers = Serializers()
