"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const mobx_1 = require("mobx");
require("reflect-metadata");
const ModelInfo_1 = require("./ModelInfo");
exports.MODEL_PREFIX = "_PI_";
exports.MODEL_PREFIX_LENGTH = exports.MODEL_PREFIX.length;
exports.MODEL_CONTAINER = exports.MODEL_PREFIX + "Container";
exports.MODEL_NAME = exports.MODEL_PREFIX + "Name";
function observablereference(target, propertyKey) {
    ModelInfo_1.ModelInfo.references.add(target.constructor.name, propertyKey.toString());
}
exports.observablereference = observablereference;
function observablelistreference(target, propertyKey) {
    ModelInfo_1.ModelInfo.listReferences.add(target.constructor.name, propertyKey.toString());
}
exports.observablelistreference = observablelistreference;
function model1() {
    return (constructor) => {
        return constructor;
    };
}
exports.model1 = model1;
function model2(target) {
    ModelInfo_1.ModelInfo.addClass(target.name, target);
    return function (target) {
        var original = target;
        var f = function (...args) {
            console.log("ClassWrapper: before class constructor", original.name);
            let instance = original.apply(this, args);
            console.log("ClassWrapper: after class constructor", original.name);
            return instance;
        };
        f.prototype = original.prototype;
        return f;
    };
}
exports.model2 = model2;
function model(target) {
    ModelInfo_1.ModelInfo.addClass(target.name, target);
}
exports.model = model;
function observablepart(target, propertyKey) {
    ModelInfo_1.ModelInfo.parts.add(target.constructor.name, propertyKey.toString());
    const privatePropertyKey = exports.MODEL_PREFIX + propertyKey.toString();
    const getter = function () {
        const storedObserver = this[privatePropertyKey];
        if (!!storedObserver) {
            return storedObserver.get();
        }
        else {
            this[privatePropertyKey] = mobx_1.observable.box(null);
            return this[privatePropertyKey].get();
        }
    };
    const setter = function (val) {
        let storedObserver = this[privatePropertyKey];
        const storedValue = storedObserver ? storedObserver.get() : null;
        if (!!storedValue) {
            storedValue.container = null;
            storedValue.propertyName = "";
            storedValue.propertyIndex = undefined;
        }
        if (!!storedObserver) {
            storedObserver.set(val);
        }
        else {
            this[privatePropertyKey] = mobx_1.observable.box(val);
            storedObserver = this[privatePropertyKey];
        }
        if (val !== null && val !== undefined) {
            if (val.container !== undefined && val.container !== null) {
                if (val.propertyIndex !== undefined) {
                    val.container[val.propertyName].splice(val.propertyIndex, 1);
                }
                else {
                    val.container[exports.MODEL_PREFIX + val.propertyName] = null;
                }
            }
            val.container = this;
            val.propertyName = propertyKey.toString();
            val.propertyIndex = undefined;
        }
    };
    Reflect.deleteProperty(target, propertyKey);
    Reflect.defineProperty(target, propertyKey, {
        get: getter,
        set: setter,
        configurable: true
    });
}
exports.observablepart = observablepart;
function observablelistpart(target, propertyKey) {
    ModelInfo_1.ModelInfo.listparts.add(target.constructor.name, propertyKey.toString());
    const privatePropertyKey = exports.MODEL_PREFIX + propertyKey.toString();
    const getter = function () {
        let result = this[privatePropertyKey];
        if (result === undefined) {
            const array = mobx_1.observable.array([], { deep: false });
            result = array;
            this[privatePropertyKey] = result;
            array[exports.MODEL_CONTAINER] = this;
            array[exports.MODEL_NAME] = propertyKey.toString();
            array.intercept(change => willChange(change));
        }
        return result;
    };
    Reflect.deleteProperty(target, propertyKey);
    Reflect.defineProperty(target, propertyKey, {
        get: getter
    });
}
exports.observablelistpart = observablelistpart;
function willChange(change) {
    switch (change.type) {
        case "update":
            const newValue = change.newValue;
            const oldValue = change.object[change.index];
            if (newValue === oldValue) {
            }
            else {
                if (!!newValue) {
                    if (!!newValue.container) {
                        if (newValue.propertyIndex !== undefined) {
                            newValue.container[newValue.propertyName][newValue.propertyIndex] = null;
                        }
                        else {
                            newValue.container[newValue.propertyName] = null;
                        }
                    }
                    newValue.container = oldValue.container;
                    newValue.propertyName = oldValue.propertyName;
                    newValue.propertyIndex = oldValue.propertyIndex;
                }
                oldValue.container = null;
                oldValue.propertyName = "";
                oldValue.propertyIndex = undefined;
            }
            break;
        case "splice":
            let index = change.index;
            const removedCount = change.removedCount;
            const added = change.added;
            const addedCount = added.length;
            const xxx = change.object;
            for (const i in added) {
                const element = added[i];
                if (!!element) {
                    if (!!element.container) {
                        if (element.propertyIndex !== undefined) {
                            element.container[element.propertyName][element.propertyIndex] = null;
                        }
                        else {
                            element.container[element.propertyName] = null;
                        }
                    }
                    element.container = change.object[exports.MODEL_CONTAINER];
                    element.propertyName = change.object[exports.MODEL_NAME];
                    element.propertyIndex = index + Number(i);
                }
            }
            for (let num = 0; num < removedCount; num++) {
                let rr = index + num;
                if (!(typeof index === "number")) {
                    console.trace("=====================================");
                    console.log("MOBX ARRAY change Index type " + typeof index);
                    for (const pp in index) {
                        console.log("        key " + pp + " type " + typeof index[pp]);
                    }
                    index = index[0];
                }
                rr = num + index;
                change.object[rr].container = null;
                change.object[rr].propertyName = "";
                change.object[rr].propertyIndex = undefined;
            }
            for (let above = index; above < change.object.length; above++) {
                const aboveElement = change.object[above];
                if (aboveElement.propertyIndex !== undefined) {
                    aboveElement.propertyIndex += addedCount - removedCount;
                }
            }
            break;
    }
    return change;
}
//# sourceMappingURL=MobxModelDecorators.js.map