/// class ProspectDirector.Modules.Views.ViewFilterConfiguration
/// using ProspectDirector.Types.Core.Dialog
/// using ProspectDirector.Types.Core.ContextMenu

ProspectDirector.Modules.Views.ViewFilterConfiguration = (function (options) {

    var 

    PRIVATE = {

        //---------------------------
        //--- CONSTRUCTOR
        //---------------------------

        init: function () {

            options = $.extend({
                selector: null,
                viewStateId: null,
                data: null,
                type: null
            }, options);

            PRIVATE.init_container();
            PRIVATE.init_menu();
            PRIVATE.init_tree();

        },

        //---------------------------
        //--- PROPERTIES
        //---------------------------

        get_container: function () {
            return $(options.selector);
        },

        get_menu: function () {
            return PRIVATE.get_container().find("[data-role=menu]");
        },

        get_tree: function () {
            return PRIVATE.get_container().find("[data-role=treeview]");
        },

        //---------------------------
        //--- INITIALIZERS
        //---------------------------

        init_container: function () {

            PRIVATE.get_container().data("contextMenu", new ProspectDirector.Modules.Views.ViewFilterConfiguration.ContextMenu({
                parent: PRIVATE
            }));

        },

        init_menu: function () {

            PRIVATE.get_menu().kendoMenu({
                select: $.proxy(PRIVATE.menu_onSelect, PRIVATE)
            });

        },

        init_tree: function () {

            var tree = PRIVATE.get_tree().kendoTreeView({
                dragAndDrop: true,
                template: null,
                drag: $.proxy(PRIVATE.tree_onDrag, PRIVATE),
                drop: $.proxy(PRIVATE.tree_onDrop, PRIVATE),
                dataBound: $.proxy(PRIVATE.tree_onDataBound, PRIVATE)
            }).data("kendoTreeView");

            PRIVATE.get_tree().on("dblclick", "li[data-uid] span.k-in", $.proxy(PRIVATE.tree_onDblClick, PRIVATE));
            PRIVATE.get_tree().on("click", "INPUT[type=checkbox]", $.proxy(PRIVATE.checkbox_onClick, PRIVATE));

            PRIVATE.get_tree().parent().css({
                border: "1px solid #AAAAAA",
                paddingTop: "5px",
                paddingLeft: "0px",
                height: "300px",
                overflow: "auto",
                fontSize: "12px",
                fontFamily: "Arial",
                backgroundColor: "#FFFFFF"
            });

            if (options.data === undefined || options.data === null) {
                PRIVATE.addNoFiltersMessage();
            }
            else {
                PRIVATE.populate(options.data);
            }

        },

        //---------------------------
        //--- EVENT HANDLERS
        //---------------------------

        menu_onSelect: function (e) {

            var command = $(e.item).data("command"),
                tree = PRIVATE.get_tree().data("kendoTreeView");

            switch (command) {
                case "add":
                    PRIVATE.showFinderDialog(tree.select());
                    break;
                case "remove":
                    PRIVATE.remove(tree.select());
                    break;
                case "clear":
                    PRIVATE.remove(PRIVATE.get_tree().children("LI").first());
                    break;
            };

        },

        tree_onDrop: function (e) {

            var tree = PRIVATE.get_tree().data("kendoTreeView");

            if (e.dropPosition !== "over") {
                e.setValid(false);
            }
            else if (!PRIVATE.isConditionOrFilter(e.destinationNode)) {
                e.setValid(false);
            }
            else if (PRIVATE.isCondition(e.sourceNode) && PRIVATE.isFilter(e.destinationNode)) {
                e.setValid(false);
            }
            else {

                if ($(e.sourceNode).data().role === "condition") {
                    PRIVATE.dropCondition(e);
                }
                else {
                    PRIVATE.dropFilter(e);
                }

            }

        },

        tree_onDrag: function (e) {

            if (!$(e.dropTarget).closest(".k-in").hasClass("k-state-hover")) {
                e.setStatusClass("k-denied");
            }
            else if (!PRIVATE.isConditionOrFilter(e.dropTarget)) {
                e.setStatusClass("k-denied");
            }
            else if (PRIVATE.isCondition(e.sourceNode) && PRIVATE.isFilter(e.dropTarget)) {
                e.setStatusClass("k-denied");
            }

        },

        tree_onDblClick: function (e) {

            var info = PRIVATE.get_tree().data("kendoTreeView").dataItem(e.target).info;

            e.preventDefault();
            e.stopPropagation();

            if (e.target.tagName !== "INPUT" && info !== undefined && info !== null) {

                switch (info.role) {
                    case "condition":
                        PRIVATE.toggleCondition(e.target);
                        break;
                    case "filter":
                        PRIVATE.editFilter(e.target);
                        break;
                }

            }

        },

        tree_onDataBound: function (e) {

            var data = null,
                index = 0;

            if (e.node === undefined || e.node.length === 0) {
                data = e.sender.dataSource._data;
            }
            else {
                data = PRIVATE.get_tree().data("kendoTreeView").dataItem(e.node).children._data;
            }

            if (data !== undefined) {

                for (index = 0; index < data.length; index++) {
                    PRIVATE.nodeTemplate(data[index]);
                }

            }

        },

        checkbox_onClick: function (e) {

            var checked = $(e.target).is(":checked"),
                tree = PRIVATE.get_tree().data("kendoTreeView"),
                node = $(e.target).closest("LI.k-item"),
                data = tree.dataItem(node);

            if (data.info !== undefined) {
                data.info.enabled = checked;
            }

            e.stopPropagation();

            node.find("INPUT[type=checkbox]").each(function (index, element) {

                data = tree.dataItem($(element).closest("LI.k-item"))

                if (data.info !== undefined) {
                    $(element).attr("checked", checked);
                    data.info.enabled = checked;
                }

            });

            if (checked) {

                node.parents("LI.k-item").each(function (index, element) {

                    data = tree.dataItem($(element));
                    data.info.enabled = checked;
                    $(element).find("INPUT[type=checkbox]:first").attr("checked", checked);

                });

            }

        },

        finderDialog_onOk: function (parentNode, e) {

            var tree = PRIVATE.get_tree().data("kendoTreeView");

            PRIVATE.removeMessageNodes();

            /* if parent node is not specified attempt to find root condition node */
            if (parentNode.length === 0) {

                parentNode = PRIVATE.get_tree().find("li").first()

                if (!PRIVATE.isCondition(parentNode)) {
                    parentNode = $(null);
                }

            };

            /* if no root condition node is found, then add one */
            if (parentNode.length === 0) {
                parentNode = PRIVATE.addCondition(null, { type: "AND", enabled: true });
            };

            if ($(parentNode).data().role === "filter") {
                parentNode = parentNode.parents("li[data-uid]").first();
            };

            /* add a filter node for filter selected */
            for (var i = 0; i < e.length; i++) {
                PRIVATE.addFilter(parentNode, e[i]);
            };

        },

        //---------------------------
        //--- METHODS
        //---------------------------

        addNoFiltersMessage: function () {

            PRIVATE.get_tree().data("kendoTreeView").append({
                text: "No filters have been added to the view."
            });

        },

        showFinderDialog: function (parentNode) {

            var dialog = null;

            switch (options.type) {
                case "bounds":
                    dialog = ProspectDirector.Modules.Views.ViewFilterConfiguration.BoundsFilterFinder;
                    break;
                case "design":
                    dialog = ProspectDirector.Modules.Views.ViewFilterConfiguration.DesignFilterFinder;
                    break;
            }

            dialog.show({
                params: {
                    viewStateId: options.viewStateId
                },
                callbacks: {
                    ok: $.proxy(function (sender, e) {
                        PRIVATE.finderDialog_onOk(parentNode === undefined ? $(null) : parentNode, e);
                    }, PRIVATE)
                }
            });

        },

        populate: function (condition, parent) {

            var tree = PRIVATE.get_tree().data("kendoTreeView"),
                node = null,
                index = 0;

            if (condition !== null) {
                node = PRIVATE.addCondition(parent, { type: condition.type, enabled: condition.enabled });
            }

            for (index = 0; index < condition.filters.length; index++) {
                PRIVATE.addFilter(node, condition.filters[index]);
            }

            for (index = 0; index < condition.conditions.length; index++) {
                PRIVATE.populate(condition.conditions[index], node);
            }

            //clear selections
            tree.select($());

        },

        remove: function (node) {

            var next = null,
                tree = PRIVATE.get_tree().data("kendoTreeView");

            if (node.length === 0) {
                return;
            };

            next = node.prev();

            if (next.length === 0) {
                next = node.next();
            };

            if (next.length === 0) {
                next = node.parent().closest("li.k-item");
            };

            tree.remove(node);
            tree.select(next);

            if (PRIVATE.get_tree().find("li.k-item").length === 0) {

                PRIVATE.addNoFiltersMessage();

            }

        },

        removeMessageNodes: function () {
            PRIVATE.get_tree().data("kendoTreeView").remove(PRIVATE.get_tree().find("li[data-message=true]"));
        },

        editFilter: function (node) {

            var data = PRIVATE.get_tree().data("kendoTreeView").dataItem(node),
                info = data.info;

            if (info.value === null) {
                delete info.value;
            };

            var params = {
                viewStateId: options.viewStateId,
                id: info.id,
                enabled: info.enabled,
                operator: info.operator,
                value: info.value,
                verse: info.verse
            };

            ProspectDirector.Types.Core.Dialogs.FilterEditor.show({
                params: params,
                callbacks: {
                    ok: function (sender, e) {
                        info.id = e.id;
                        info.enabled = e.enabled;
                        info.operator = e.operator;
                        info.value = e.value;
                        info.verse = e.verse;
                        PRIVATE.nodeTemplate(data);
                    }
                }
            });

        },

        addCondition: function (parentNode, data) {

            var guid = ProspectDirector.RUNTIME.guid(),
                tree = PRIVATE.get_tree().data("kendoTreeView"),
                result = null;

            if (parentNode === undefined || parentNode === null || parentNode.length === 0) {
                parentNode = undefined;
            }

            tree.append({
                info: {
                    ref: guid,
                    role: "condition",
                    enabled: data.enabled,
                    type: data.type
                }
            }, parentNode);

            result = PRIVATE.get_tree().find("[data-ref=" + guid + "]");

            tree.select(result);

            return result;

        },

        addFilter: function (parentNode, data) {

            var guid = ProspectDirector.RUNTIME.guid(),
                tree = PRIVATE.get_tree().data("kendoTreeView"),
                condition = null,
                result = null,
                info = {
                    info: {
                        ref: guid,
                        id: data.id,
                        name: data.name,
                        enabled: data.enabled,
                        operator: data.operator,
                        value: data.value,
                        verse: data.verse,
                        role: "filter"
                    }
                };

            switch (true) {

                case PRIVATE.isFilter(parentNode):
                    tree.insertAfter(info, parentNode);
                    break;

                case PRIVATE.isCondition(parentNode):

                    condition = parentNode.find("[data-role=condition]").first();

                    if (condition.length > 0) {
                        tree.insertBefore(info, condition);
                    }
                    else {
                        tree.append(info, parentNode);
                    }

                    break;
            }

            result = PRIVATE.get_tree().find("[data-ref=" + guid + "]");

            tree.select(result);

            return result;

        },

        dropCondition: function (e) {

            var tree = PRIVATE.get_tree().data("kendoTreeView"),
                filter = $(e.destinationNode).find("UL:first > [data-role=filter]").last(),
                parent = ProspectDirector.Types.KendoExtensions.TreeView.parent(tree, $(e.sourceNode));

            if ($(e.destinationNode).is($(e.sourceNode)) || $(e.destinationNode).is(parent)) {
                e.setValid(false);
                return false;
            };

            if (filter.length === 0) {
                tree.append($(e.sourceNode), $(e.destinationNode));
            }
            else {
                e.preventDefault();
                tree.insertAfter($(e.sourceNode), filter);
            };

        },

        dropFilter: function (e) {

            var tree = PRIVATE.get_tree().data("kendoTreeView"),
                condition = $(e.destinationNode).find("UL:first > [data-role=condition]").first(),
                parent = ProspectDirector.Types.KendoExtensions.TreeView.parent(tree, $(e.sourceNode));

            if (PRIVATE.isFilter($(e.destinationNode)) || $(e.destinationNode).is(parent)) {
                e.setValid(false);
                return false;
            };

            if (condition.length === 0) {
                tree.append($(e.sourceNode), $(e.destinationNode));
            }
            else {
                e.preventDefault();
                tree.insertBefore($(e.sourceNode), condition);
            };

        },

        isConditionOrFilter: function (element) {

            element = $(element).closest(".k-item");

            return PRIVATE.isCondition(element) || PRIVATE.isFilter(element);

        },

        isCondition: function (element) {

            var role = $(element).data("role");

            return role !== undefined && role === "condition";

        },

        isFilter: function (element) {

            var role = $(element).data("role");

            return role !== undefined && role === "filter";

        },

        toggleCondition: function (node) {

            var tree = PRIVATE.get_tree().data("kendoTreeView"),
                data = tree.dataItem(node);

            if (data.info.type === "AND") {
                data.info.type = "OR";
            }
            else {
                data.info.type = "AND";
            }

            PRIVATE.nodeTemplate(data);

        },

        nodeTemplate: function (data) {

            var $span = $("<span></span>"),
                $node = PRIVATE.get_tree().data("kendoTreeView").findByUid(data.uid),
                $inner = $node.find(".k-in").first(),
                info = data.info;

            if (info !== undefined) {

                if (info.ref !== undefined) {
                    $node.attr("data-ref", info.ref);
                }

                $node.attr("data-role", info.role);

                switch (info.role) {

                    case "condition":

                        $span.html("<input type=\"checkbox\" style=\"position:relative;top:2px;\" " + (info.enabled ? "checked" : "") + " />&nbsp;<b>" + info.type + "</b>");

                        break;

                    case "filter":

                        $span.html("<input type=\"checkbox\" style=\"position:relative;top:2px;\" " + (info.enabled ? "checked" : "") + " />" + ProspectDirector.Types.View.FilterOperator.getFilterHtml(info));

                        break;

                }

            }
            else {

                $node.attr("data-message", "true");
                $inner.css({
                    backgroundColor: "#FFFFFF",
                    borderColor: "#FFFFFF"
                });
                $span.css({
                    color: "#AAAAAA",
                    fontStyle: "italic"
                });
                $span.html(data.text);

            }

            $inner.empty();
            $inner.html($span[0].outerHTML);

        },

        duplicateFilter: function (element) {

            var data = PRIVATE.get_tree().data("kendoTreeView").dataItem($(element));

            PRIVATE.addFilter(element.parent().closest("li.k-item"), data.info);

        },

        getData: function () {

            var data = PRIVATE.scan(PRIVATE.get_tree(), {}).conditions;
            return data

        },

        scan: function (condition, object) {

            var tree = PRIVATE.get_tree().data("kendoTreeView"),
                info = null;

            object = $.extend({
                conditions: [],
                filters: []
            }, object)

            if (condition.length > 0) {

                condition.children("li[data-role=condition]").each(function (index, element) {

                    info = tree.dataItem($(element)).info;

                    object.conditions[object.conditions.length] = {
                        type: info.type,
                        enabled: info.enabled,
                        conditions: [],
                        filters: []
                    };

                    PRIVATE.scan($(element).children("ul"), object.conditions[index]);

                });

                condition.children("li[data-role=filter]").each(function (index, element) {

                    info = tree.dataItem($(element)).info;

                    object.filters[object.filters.length] = PRIVATE.extractFilterInfo(info);

                });

            }

            return object;

        },

        extractFilterInfo: function (dataItem) {

            return {
                id: dataItem.id,
                name: dataItem.name,
                enabled: dataItem.enabled,
                operator: dataItem.operator,
                value: dataItem.value,
                verse: dataItem.verse,
                role: dataItem.role
            }

        }

    },

    PUBLIC = {
        getData: PRIVATE.getData
    };

    PRIVATE.init();

    return PUBLIC;

});

//---------------------------
//--- STATIC METHODS
//---------------------------

ProspectDirector.Modules.Views.ViewFilterConfiguration.BoundsFilterFinder = 

new (ProspectDirector.Types.Core.Dialog.extend({
    
    init: function () {
        this._super("FindFilterInBounds",
                "Find Filter",
                ProspectDirector.RUNTIME.resolveUrl("~/viewfilter/findinbounds"));
    }

}));

ProspectDirector.Modules.Views.ViewFilterConfiguration.DesignFilterFinder =

new (ProspectDirector.Types.Core.Dialog.extend({

    init: function () {
        this._super("FindFilterInDesign",
                        "Find Filter",
                        ProspectDirector.RUNTIME.resolveUrl("~/viewfilter/findindesign"));
    }

}));

//---------------------------
//--- INNER CLASSES
//---------------------------

ProspectDirector.Modules.Views.ViewFilterConfiguration.ContextMenu = ProspectDirector.Types.Core.ContextMenu.extend({

    //---------------------------
    //--- CONSTRUCTOR
    //---------------------------

    init: function (options) {
        this._super(options);
    },

    //---------------------------
    //--- PROPERTIES
    //---------------------------

    get_parent: function () {
        return this.options.parent;
    },

    get_contextMenuSelector: function () {
        return this.get_parent().get_tree().selector + " .k-item[data-uid][data-role]";
    },

    //---------------------------
    //--- PROTECTED METHODS
    //---------------------------

    _executeCommand: function (command, e) {

        switch (command) {
            case "addAndCondition":
                this.get_parent().addCondition(e.$trigger, { type: "AND", enabled: true });
                break;
            case "addOrCondition":
                this.get_parent().addCondition(e.$trigger, { type: "OR", enabled: true });
                break;
            case "addFilter":
                this.get_parent().showFinderDialog(e.$trigger);
                break;
            case "editFilter":
                this.get_parent().editFilter(e.$trigger);
                break;
            case "duplicateFilter":
                this.get_parent().duplicateFilter(e.$trigger);
                break;
            case "toggleCondition":
                this.get_parent().toggleCondition(e.$trigger);
                break;
            case "remove":
                this.get_parent().remove(e.$trigger);
                break;
        }

    },

    _configureContextMenu: function (sender, e) {

        var info = this.get_parent().get_tree().data("kendoTreeView").dataItem(sender).info,
            items = e.config.items;

        items.remove = {
            name: "Remove"
        };

        items.sep1 = "sep1";

        /* configure condition specific menu items */
        if (info.role === "condition") {

            items.addAndCondition = {
                name: "Add AND"
            };

            items.addOrCondition = {
                name: "Add OR"
            };

            items.toggleCondition = {
                name: "Convert to " + (info.type === "AND" ? "OR" : "AND")
            };

            items.sep2 = "sep2";

            items.addFilter = {
                name: "Add Filter..."
            };

        };

        /* configure filter specific menu items */
        if (info.role === "filter") {

            items.editFilter = {
                name: "Edit..."
            };

            items.duplicateFilter = {
                name: "Duplicate"
            };
        };

    }

});