Source: core/serialization/serializer/montage-ast.js

var Montage = require("../../core").Montage;

var Root = exports.Root = Montage.specialize({

    constructor: {
        value:  function Root() {
            this.object = Object.create(null);
        }
    },

    object: {value: null},

    setProperty: {
        value: function(name, value) {
            if (name !== null && name !== undefined) {
                this.object[name] = value;
            }
        }
    },

    getProperty: {
        value: function(name) {
            return this.object[name];
        }
    },

    clearProperty: {
        value: function(name) {
            delete this.object[name];
        }
    },

    hasProperty: {
        value: function(name) {
            return name in this.object;
        }
    },

    serialize: {
        value: function(indent) {
            return JSON.stringify(this, null, indent);
        }
    },

    toJSON: {
        value: function() {
            var result = Object.create(null),
                object;

            for (var label in this.object) {
                if (Object.hasOwnProperty.call(this.object, label)) {

                    object = this.object[label];

                    if (object.toJSON) {
                        result[label] = object.toJSON(label, 1);
                    } else {
                        result[label] = object;
                    }   
                }
            }

            return result;
        }
    }
});


var Value = exports.Value = Montage.specialize({
    root: {value: null},
    label: {value: null},
    value: {value: null},

    constructor: {
        value: function Value(root, value) {
            this.root = root;
            this.value = value;
        }
    },

    setLabel: {
        value: function(label) {
            if (this.label) {
                this.root.clearProperty(this.label);
            }

            this.label = label;
            this.root.setProperty(label, this);
        }
    },

    getLabel: {
        value: function() {
            return this.label;
        }
    },

    clearLabel: {
        value: function() {
            this.root.clearProperty(this.label);
            this.label = null;
        }
    },

    _getSerializationValue: {
        value: function() {
            return this.value;
        }
    },

    toJSON: {
        value: function(index, level) {
            var value = this._getSerializationValue();

            if (level === 1) {
                return {value: value};
            } else {
                return value;
            }
        }
    }
});

/**
 * @class ElementReference
 * @extends Value
 */
var ElementReference = exports.ElementReference = Value.specialize(/** @lends ElementReference# */ {

    initWithRootAndId: {
        value: function (root, id) {
            Value.call(this, root, id);
            return this;
        }
    },

    _getSerializationValue: {
        value: function () {
            return {"#": this.value};
        }
    }
});

/**
 * @class ModuleReference
 * @extends Value
 */
var ModuleReference = exports.ModuleReference = Value.specialize( /** @lends ModuleReference# */ {

    initWithRootAndModuleId: {
        value: function (root, moduleId) {
            Value.call(this, root, moduleId);
            return this;
        }
    },

    _getSerializationValue: {
        value: function () {
            return {"%": this.value};
        }
    }
});


var ObjectReference = exports.ObjectReference = Value.specialize( /** @lends ObjectReference# */ {

    constructor: {
        value: function ObjectReference(root, referenceLabel) {
            Value.call(this, root, referenceLabel);
        }
    },

    _getSerializationValue: {
        value: function() {
            return {"@": this.value};
        }
    }
});


var CustomObject = exports.CustomObject = Value.specialize( /** @lends CustomObject# */ {

    constructor: {
        value: function CustomObject(root) {
            Value.call(this, root, Object.create(null));
        }
    },

    setProperty: {
        value: function(name, value) {
            if (name !== null && name !== undefined) {
                this.value[name] = value;
            }
        }
    },

    getProperty: {
        value: function(name) {
            return this.value[name];
        }
    },

    clearProperty: {
        value: function(name) {
            delete this.value[name];
        }
    },

    toJSON: {
        value: function(index, level) {
            var reference,
                value = this._getSerializationValue();

            if (level === 1) {
                return value;
            } else {
                reference = new ObjectReference(this.root, this.label);

                return reference.toJSON();
            }
        }
    }
});

var ReferenceableValue = exports.ReferenceableValue = Value.specialize( /** @lends ObjectLiteral# */ {

    constructor: {
        value: function ReferenceableValue(root, value) {
            Value.call(this, root, value);
        }
    },

    toJSON: {
        value: function(index, level) {
            var reference,
                value = this._getSerializationValue();

            if (level === 1) {
                return {value: value};
            } else if (this.label) {
                reference = new ObjectReference(this.root, this.label);
                return reference.toJSON();
            } else {
                return value;
            }
        }
    }
});

var ObjectLiteral = exports.ObjectLiteral = ReferenceableValue.specialize( /** @lends ObjectLiteral# */ {

    constructor: {
        value: function ObjectLiteral(root, object) {
            Value.call(this, root, object);
        }
    },

    setProperty: {
        value: function(name, value) {
            if (name !== null && name !== undefined) {
                this.value[name] = value;
            }
        }
    },

    getProperty: {
        value: function(name) {
            return this.value[name];
        }
    },

    clearProperty: {
        value: function(name) {
            delete this.value[name];
        }
    },

    getPropertyNames: {
        value: function() {
            return Object.keys(this.value);
        }
    }
});

var RegExpObject = exports.RegExpObject = ReferenceableValue.specialize( /** @lends RegExpObject# */ {

    constructor: {
        value: function RegExpObject(root, regexp) {
            Value.call(this, root, regexp);
        }
    },

    _getSerializationValue: {
        value: function() {
            var regexp = this.value;

            return {"/": {
                source: regexp.source,
                flags: (regexp.global ? "g" : "") + (regexp.ignoreCase ? "i" : "") + (regexp.multiline ? "m" : "")
            }};
        }
    }
});