/*
Copyright (c) 2007, Caridy Patino. 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.5.0
*/
(function() {
    var $B = YAHOO.Bubbling,
$L = YAHOO.lang,
        $E = YAHOO.util.Event,
    $D = YAHOO.util.Dom;
/**
* @singleton Accordion Manager - Creating accordion controls based on the markup.
* 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
              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...
            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.5.0", build: "203"});