# Copyright (c) Microsoft.  All Rights Reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.

import attr
import copy
import json


def to_json(obj):
    """''Serializes an instance of a generated class to JSON.

    :param obj: an instance of any class generated by jschema-to-python.

    Before serializing the instance to JSON, this function maps the Python
    property names to the corresponding JSON schema property names. It also
    removes any property that has the default value specified by attr.ib,
    making the resulting JSON smaller.
    """

    return json.dumps(obj, indent=2, default=_generated_class_serializer)


def _generated_class_serializer(obj):
    if hasattr(obj, "__dict__"):
        dict = getattr(obj, "__dict__")
        dict = copy.deepcopy(dict)
        _remove_properties_with_default_values(obj, dict)
        _change_python_property_names_to_schema_property_names(obj, dict)
        return dict
    else:
        return str(obj)


def _remove_properties_with_default_values(obj, dict):
    for field in attr.fields(obj.__class__):
        dict_entry = dict.get(field.name)
        if value_is_default(dict_entry, field.default) and field.name in dict:
            del dict[field.name]


def value_is_default(dict_entry, default_value):
    if type(default_value) == attr._make.Factory:
        value = default_value.factory()
    else:
        value = default_value
    return dict_entry == value


def _change_python_property_names_to_schema_property_names(obj, dict):
    for field in attr.fields(obj.__class__):
        schema_property_name = field.metadata.get("schema_property_name")
        if schema_property_name and schema_property_name != field.name and field.name in dict:
            dict[schema_property_name] = dict[field.name]
            del dict[field.name]
