/*
 * JBoss, Home of Professional Open Source
 * Copyright ${year}, Red Hat, Inc. and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 * 
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 * 
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */


(function ($, rf) {

    rf.ui = rf.ui || {};

    var __DEFAULT_OPTIONS = {
        expanded : false,
        stylePrefix : "rf-pm-gr",
        expandEvent: "click",
        collapseEvent: "click",

        // TODO we should use selectionType = {none, selectable, unselectable}
        selectable : false,
        unselectable : false // unselectable can be only selectable item => if selectable == false than unselectable = false
    };

    var EXPAND_ITEM = {

        /**
         *
         * @return {void}
         * */
        exec : function (group, expand) {
            var mode = group.mode;
            if (mode == "server") {
                return this.execServer(group);
            } else if (mode == "ajax") {
                return this.execAjax(group);
            } else if (mode == "client" || mode == "none") {
                return this.execClient(group, expand);
            } else {
                rf.log.error("EXPAND_ITEM.exec : unknown mode (" + mode + ")");
            }
        },

        /**
         * @protected
         *
         * @return {Boolean} false
         * */
        execServer : function (group) {
            group.__changeState();
            rf.submitForm(this.__getParentForm(group), group.options["ajax"]["parameters"] || {});

            return false;
        },

        /**
         * @protected
         *
         * @return {Boolean} false
         * */
        execAjax : function (group) {
            var oldState = group.__changeState();
            rf.ajax(group.id, null, $.extend({}, group.options["ajax"], {}));
            group.__restoreState(oldState);

            return true;
        },

        /**
         * @protected
         *
         * @param {PanelMenuGroup} group
         * @param {Boolean} expand
         * @return {undefined}
         *             - false - if process has been terminated
         *             - true  - in other cases
         * */
        execClient : function (group, expand) {
            if (expand) {
                group.__expand();
            } else {
                group.__collapse();
            }

            return group.__fireEvent("switch");
        },

        /**
         * @private
         * */
        __getParentForm : function (item) {
            return $($(rf.getDomElement(item.id)).parents("form")[0]);
        }
    };

    rf.ui.PanelMenuGroup = rf.ui.PanelMenuItem.extendClass({
            // class name
            name:"PanelMenuGroup",

            /**
             * @class PanelMenuGroup
             * @name PanelMenuGroup
             *
             * @constructor
             * @param {String} componentId - component id
             * @param {Hash} options - params
             * */
            init : function (componentId, options) {
                $super.constructor.call(this, componentId, $.extend({}, __DEFAULT_OPTIONS, options || {}));

                this.options.bubbleSelection = this.__rfPanelMenu().options.bubbleSelection;
                this.options.expandSingle = this.__rfPanelMenu().options.expandSingle;

                if (!this.options.disabled) {
                    var menuGroup = this;

                    if (!this.options.selectable) {

                        //TODO nick - this can be replaced by jQuery.delegate on menu itself
                        if (this.options.expandEvent == this.options.collapseEvent) {
                            this.__header().bind(this.options.expandEvent, function () {
                                menuGroup.switchExpantion();
                            });

                        } else {
                            this.__header().bind(this.options.expandEvent, function () {
                                if (menuGroup.collapsed()) {
                                    return menuGroup.expand();
                                }
                            });

                            this.__header().bind(this.options.collapseEvent, function () {
                                if (menuGroup.expanded()) {
                                    return menuGroup.collapse();
                                }
                            });
                        }
                    } else {

                        if (this.options.expandEvent == this.options.collapseEvent) {
                            if (this.options.expandEvent != 'click') {
                                this.__header().bind(this.options.expandEvent, function () {
                                    menuGroup.switchExpantion();
                                });
                            }

                        } else {
                            if (this.options.expandEvent != 'click') {
                                this.__header().bind(this.options.expandEvent, function () {
                                    if (menuGroup.collapsed()) {
                                        return menuGroup.expand();
                                    }
                                });
                            }

                            if (this.options.collapseEvent != 'click') {
                                this.__header().bind(this.options.collapseEvent, function () {
                                    if (menuGroup.expanded()) {
                                        return menuGroup.collapse();
                                    }
                                });
                            }
                        }

                    }

                    if (this.options.selectable || this.options.bubbleSelection) {
                        this.__content().bind("select", function (event) {
                            if (menuGroup.options.selectable && menuGroup.__isMyEvent(event)) {
                                menuGroup.expand();
                            }

                            if (menuGroup.options.bubbleSelection && !menuGroup.__isMyEvent(event)) {
                                menuGroup.__select();
                                if (!menuGroup.expanded()) {
                                    menuGroup.expand();
                                }
                            }
                        });

                        this.__content().bind("unselect", function (event) {
                            if (menuGroup.options.selectable && menuGroup.__isMyEvent(event)) {
                                menuGroup.collapse();
                            }

                            if (menuGroup.options.bubbleSelection && !menuGroup.__isMyEvent(event)) {
                                menuGroup.__unselect();
                            }
                        });
                    }

                    /*this.__addUserEventHandler("beforecollapse");
                     this.__addUserEventHandler("collapse");
                     this.__addUserEventHandler("beforeexpand");
                     this.__addUserEventHandler("expand");
                     this.__addUserEventHandler("beforeswitch");
                     this.__addUserEventHandler("switch");*/
                }
            },

            /***************************** Public Methods  ****************************************************************/
            expanded : function () {
                // TODO check invariant in dev mode
                // return this.__content().hasClass("rf-pm-exp")
                return this.__getExpandValue();
            },

            expand : function () {
                if (this.expanded()) return;
                if (!this.__fireEvent("beforeexpand")) {
                    return false;
                }

                EXPAND_ITEM.exec(this, true);
            },

            __expand : function () {
                this.__updateStyles(true);
                this.__collapseForExpandSingle();

                return this.__fireEvent("expand");
            },

            collapsed : function () {
                // TODO check invariant in dev mode
                // return this.__content().hasClass("rf-pm-colps")
                return !this.__getExpandValue();
            },

            collapse : function () {
                if (!this.expanded()) return;
                if (!this.__fireEvent("beforecollapse")) {
                    return false;
                }

                EXPAND_ITEM.exec(this, false);
            },

            __collapse : function () {
                this.__updateStyles(false);

                this.__childGroups().each(function(index, group) {
                    //TODO nick - why not group.collapse()?
                    rf.component(group.id).__collapse();
                });

                return this.__fireEvent("collapse");
            },

            __updateStyles : function (expand) {
                if (expand) {
                    //expand
                    this.__content().removeClass("rf-pm-colps").addClass("rf-pm-exp");
                    this.__header().removeClass("rf-pm-hdr-colps").addClass("rf-pm-hdr-exp");

                    this.__setExpandValue(true);
                } else {
                    this.__content().addClass("rf-pm-colps").removeClass("rf-pm-exp");
                    this.__header().addClass("rf-pm-hdr-colps").removeClass("rf-pm-hdr-exp");

                    this.__setExpandValue(false);
                }
            },

            /**
             * @methodOf
             * @name PanelMenuGroup#switch
             *
             * TODO ...
             *
             * @param {boolean} expand
             * @return {void} TODO ...
             */
            switchExpantion : function () { // TODO rename
                var continueProcess = this.__fireEvent("beforeswitch");
                if (!continueProcess) {
                    return false;
                }

                if (this.expanded()) {
                    this.collapse();
                } else {
                    this.expand();
                }
            },

            /**
             * please, remove this method when client side ajax events will be added
             *
             * */
            onCompleteHandler : function () {
                if (this.options.selectable) {
                    $super.onCompleteHandler.call(this);
                }

                EXPAND_ITEM.execClient(this, this.expanded());
            },

            __switch : function (expand) {
                if (expand) {
                    this.__expand();
                } else {
                    this.__collapse();
                }
                return this.__fireEvent("switch");
            },

            /***************************** Private Methods ****************************************************************/
            __childGroups : function () {
                return this.__content().children(".rf-pm-gr")
            },

            __group : function () {
                return $(rf.getDomElement(this.id))
            },

            __header : function () {
                return $(rf.getDomElement(this.id + ":hdr"))
            },

            __content : function () {
                return $(rf.getDomElement(this.id + ":cnt"))
            },

            __expandValueInput : function () {
                return document.getElementById(this.id + ":expanded");
            },

            __getExpandValue : function () {
                return this.__expandValueInput().value == "true";
            },

            __collapseForExpandSingle: function() {
                if (this.options.expandSingle) {
                    this.__rfPanelMenu().__collapseGroups(this);
                }
            },

            /**
             * @methodOf
             * @name PanelMenuGroup#__setExpandValue
             *
             * @param {boolean} value - is group expanded?
             * @return {boolean} preview value
             */
            __setExpandValue : function (value) {
                var input = this.__expandValueInput();
                var oldValue = input.value;

                input.value = value;

                return oldValue;
            },

            __changeState : function () {
                if (!this.__getExpandValue()) {
                    this.__collapseForExpandSingle();
                }

                var state = {};
                state["expanded"] = this.__setExpandValue(!this.__getExpandValue());
                if (this.options.selectable) {
                    state["itemName"] = this.__rfPanelMenu().selectedItem(this.itemName); // TODO bad function name for function which change component state
                }

                return state;
            },

            __restoreState : function (state) {
                if (!state) {
                    return;
                }

                if (state["expanded"]) {
                    this.__setExpandValue(state["expanded"]);
                }

                if (state["itemName"]) {
                    this.__rfPanelMenu().selectedItem(state["itemName"]);
                }
            },

            __isMyEvent: function (event) {
                return this.id == event.target.id;
            },

            destroy: function () {
                rf.Event.unbindById(this.id, "." + this.namespace);

                $super.destroy.call(this);
            }
        });

    // define super class link
    var $super = rf.ui.PanelMenuGroup.$super;
})(RichFaces.jQuery, RichFaces);
