/***************************************************
* Fuzz.js
***************************************************/
// Set the Fuzz namespace
YAHOO.namespace('com.fuzz', 'com.fuzz.util', 'com.fuzz.widget');

/***************************************************
* Utilities.js
***************************************************/
YAHOO.com.fuzz.util.getUniqueId = function(el, name) {
    if (! YAHOO.com.fuzz.util._usedIds)
        YAHOO.com.fuzz.util._usedIds = new Array();
    
    if (! YAHOO.com.fuzz.util._usedIds[name])
        YAHOO.com.fuzz.util._usedIds[name] = new Array();
    
    YAHOO.com.fuzz.util._usedIds[name][YAHOO.com.fuzz.util._usedIds[name].length] = el;
    
    return name + "_" + YAHOO.com.fuzz.util._usedIds[name].length;
}

YAHOO.com.fuzz.util.removeAllChildren = function(el) {
    if(!el) return false;
    
    while (el.firstChild) 
    {
       el.removeChild(el.firstChild);
    };
}

YAHOO.com.fuzz.util.isEmpty = function(o) {
    var i, v;
    if (typeof o === 'object') {
        for (i in o) {
            v = o[i];
            if (v !== undefined && typeOf(v) !== 'function') {
                return false;
            }
        }
    }
    return true;
}

/***************************************************
* Container.js
***************************************************/
YAHOO.namespace('com.fuzz');

// Overwrite YUI's Module Init function 'cause it sucks
(function () {
    var Dom = YAHOO.util.Dom,
        Config = YAHOO.util.Config,
        Event = YAHOO.util.Event,
        CustomEvent = YAHOO.util.CustomEvent,
        Module = YAHOO.widget.Module,

        m_oModuleTemplate,
        m_oHeaderTemplate,
        m_oBodyTemplate,
        m_oFooterTemplate;


    function createModuleTemplate() {

        if (!m_oModuleTemplate) {

            m_oModuleTemplate = document.createElement("div");

            m_oModuleTemplate.innerHTML = ("<div class=\"" +
                Module.CSS_HEADER + "\"></div>" + "<div class=\"" +
                Module.CSS_BODY + "\"></div><div class=\"" +
                Module.CSS_FOOTER + "\"></div>");

            m_oHeaderTemplate = m_oModuleTemplate.firstChild;
            m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
            m_oFooterTemplate = m_oBodyTemplate.nextSibling;

        }

        return m_oModuleTemplate;
    }


    YAHOO.widget.Module.prototype.init = function (el, userConfig) {
        var elId, i, child;

        this.initEvents();
        this.beforeInitEvent.fire(Module);

        /**
        * The Module's Config object used for monitoring
        * configuration properties.
        * @property cfg
        * @type YAHOO.util.Config
        */
        this.cfg = new Config(this);

        if (this.isSecure) {
            this.imageRoot = Module.IMG_ROOT_SSL;
        }

        if (typeof el == "string") {
            elId = el;
            el = document.getElementById(el);

            if (! el) {
                el = (createModuleTemplate()).cloneNode(false);
                el.id = elId;
            }
        }

        this.element = el;

        if (el.id) {
            this.id = el.id;
        }

        /********* CHANGED CODE *********/
        // Get the header/body/footer anywhere in the element
        var header = Dom.getElementsByClassName(Module.CSS_HEADER, 'div', this.element);
        if(header.length) this.header = header[0];

        var body = Dom.getElementsByClassName(Module.CSS_BODY, 'div', this.element);
        if(body.length) this.body = body[0];

        var footer = Dom.getElementsByClassName(Module.CSS_FOOTER, 'div', this.element);
        if(footer.length) this.footer = footer[0];
        /********* END CHANGED CODE *********/

        this.initDefaultConfig();

        Dom.addClass(this.element, Module.CSS_MODULE);

        if (userConfig) {
            this.cfg.applyConfig(userConfig, true);
        }

        /*
            Subscribe to the fireQueue() method of Config so that any
            queued configuration changes are excecuted upon render of
            the Module
        */

        if (!Config.alreadySubscribed(this.renderEvent,
            this.cfg.fireQueue, this.cfg)) {

            this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);

        }

        this.initEvent.fire(Module);
    };
}());

// NOTICE OVERLAY
(function() {
    YAHOO.com.fuzz.Notice = function(el, userConfig){
        YAHOO.com.fuzz.Notice.superclass.constructor.call(this, el, userConfig);
    }

    var Lang = YAHOO.lang,
        Dom = YAHOO.util.Dom,
        Event = YAHOO.util.Event,
        CustomEvent = YAHOO.util.CustomEvent,
        Config = YAHOO.util.Config,
        Overlay = YAHOO.widget.Overlay,
        Notice = YAHOO.com.fuzz.Notice,

        m_oCloseIconTemplate,
        n_aNotices,

        EVENT_TYPES = {
            "ADD_NOTICE": "addNotice"
        }

        /**
        * Constant representing the Notice's configuration properties
        * @property DEFAULT_CONFIG
        * @private
        * @final
        * @type Object
        */
        DEFAULT_CONFIG = {
            "CLOSE": {
                key: "close",
                value: true,
                validator: Lang.isBoolean,
                supercedes: ["visible"]
            },

            "NOTICES": {
                key: "notices",
                validator: Lang.isArray
            }
        };

    Notice.CSS_NOTICE = "fuzz-notice";

    YAHOO.extend(Notice, Overlay, {
        init: function (el, userConfig) {

            /*
                 Note that we don't pass the user config in here yet because
                 we only want it executed once, at the lowest subclass level
            */

            Notice.superclass.init.call(this, el/*, userConfig*/);

            this.beforeInitEvent.fire(Notice);

            Dom.addClass(this.element, Notice.CSS_NOTICE);

            if (userConfig) {
                this.cfg.applyConfig(userConfig, true);
            }

            this._notices = new Array();

            this.setBody("");

            this.subscribe("render", this.doShowNext);
            this.subscribe("hide", this.doShowNext);
            this.subscribe("addNotice", this.onAddNotice);

            this.initEvent.fire(Notice);
        },

        /**
        * Initializes the custom events for Module which are fired
        * automatically at appropriate times by the Module class.
        */
        initEvents: function () {
            Notice.superclass.initEvents.call(this);

            var SIGNATURE = CustomEvent.LIST;

            /**
            * CustomEvent fired after a new notice is added
            * @event addNoticeEvent
            */
            this.addNoticeEvent = this.createEvent(EVENT_TYPES.ADD_NOTICE);
            this.addNoticeEvent.signature = SIGNATURE;
        },

        /**
        * Initializes the class's configurable properties which can be changed
        * using the Notice's Config object (cfg).
        * @method initDefaultConfig
        */
        initDefaultConfig: function () {
            Notice.superclass.initDefaultConfig.call(this);

            // Add notice config properties //

            /**
            * True if the Notice should display a "close" button
            * @config close
            * @type Boolean
            * @default true
            */
            this.cfg.addProperty(DEFAULT_CONFIG.CLOSE.key, {
                handler: this.configClose,
                value: DEFAULT_CONFIG.CLOSE.value,
                validator: DEFAULT_CONFIG.CLOSE.validator,
                supercedes: DEFAULT_CONFIG.CLOSE.supercedes
            });

            this.cfg.addProperty(DEFAULT_CONFIG.NOTICES.key, {
                handler: this.configNotices,
                value: DEFAULT_CONFIG.NOTICES.value,
                validator: DEFAULT_CONFIG.NOTICES.validator,
                supercedes: DEFAULT_CONFIG.NOTICES.supercedes
            });
        },

        // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //

        /**
        * The default event handler fired when the "close" property is changed.
        * The method controls the appending or hiding of the close icon at the
        * right of the Notice.
        * @method configClose
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers,
        * this will usually equal the owner.
        */
        configClose: function (type, args, obj) {
            var val = args[0],
                oClose = this.close;

            function doHide(e, obj) {
                obj.hide();
            }

            if (val) {
                if (!oClose) {
                    if (!m_oCloseIconTemplate) {
                        m_oCloseIconTemplate = document.createElement("span");
                        m_oCloseIconTemplate.innerHTML = "&#160;";
                        m_oCloseIconTemplate.className = "container-close";
                    }

                    oClose = m_oCloseIconTemplate.cloneNode(true);

                    this.footer.appendChild(oClose);

                    Event.on(oClose, "click", doHide, this);

                    this.close = oClose;

                } else {
                    oClose.style.display = "block";
                }
            } else {
                if (oClose) {
                    oClose.style.display = "none";
                }
            }
        },

        configNotices: function (type, args, obj) {
            var notices = args[0];

            for(var i = 0; i < notices.length; i++) {
                this._notices[this._notices.length] = {type: notices[i].type, notice: notices[i].notice};
            }
        },

        addNotice: function (type, notice) {
            this._notices[this._notices.length] = {type: type, notice: notice};
            this.addNoticeEvent.fire();
        },

        onAddNotice: function (e) {
            var currentVis = Dom.getStyle(this.element, "visibility");

            if(currentVis == "visible") return false;

            this.doShowNext();
        },

        doShowNext: function () {
            if(!this._notices.length) return false;

            var notice = this._notices.shift();
            //this.setBody (notice.type + ": " + notice.notice);
            this.setBody (notice.notice);
            this.show();
        }
    });
}());