"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const MobxModelDecorators_1 = require("../language/decorators/MobxModelDecorators");
const ModelInfo_1 = require("../language/decorators/ModelInfo");
const MODEL_ID = MobxModelDecorators_1.MODEL_PREFIX + "_SERIAL_ID";
const MODEL_TYPE = "$typename";
class ModelSerializer {
    constructor(constructors) {
        this.identification = 1;
        this.revivedTypeScriptObjects = new Map();
        this.unresolvedReferences = [];
        this.unresolvedRefIdentities = [];
        this.createdObjects = new Map();
        this.constructors = constructors;
    }
    toTypeScriptInstance(jsonObject) {
        const result = this.toTypeScriptInstanceInternal(jsonObject);
        this.resolveRefs();
        return result;
    }
    toTypeScriptInstanceInternal(jsonObject) {
        const type = jsonObject[MODEL_TYPE];
        const id = jsonObject[MODEL_ID];
        const dummy = this.constructors[type];
        console.log("TS type " + type + "  id " + id + "  nr pf constructors: " + JSON.stringify(this.constructors));
        if (dummy === undefined) {
            console.log(JSON.stringify(jsonObject));
        }
        const result = Object.create(dummy.prototype);
        this.revivedTypeScriptObjects.set(id, result);
        for (var key of Object.getOwnPropertyNames(jsonObject)) {
            if (key === MODEL_ID) {
                continue;
            }
            const value = jsonObject[key];
            if (value === undefined) {
                continue;
            }
            if (typeof value === "string") {
                result[key] = value;
            }
            else if (typeof value === "number") {
                result[key] = value;
            }
            else if (typeof value === "boolean") {
                result[key] = value;
            }
            else {
                if (Array.isArray(value)) {
                    if (result[key] === undefined) {
                        result[key] = [];
                    }
                    for (var item in value) {
                        result[key].push(this.toTypeScriptInstance(value[item]));
                    }
                }
                else {
                    if (ModelInfo_1.ModelInfo.references.contains(type, key)) {
                        const refId = jsonObject[key]["idref"];
                        const refObject = { reference: true, id: refId };
                        result[key] = refObject;
                        this.unresolvedReferences.push({ object: result, key: key });
                    }
                    else {
                        result[key] = this.toTypeScriptInstance(value);
                    }
                }
            }
        }
        return result;
    }
    resolveRefs() {
        this.unresolvedReferences.forEach(ref => {
            console.log("resolve typescript identity " + ref.key);
            ref.object[ref.key] = this.revivedTypeScriptObjects.get(ref.object[ref.key].id);
        });
    }
    toPrintableJSON(object) {
        this.createdObjects.clear();
        this.unresolvedRefIdentities = [];
        const result = this.convertToJSON(object, false);
        this.resolveObjectRefIdentities();
        return result;
    }
    toSerializableJSON(object) {
        this.createdObjects.clear();
        this.unresolvedRefIdentities = [];
        const result = this.convertToJSON(object, true);
        this.resolveObjectRefIdentities();
        return result;
    }
    resolveObjectRefIdentities() {
        this.unresolvedRefIdentities.forEach(ref => {
            const referenceObject = ref.object[ref.key];
            console.log("resolve JSON identity " + ref.key);
            referenceObject.idref = this.createdObjects.get(referenceObject.objectref);
            referenceObject.objectref = undefined;
        });
    }
    convertToJSON(tsObject, serialize) {
        var result = this.createJsonObjectFor(tsObject, serialize);
        Object.keys(tsObject).forEach(key => {
            console.log("    key " + key);
            if (key.startsWith(MobxModelDecorators_1.MODEL_PREFIX)) {
                const simpleKey = key.substring(MobxModelDecorators_1.MODEL_PREFIX_LENGTH);
                var value = tsObject[key.substring(MobxModelDecorators_1.MODEL_PREFIX_LENGTH)];
                if (ModelInfo_1.ModelInfo.listparts.contains(tsObject[MODEL_TYPE], simpleKey)) {
                    console.log("_PI_ prefix found for list");
                    const parts = tsObject[simpleKey];
                    result[simpleKey] = [];
                    for (var i = 0; i < parts.length; i++) {
                        result[simpleKey][i] = this.convertToJSON(parts[i], serialize);
                    }
                }
                else {
                    console.log("_PI_ prefix found for object: " + simpleKey);
                    console.log(" ==> " + ModelInfo_1.ModelInfo.parts.contains(tsObject[MODEL_TYPE], simpleKey));
                    result[simpleKey] = this.convertToJSON(value, serialize);
                }
            }
            else if (key === "container" || key === "propertyName" || key === "propertyIndex") {
                console.log("Skipping container/propertName/Index");
            }
            else {
                console.log("Nortal property: " + key);
                var value = tsObject[key];
                if (typeof value === "string") {
                    result[key] = value;
                }
                else if (typeof value === "number") {
                    result[key] = value;
                }
                else if (typeof value === "boolean") {
                    result[key] = value;
                }
                else if (value === undefined) {
                }
                else {
                    console.log("Assume reference is ");
                    result[key] = { reference: true, objectref: value };
                    this.unresolvedRefIdentities.push({ object: result, key: key });
                }
            }
        });
        return result;
    }
    createJsonObjectFor(tsObject, serialize) {
        console.log("createJsonObjectFor " + tsObject);
        const result = {};
        if (serialize) {
            result[MODEL_ID] = this.identification++;
            console.log("created object " + result[MODEL_ID]);
        }
        this.createdObjects.set(tsObject, result[MODEL_ID]);
        return result;
    }
}
exports.ModelSerializer = ModelSerializer;
//# sourceMappingURL=ModelSerializer.js.map