/*
Copyright (c) 2007, Caridy Patiņo. All rights reserved.
Portions Copyright (c) 2007, Yahoo!, Inc. All rights reserved.
Code licensed under the BSD License:
http://www.bubbling-library.com/eng/licence
version: 1.4.0
*/
(function() {

    var $B = YAHOO.Bubbling,
		$L = YAHOO.lang,
        $E = YAHOO.util.Event,
	    $D = YAHOO.util.Dom;

    /**
    * @singleton Selector - The Selector Manager will monitoring the areas using the className value and will highlighting the "yui-cms-item" areas on mouseover.
    * Apply visual enhanced to an area
    * @constructor
    */
    YAHOO.widget.AccordionManager = function() {
        var obj = {},
		    _selector = 'selected',
		    _sliding = 'sliding',
		    _anims = {};

        // on click action behaviors...
        $B.addDefaultAction('accordionToggleItem', function(layer, args) {
            if (!args[1].decrepitate) {
                // switching the slidable area and reclaiming the behavior
                return obj.toggle(args[1].target);
            }
        });
        $B.addDefaultAction('accordionRemoveItem', function(layer, args) {
            if (!args[1].decrepitate) {
                // removing an item from the accordion and reclaiming the behavior
                return obj.remove(args[1].target);
            }
        });

        // on event arrive
        // behaviors for the second accordion (ADVANCED AJAX APPLICATION)
        // Tagline: One behavior that will rule them all (based on the slide's rel attribute)
        $B.on('accordionOpenItem', function(layer, args) {
            var reLink = /.*#/;
            // if can be loaded thru AJAX
            if ($D.hasClass(args[1].slide, 'ajax') && $L.isObject(YAHOO.plugin.Dispatcher)) {
                var trigger = $D.getElementsByClassName('accordionToggleItem', '*', args[1].el);
                trigger = (trigger.length > 0 ? trigger[0] : null);
                if (trigger && (trigger = trigger.getAttribute('href', 2))) {
                    YAHOO.plugin.Dispatcher.fetch(args[1].slide, trigger.replace(reLink, ''), {
                        onLoad: function(el) {
                            $D.removeClass(args[1].slide, 'ajax');
                        }
                    });
                }
            }
        });

        // on keyboad action behavior...
        $B.on('key', function(layer, args) {
            var o = args[1], item = null, result = false;
            if (!o.decrepitate && (o.type == 'keyup')) {
                if (((o.keyCode === 39) && obj.open(o.target)) ||
    	          ((o.keyCode === 37) && obj.close(o.target))) { // Shortcut: cursor -> or cursor <-
                    // reclaiming the event & stoping the event propagation
                    o.decrepitate = true;
                    o.stop = true;
                }
            }
        });

        // on rollover action behavior...
        $B.on('rollover', function(layer, args) {
            var list, item, onWayOut;
            if (item = _getItem(args[1].target)) {
                if ((list = _getList(item)) && list.rollover) {
                    if (!list.selected) {
                        $D.addClass(list.el, _selector);
                        onWayOut = function(e) {
                            var l = _getList({ el: $E.getTarget(e) });
                            if (l && !$B.virtualTarget(e, l.el) && !l.persistent) {
                                _reset(l, { force: true });
                            }
                        };
                        if (!list.persistent) {
                            $E.removeListener(list.el, 'mouseout', onWayOut);
                            $E.addListener(list.el, 'mouseout', onWayOut, obj, true);
                        }
                    }
                    if (!item.selected) {
                        // is over a new item...
                        _openItem(item, list);
                    }
                }
            }
        });

        // creating the most common message (behavior layer)
        $B.addLayer(['accordionOpenItem', 'accordionCloseItem', 'accordionRemoveItem'], obj);

        function _getEffect(el) {
            var effect = el.getAttribute('rel') || null;
            if (effect) {
                effect = YAHOO.util.Easing[effect] || null;
            }
            return effect;
        }
        function _getTimer(el) {
            var t = ($D.hasClass(el, 'fast') ? 0.1 : null) || ($D.hasClass(el, 'slow') ? 0.6 : null) || 0.4;
            return t;
        }
        function _getItem(elem) {
            if (elem && ($L.isObject(elem) || (elem = $D.get(elem)))) {
                var item, el = $B.getOwnerByClassName(elem, 'yui-cms-item');
                if ($L.isObject(el)) {
                    item = {
                        el: el,
                        triger: elem,
                        selected: $D.hasClass(el, _selector),
                        sliding: $D.hasClass(el, _sliding),
                        size: { width: 0, Height: 0 }
                    };
                    // getting the slidable element
                    var slide = $D.getElementsByClassName('bd', '*', el);
                    slide = (slide.length > 0 ? slide[0] : null);
                    item.slide = slide;
                    var h = parseInt($D.getStyle(slide, 'height'), 10);
                    var w = parseInt($D.getStyle(slide, 'width'), 10);
                    // forcing to number... to avoid misbehavior on "auto" height/width...
                    if (!$L.isNumber(h)) {
                        $D.setStyle(slide, 'height', slide.scrollHeight + 'px');
                    }
                    if (!$L.isNumber(w)) {
                        $D.setStyle(slide, 'width', slide.scrollWidth + 'px');
                    }
                    item.size.height = slide.scrollHeight;
                    item.size.width = slide.scrollWidth;
                }
                return item;
            }
        }
        function _getList(item) {
            var list = null, el = item.el;
            if (el && ($L.isObject(el) || (el = $D.get(el)))) {
                if (el = $B.getOwnerByClassName(el, 'yui-cms-accordion')) {
                    // creating the list literal based on the classnames defined for the accordion wrapper
                    list = {
                        el: el,
                        effect: _getEffect(el),
                        orientation: ($D.hasClass(el, 'vertical') ? 'width' : 'height'),
                        selected: $D.hasClass(el, _selector),
                        fade: $D.hasClass(el, 'fade'),
                        manually: $D.hasClass(el, 'manually'),
                        fixIE: ($E.isIE && $D.hasClass(el, 'fixIE')), // hack for IE and quirk mode...
                        multiple: $D.hasClass(el, 'multiple'),
                        rollover: $D.hasClass(el, 'rollover'),
                        persistent: $D.hasClass(el, 'persistent'),
                        dispatcher: $D.hasClass(el, 'dispatcher'),
                        wizard: $D.hasClass(el, 'wizard'),
                        timer: _getTimer(el),
                        items: []
                    };
                    // searching for items childs...
                    $D.batch($D.getElementsByClassName('bd', '*', el), function(elem) {
                        // adding an item to the list
                        list.items.push(_getItem(elem));
                    });
                }
                return list;
            }
        }
        function _reset(list, params) {
            params = params || {};
            var conf = [], i,
                force = params.force || false,
                item = params.item || null;
            if (list) {
                if (!list.multiple || force) {
                    // closing all the selected items
                    for (i = 0; i < list.items.length; i++) {
                        // is the element is not equal to item, or if the item is under an animation...
                        if ((!item || (list.items[i].el !== item.el)) && (list.items[i].selected || list.items[i].sliding || params.expand)) {
                            if (params.expand) {
                                _openItem(list.items[i], list, params.grouping);
                            } else {
                                _closeItem(list.items[i], list, params.grouping);
                                if (params.mirror) {
                                    // hack for get the mirror element in persistent and !mutiples accordions
                                    params.mirror.push(list.items[i]);
                                }
                            }
                        }
                    }
                }
            }
        }
        function _openItem(item, list) {
            var conf = [], anim, i, g = [], m = [], fs, onFinish;
            if (list || (list = _getList(item))) {
                // if the item is not already opened
                // ANTONIO: cambiamos a pelo la imagen
                for (var c = 0; c <= item.el.all.length; c++) {
                    if (item.el.all[c].children.length > 0) {
                        if (item.el.all[c].children[0].id == 'idimg') {
                            item.el.all[c].children[0].src = item.el.all[c].children[0].src.replace('expand.gif', 'collapse.gif');
                            c = item.el.all.length + 1;
                        }
                    }
                }

                if (!item.selected) {
                    // closing all the selected items if neccesary
                    if (!list.multiple) {
                        _reset(list, { item: item, grouping: g, mirror: m });
                    }
                    // if the animation is underway: we need to stop it...
                    anim = _anims[$E.generateId(item.slide)];
                    if ((anim) && (anim.isAnimated())) { anim.stop(); }
                    // opening the selected element, based on the list's orientation, timer and effect attribute...
                    conf[list.orientation] = { to: item.size[list.orientation] };
                    // scrolling effect
                    if (!list.manually) {
                        conf['scroll'] = { from: (list.orientation == 'width' ? [item.size[list.orientation], 0] : [0, item.size[list.orientation]]), to: [0, 0] };
                    }
                    if (list.fade) { // appliying fadeIn
                        conf['opacity'] = { to: 1 };
                    }
                    anim = new YAHOO.util.Scroll(item.slide, conf, list.timer, list.effect);
                    $D.addClass(item.el, _sliding);
                    onFinish = function() {
                        $D.removeClass(item.el, _sliding);
                        $D.addClass(item.el, _selector);
                        // broadcasting the corresponding event...
                        $B.fire('accordionOpenItem', item);
                    };
                    anim.onComplete.subscribe(onFinish);
                    _anims[$E.generateId(item.slide)] = anim;
                    if (list.manually) {
                        // manually animation...
                        m = m[0] || null;
                        // getting the desired dimension from the mirror or from the current item
                        fs = (m ? m.size[list.orientation] : item.size[list.orientation]);
                        for (i = 1; i <= fs; i++) {
                            if (m) {
                                $D.setStyle(m.slide, list.orientation, (fs - i) + 'px');
                            }
                            $D.setStyle(item.slide, list.orientation, i + 'px');
                        }
                        onFinish();
                    } else {
                        // creating an animation thread
                        for (i = 0; i < g.length; i++) {
                            YAHOO.util.AnimMgr.registerElement(g[i]);
                        }
                        YAHOO.util.AnimMgr.registerElement(anim);
                    }
                }
                return true;
            }
            return false;
        }
        function _closeItem(item, list, grouping) {
            var conf = [], anim, fs;
            if (item && (list || (list = _getList(item)))) {
                // closing the item, based on the list's orientation, timer and effect attribute...
                // ANTONIO: cambiamos a pelo la imagen
                // ANTONIO: cambiamos a pelo la imagen
                for (var c = 0; c <= item.el.all.length; c++) {
                    if (item.el.all[c].children.length > 0) {
                        if (item.el.all[c].children[0].id == 'idimg') {
                            item.el.all[c].children[0].src = item.el.all[c].children[0].src.replace('collapse.gif', 'expand.gif');
                            c = item.el.all.length + 1;
                        }
                    }
                }
                conf[list.orientation] = { to: ((list.orientation == 'width' || list.fixIE) ? 1 : 0) }; // hack for vertical accordion issue on Safari and Opera
                if (list.fade) { // appliying fadeIn
                    conf['opacity'] = { to: 0 };
                }
                // scrolling effect
                if (!list.manually) {
                    conf['scroll'] = { to: (list.orientation == 'width' ? [item.size[list.orientation], 0] : [0, item.size[list.orientation]]) };
                }
                // if the animation is underway: we need to stop it...
                anim = _anims[$E.generateId(item.slide)];
                if ((anim) && (anim.isAnimated())) { anim.stop(); }
                anim = new YAHOO.util.Scroll(item.slide, conf, list.timer, list.effect);
                $D.addClass(item.el, _sliding);
                onFinish = function() {
                    $D.removeClass(item.el, _sliding);
                    $D.removeClass(item.el, _selector);
                    // broadcasting the corresponding event...
                    $B.fire('accordionOpenItem', item);
                };
                anim.onComplete.subscribe(onFinish);
                if ($L.isArray(grouping)) {
                    grouping.push(anim);
                } else {
                    anim.animate();
                }
                if (list.manually) {
                    // animation manually
                    fs = item.size[list.orientation];
                    for (i = fs; i >= conf[list.orientation].to; i--) {
                        $D.setStyle(item.slide, list.orientation, i + 'px');
                    }
                    onFinish();
                }
                _anims[$E.generateId(item.slide)] = anim;
                return true;
            }
            return false;
        }
        function _removeItem(item, list) {
            if (item && (list || (list = _getList(item)))) {
                // closing element
                _closeItem(item, list);
                // removing listeners...
                $E.purgeElement(item.el, true);
                // hack, removing the element after close it...
                window.setTimeout(function() {
                    item.el.parentNode.removeChild(item.el);
                    $B.fire('accordionRemoveItem', item);
                }, list.timer + 0.1);
                return true;
            }
            return false;
        }

        // public vars
        // public methods
        /**
        * * Expanding all the elements in the accordion...
        * @public
        * @param {object} el   DOM reference
        * @return boolean
        */
        obj.expand = function(el) {
            var list;
            if (list = _getList({ el: el })) {
                return _reset(list, { force: true, expand: true });
            }
        };
        /**
        * * Collapsing all the elements in the accordion...
        * @public
        * @param {object} el   DOM reference
        * @return boolean
        */
        obj.collapse = function(el) {
            var list;
            if (list = _getList({ el: el })) {
                return _reset(list, { force: true });
            }
        };
        /**
        * * Open a certain item inside an area...
        * @public
        * @param {object} el   DOM reference
        * @return boolean
        */
        obj.open = function(el) {
            var item;
            if (item = _getItem(el)) {
                return _openItem(item);
            }
        };
        /**
        * * Close a certain item inside an area...
        * @public
        * @param {object} el   DOM reference
        * @return boolean
        */
        obj.close = function(el) {
            var item, list;
            if (item = _getItem(el)) {
                if (list = _getList(item)) {
                    // if the item is already opened, and is multiple and not persistent
                    return ((item.selected && (list.multiple || !list.persistent)) ? _closeItem(item, list) : false);
                }
            }
        };
        /**
        * * toggle a certain item inside an area...
        * @public
        * @param {object} el   DOM reference
        * @return boolean
        */
        obj.toggle = function(el) {
            var item, list;
            if (item = _getItem(el)) {
                if (list = _getList(item)) {
                    // if the item is already opened, and is multiple and not persistent
                    return ((item.selected && (list.multiple || !list.persistent)) ? _closeItem(item, list) : _openItem(item, list));
                }
            }
        };
        /**
        * * remove a certain item from the area...
        * @public
        * @param {object} el   DOM reference
        * @return boolean
        */
        obj.remove = function(el) {
            var item, list;
            if (item = _getItem(el)) {
                if (list = _getList(item)) {
                    return _removeItem(item, list);
                }
            }
        };
        return obj;
    } ();
})();
YAHOO.register("accordion", YAHOO.widget.AccordionManager, {version: "1.4.0", build: "202"});
