/// class PD.Web.Structure

/**
A list class that wraps a JavaScript array.
@class Structure
@namespace Web
@constructor
@param {Object}
**/
PD.Web.Structure = Class.extend({

    //===================================
    // FIELDS
    //===================================

    _innerObject: null,

    //===================================
    // CONSTRUCTOR
    //===================================

    init: function (dataObject) {
        this._innerObject = dataObject;
    },

    //===================================
    // PUBLIC METHODS
    //===================================

    update: function (obj) {

        var that = this,
            keys = this._keys(obj);

        keys.each(function (index, key) {
            if (that._innerObject.hasOwnProperty(key)) {
                that._innerObject[key] = obj[key];
            }
        });

    },

    value: function (path, value) {

        var keys = new PD.BCL.List(path.split("."));

        if (value === undefined) {
            return this._getValue(keys);
        }
        else {
            this._setValue(keys, value);
        }

    },

    remove: function (path) {
        this._removeProperty(path);
    },

    add: function (path, value) {

        var keys = new PD.BCL.List(path.split(".")),
            item = this._getObjectByPath(keys);

        if (keys.count() > 0 && item) {
            item[keys.last()] = (value !== undefined ? value : null);
        }

    },

    toObject: function () {
        return this._innerObject;
    },

    toPartial: function (exclude) {

        var that = this,
            result = {},
            excludeList = new PD.BCL.List(exclude);

        this._keys.each(function (index, key) {
            if (!excludeList.contains(key)) {
                result[key] = that._innerObject[key];
            }
        });

        return result;

    },

    //===================================
    // PRIVATE METHODS
    //===================================

    _setValue: function (keys, value) {

        var that = this,
            result = this._innerObject,
            count = keys.count();

        keys.each(function (index, key) {
            if (result.hasOwnProperty(key)) {
                if (count === index + 1) {
                    result[key] = value;
                }
                else {
                    result = result[key];
                }
            }
            else {
                result = undefined;
                return false;
            }
        });

    },

    _getValue: function (keys) {

        var that = this,
            result = this._innerObject;

        keys.each(function (index, key) {
            if (result.hasOwnProperty(key)) {
                result = result[key];
            }
            else {
                result = undefined;
                return false;
            }
        });

        return result;

    },

    _removeProperty: function (keys) {

        var that = this,
            result = this._innerObject,
            count = keys.count();

        keys.each(function (index, key) {
            if (result.hasOwnProperty(key)) {
                if (count === index + 1) {
                    result[key] = value;
                }
                else {
                    delete result[key];
                }
            }
        });

    },

    _getObjectByPath: function (keys, value) {

        var that = this,
            result = this._innerObject,
            count = keys.count();

        keys.each(function (index, key) {
            if (result.hasOwnProperty(key)) {
                if (count < index + 1) {
                    result = result[key];
                }
            }
        });

        return result;

    },

    _keys: function (target) {

        var source = target || this._innerObject,
            result = new PD.BCL.List();

        for (var key in source) {
            result.add(key);
        }

        return result;

    }

});

PD.Web.Structure.mixin = function (dataObject, wrapperObject) {

    wrapperObject["_data"] = new PD.Web.Structure(dataObject);

    wrapperObject["data"] = $.proxy(function (name, value) {

        var result = this._data;

        if (name !== undefined) {
            result = (value !== undefined) ? this._data.value(name, value) : this._data.value(name);
        }

        return result;

    }, wrapperObject);

};