/// <reference path="../util/Json.ts" />
/// <reference path="./ISerializable.ts" />
var econda;
(function (econda) {
    var serialization;
    (function (serialization) {
        /**
         * Serialize to Json
         * @class econda.serialization.JsonSerializer
         * @experimental
         */
        var JsonSerializer = (function () {
            function JsonSerializer() {
            }
            /**
             * Serialize data to json string
             * @param {Object} data
             * @returns {String}
             * @static
             */
            JsonSerializer.serialize = function (data) {
                var serializer = new JsonSerializer();
                return serializer.serialize(data);
            };
            JsonSerializer.deserialize = function (data, targetObj) {
                if (targetObj === void 0) { targetObj = null; }
                var serializer = new JsonSerializer();
                return serializer.deserialize(data, targetObj);
            };
            JsonSerializer.prototype.serialize = function (obj) {
                var data = this._serializeNestedObjects(obj);
                return econda.util.Json.stringify(data);
            };
            JsonSerializer.prototype._serializeNestedObjects = function (data) {
                var ret;
                if (econda.util.ArrayUtils.isArray(data)) {
                    ret = [];
                    for (var n = 0; n < data.length; n++) {
                        ret[n] = this._serializeNestedObjects(data[n]);
                    }
                    return ret;
                }
                if (typeof data === 'object' && data !== null) {
                    if (typeof data['getObjectData'] !== 'undefined') {
                        ret = data.getObjectData();
                        ret['$serialized-object$'] = true;
                        ret.data = this._serializeNestedObjects(ret.data || null);
                        return ret;
                    }
                    else if (data instanceof Date) {
                        ret = {
                            className: 'Date',
                            "$serialized-object$": true,
                            data: data.toISOString()
                        };
                        return ret;
                    }
                    else {
                        ret = {};
                        for (var propertyName in data) {
                            ret[propertyName] = this._serializeNestedObjects(data[propertyName]);
                        }
                        return ret;
                    }
                }
                return data;
            };
            JsonSerializer.prototype.deserialize = function (json, targetObj) {
                if (targetObj === void 0) { targetObj = null; }
                if (!json) {
                    return targetObj || null;
                }
                var info = econda.util.Json.parse(json);
                var ret;
                if (targetObj !== null) {
                    this._applyData(info.data, targetObj);
                    ret = targetObj;
                }
                else {
                    ret = this._resolveNestedSerializedObjects(info);
                }
                return ret;
            };
            JsonSerializer.prototype._applyData = function (data, targetObj) {
                if (typeof targetObj.setObjectData !== 'function') {
                    throw "setObjectData() not implemented. Cannot deserialize object";
                }
                data = this._resolveNestedSerializedObjects(data);
                targetObj.setObjectData(data);
            };
            JsonSerializer.prototype._resolveNestedSerializedObjects = function (data) {
                if (econda.util.ArrayUtils.isArray(data)) {
                    for (var n = 0; n < data.length; n++) {
                        data[n] = this._resolveNestedSerializedObjects(data[n]);
                    }
                }
                else if (typeof data === 'object' && data !== null) {
                    if (typeof data['$serialized-object$'] !== 'undefined') {
                        data = this._deserializeNestedObject(data);
                    }
                    else {
                        for (var propertyName in data) {
                            data[propertyName] = this._resolveNestedSerializedObjects(data[propertyName]);
                        }
                    }
                }
                return data;
            };
            JsonSerializer.prototype._deserializeNestedObject = function (info) {
                var obj;
                if (info.className === 'Date') {
                    obj = new Date(info.data);
                }
                else {
                    try {
                        obj = eval('new ' + info.className + '();');
                        if (typeof info.data !== 'undefined') {
                            this._applyData(info.data, obj);
                        }
                    }
                    catch (e) {
                        econda.debug.error('deserialization faild with exception:', e);
                    }
                }
                return obj;
            };
            return JsonSerializer;
        }());
        serialization.JsonSerializer = JsonSerializer;
    })(serialization = econda.serialization || (econda.serialization = {}));
})(econda || (econda = {}));