ProspectDirector.Web.UI.Queries.Constraints = Class.extend({

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

    _condition: null,

    //================================
    // CONSTRCUTOR
    //================================

    init: function (options) {
        this._options = options || { data: null };
        this._fill();
    },

    //================================
    // CONSTRCUTOR
    //================================

    get_root: function () {
        return this._condition;
    },

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

    hasRoot: function () {
        return this._condition !== null;
    },

    addRoot: function (condition) {
        if (!this._condition) {
            this._condition = condition ? condition : new ProspectDirector.Web.UI.Queries.Condition();
        }
    },

    clear: function () {
        this._condition = null;
    },

    findById: function (id) {

        var result = null;

        if (this.get_root()) {

            if (this.get_root().get_id() === id) {
                return this.get_root();
            }

            if (!result) {
                result = this.get_root().findById(id);
            }

        }

        return result;

    },

    toJSON: function () {
        return this.hasRoot() ? this.get_root().toJSON() : null;
    },

    getCounts: function () {

        var result = {
            filters: 0,
            conditions: 0
        };

        if (this.get_root()) {
            result = this.get_root().getCounts();
            result.conditions += 1;
        }

        return result;

    },

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

    addCondition: function (condition, parentId) {

        var parent = null;

        if (!this.hasRoot()) {
            this.addRoot(condition);
            parent = this.get_root();
        }
        else {
            parent = this._getParentConstraint(parentId);
            parent.get_conditions().add(condition);
        }

    },

    addFilter: function (filter, parentId) {

        var parent = null;

        if (!this.hasRoot()) {
            this.addRoot();
            parent = this.get_root();
        }
        else {
            parent = this._getParentConstraint(parentId);
        }

        parent.get_filters().add(filter);

    },

    remove: function (id) {

        var constraint = this.findById(id),
            parent = null;

        if (constraint) {

            parent = constraint.get_parent();

            if (parent === null) {
                this.clear();
            }
            else {

                if (constraint.get_role() === "condition") {
                    parent.get_conditions().remove(constraint);
                }
                else {
                    parent.get_filters().remove(constraint);
                }

            }

        }

    },

    move: function (srcId, dstId) {

        var srcConstraint = this.findById(srcId),
            dstConstraint = this.findById(dstId);

        if (srcConstraint == null || dstConstraint == null) {
            return;
        }

        if (dstConstraint.get_role() === "condition") {
            dstConstraint.add(srcConstraint);
        }

    },

    package: function (condition) {

        var that = this,
            list = null;

        if (!condition) {
            if (this.hasRoot()) {
                condition = JSON.parse(JSON.stringify(this.toJSON()));
            }
            else {
                condition = new ProspectDirector.Web.UI.Queries.Condition();
            }
        }

        list = new ProspectDirector.Web.List(condition.conditions);

        condition["items"] = [];
        condition["expanded"] = true;

        list.each(function (index, item) {
            that.package(item);
        });

        condition.items = condition.items.concat(condition.filters);
        condition.items = condition.items.concat(condition.conditions);

        delete condition.conditions;
        delete condition.filters;

        return condition;

    },

    getFilterCondition: function (filter) {

        var result = null,
            last = null;

        filter = this.findById(filter);

        if (!filter.get_parent()) {
            return null;
        }

        last = filter.get_parent().get_filters().last();

        if (!last) {
            return null;
        }

        if (last.get_id() !== filter.get_id()) {
            result = filter.get_parent();
        }
        else {
            result = this.getWrappingCondition(filter.get_parent())
        }

        return result;

    },

    getWrappingCondition: function (group) {

        var result = null;

        if (!group.get_parent()) {
            return group;
        }

        last = group.get_parent().get_conditions().last();

        if (!last) {
            return this.get_root();
        }

        if (last.get_id() !== group.get_id()) {
            result = group.get_parent();
        }
        else {
            result = this.getWrappingCondition(group.get_parent());
        }

        return result;

    },

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

    _fill: function () {
        if (this._options.data) {
            this._condition = new ProspectDirector.Web.UI.Queries.Condition({
                data: this._options.data
            });
        }
    },

    _getParentConstraint: function (parentId) {

        var result = null;

        if (parentId) {
            result = this.findById(parentId);
        }

        if (result && result.get_role() !== "condition") {
            result = result.get_parent();
        }

        if (!result) {
            result = this.get_root();
        }

        return result;

    }

});