//mouseenter, mouseleave
//from http://dev.rubyonrails.org/attachment/ticket/8354/event_mouseenter_106rc1.patch
Object.extend(Event, (function() {
  var cache = Event.cache;

  function getEventID(element) {
    if (element._prototypeEventID) return element._prototypeEventID[0];
    arguments.callee.id = arguments.callee.id || 1;
    return element._prototypeEventID = [++arguments.callee.id];
  }

  function getDOMEventName(eventName) {
    if (eventName && eventName.include(':')) return "dataavailable";
    //begin extension
    if(!Prototype.Browser.IE){
      eventName = {
        mouseenter: 'mouseover',
        mouseleave: 'mouseout'
      }[eventName] || eventName;
    }
    //end extension
    return eventName;
  }

  function getCacheForID(id) {
    return cache[id] = cache[id] || { };
  }

  function getWrappersForEventName(id, eventName) {
    var c = getCacheForID(id);
    return c[eventName] = c[eventName] || [];
  }

  function createWrapper(element, eventName, handler) {
    var id = getEventID(element);
    var c = getWrappersForEventName(id, eventName);
    if (c.pluck("handler").include(handler)) return false;

    var wrapper = function(event) {
      if (!Event || !Event.extend ||
        (event.eventName && event.eventName != eventName))
          return false;

      Event.extend(event);
      handler.call(element, event);
    };

    //begin extension
    if(!(Prototype.Browser.IE) && ['mouseenter','mouseleave'].include(eventName)){
      wrapper = wrapper.wrap(function(proceed,event) {
        var rel = event.relatedTarget;
        var cur = event.currentTarget;
        if(rel && rel.nodeType == Node.TEXT_NODE)
          rel = rel.parentNode;
        if(rel && rel != cur && !rel.descendantOf(cur))
          return proceed(event);
      });
    }
    //end extension

    wrapper.handler = handler;
    c.push(wrapper);
    return wrapper;
  }

  function findWrapper(id, eventName, handler) {
    var c = getWrappersForEventName(id, eventName);
    return c.find(function(wrapper) { return wrapper.handler == handler });
  }

  function destroyWrapper(id, eventName, handler) {
    var c = getCacheForID(id);
    if (!c[eventName]) return false;
    c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
  }

  function destroyCache() {
    for (var id in cache)
      for (var eventName in cache[id])
        cache[id][eventName] = null;
  }

  if (window.attachEvent) {
    window.attachEvent("onunload", destroyCache);
  }

  return {
    observe: function(element, eventName, handler) {
      element = $(element);
      var name = getDOMEventName(eventName);

      var wrapper = createWrapper(element, eventName, handler);
      if (!wrapper) return element;

      if (element.addEventListener) {
        element.addEventListener(name, wrapper, false);
      } else {
        element.attachEvent("on" + name, wrapper);
      }

      return element;
    },

    stopObserving: function(element, eventName, handler) {
      element = $(element);
      var id = getEventID(element), name = getDOMEventName(eventName);

      if (!handler && eventName) {
        getWrappersForEventName(id, eventName).each(function(wrapper) {
          element.stopObserving(eventName, wrapper.handler);
        });
        return element;

      } else if (!eventName) {
        Object.keys(getCacheForID(id)).each(function(eventName) {
          element.stopObserving(eventName);
        });
        return element;
      }

      var wrapper = findWrapper(id, eventName, handler);
      if (!wrapper) return element;

      if (element.removeEventListener) {
        element.removeEventListener(name, wrapper, false);
      } else {
        element.detachEvent("on" + name, wrapper);
      }

      destroyWrapper(id, eventName, handler);

      return element;
    },

    fire: function(element, eventName, memo) {
      element = $(element);
      if (element == document && document.createEvent && !element.dispatchEvent)
        element = document.documentElement;

      var event;
      if (document.createEvent) {
        event = document.createEvent("HTMLEvents");
        event.initEvent("dataavailable", true, true);
      } else {
        event = document.createEventObject();
        event.eventType = "ondataavailable";
      }

      event.eventName = eventName;
      event.memo = memo || { };

      if (document.createEvent) {
        element.dispatchEvent(event);
      } else {
        element.fireEvent(event.eventType, event);
      }

      return Event.extend(event);
    }
  };
})());




var Carousel = Class.create();
Carousel.prototype = {

	//
	//  Setup the Variables
	//
	//imageArr : [],

	activeElement : 0,

	elementCount : null,
	elementWidth : null,
	listWidth : null,

	controlls : null,
	prevButton : null,
	nextButton : null,

	indexLinks : [],

	activeSlide : false,
	//
	//  Initialize the accordions
	//
	initialize: function(options) {


//	    console.info(options);

	    this.options = Object.extend({
	      resizeSpeed : 8,
	      step : 1,
	      autostartDelay : 10000,
	      slideDelay : 10000,

	      showControlls : true,

	      elementIds : {
		  container : 'carousel'
	      },

	      classNames : {
	        clipContainer : 'clipContainer',
	      	controlls : 'controlls',
	      	prevButton : 'previous_button',
	      	nextButton : 'next_button',
	      	index : 'index',

	        hoverClassActive : 'hoverWrap-active',
	        linkClass : 'detailLink',
	        progressClass : 'progress'

	      }
	    }, options || {});




//	    Event.observe(window, 'load', this.move.bindAsEventListener(this));


	    document.observe('dom:loaded', this.start.bindAsEventListener(this));

	},

	move : function(ev){
	    console.info(ev);

	    console.info(ev.pointerX());
	    console.info(ev.pointerY());
	},


	start : function(ev){


	    container = this.options.elementIds.container;
            this.container = $$('#'+container).first();


	    Event.observe(this.container, 'mouseenter', this.controllsShow.bindAsEventListener(this), true);
	    Event.observe(this.container, 'mouseleave', this.controllsHide.bindAsEventListener(this), true);


	    this.clipContainer = $$('#'+container+' .' + this.options.classNames.clipContainer).first();

	    this.list1 = $$('#'+container+' .' + this.options.classNames.clipContainer+' UL').first();
	    this.list2 = this.list1.cloneNode(true);

	    this.list1.insert({after : this.list2});

	    this.elementCount = this.list1.childElements().size();
	    this.elementWidth = this.list1.childElements().first().getWidth();
	    this.listWidth = this.elementWidth * this.elementCount;


	    // move list2 behind list1
	    this.list2.setStyle({left : this.listWidth + 'px'});



	  	this.prevButton = $$('#'+container+' .' + this.options.classNames.prevButton).first();
	  	this.nextButton = $$('#'+container+' .' + this.options.classNames.nextButton).first();
		this.prevButton.setOpacity(0);
		this.nextButton.setOpacity(0);
	  	Event.observe(this.prevButton, 'click', this.prevButtonClick.bindAsEventListener(this), false);
	  	Event.observe(this.nextButton, 'click', this.nextButtonClick.bindAsEventListener(this), false);


	    // Controlls setup
	    if(this.options.showControlls == true){
	  	this.index = $$('#'+container+' .' + this.options.classNames.index).first();
	  	this.indexLinks = $$('#'+container+' .' + this.options.classNames.index + ' a');


		this.index.setOpacity(0);


	  	this.indexLinks.each(function(elm){
	  		Event.observe(elm, 'click', this.indexLinkClick.bindAsEventListener(this), false);
	  	}.bind(this));

	    }

	    this.progress = $$('#'+container+' .' + this.options.classNames.progressClass).first();

	    this.progress.setStyle({'width' : '0px'});
	    this.slideTimer_start(this.options.autostartDelay);

	},


	slideTimer_start : function(time){
//	    console.info('timer start called', time);
//	    this.autostartTimer = window.setTimeout(this.slideTimer.bind(this), this.options.slideDelay);

	    this.progressEffect = new Effect.Morph(this.progress, {
		style: 'width: 857px',
		duration: (time / 1000),
		transition: Effect.Transitions.linear,
		afterFinish: this.slideTimer_end.bind(this)
	    });

	},
	slideTimer_end : function(){
	    //console.info('timer end called');
	    this.progress.setStyle({'width' : '0px'});
	    this.slideRight();
	},
	slideTimer_pause : function(){
	    //console.info('timer pause called');
	    //window.clearTimeout(this.autostartTimer);
	    this.progressEffect.cancel();
	},
	slideTimer_resume : function(){
//	    console.info('timer resume called', this.resetFlag);
//		window.clearTimeout(this.autostartTimer);
//	  	this.autostartTimer = window.setTimeout(this.slideTimer.bind(this), this.options.autostartDelay);

	    if(this.lightbox == true) {
		return true;
	    }

	    if(this.resetFlag == true) {
		time = this.options.slideDelay;
		this.resetFlag = false;
	    } else {
		time = ((this.progressEffect.totalFrames- this.progressEffect.currentFrame) / this.progressEffect.totalFrames) * (this.progressEffect.options.duration*1000);
	    }



	    if(this.progressEffect.state == 'finished'){
		this.slideTimer_start(time);
	    }


	},

	slideTimer_reset : function(){
	    //console.info('timer reset called');
	    this.progressEffect.cancel();
	    this.resetFlag = true;
	    this.progress.setStyle({'width' : '0px'});
	},



	controllsShow : function(ev) {
	    ev.stop();
	    //console.info('controllsOver');

	    this.controllsActive = true;

	    this.slideTimer_pause();

	    new Effect.Morph(this.prevButton, {style : 'opacity:1;', duration: 0.2});
	    new Effect.Morph(this.nextButton, {style : 'opacity:1;', duration: 0.2});

	    if(this.options.showControlls == true){
		new Effect.Morph(this.index, {style : 'opacity:1;', duration: 0.2});
	    }
	},
	controllsHide : function(ev) {
	    ev.stop();
	    //console.info('controllsOut');

	    this.controllsActive = false;

	    this.slideTimer_resume();

	    new Effect.Morph(this.prevButton, {style : 'opacity:0;', duration: 0.2});
	    new Effect.Morph(this.nextButton, {style : 'opacity:0;', duration: 0.2});
	    if(this.options.showControlls == true){
		new Effect.Morph(this.index, {style : 'opacity:0;', duration: 0.2});
	    }
	},


	prevButtonClick : function(ev) {
	    ev.stop();

	    this.slideTimer_reset();

	    this.slideLeft();
	},
	nextButtonClick : function(ev) {
	    ev.stop();

	    this.slideTimer_reset();

	    this.slideRight();
	},

	indexLinkClick : function(ev) {
		ev.stop();

		if(this.activeSlide == true) return;

		a = ev.element();
		li = a.up();

		var i;
		ev.element().up(1).childElements().each(function(elm, c){if(elm == li) i = c;});

		//console.info(i)
		if(this.activeElement == i) return;

		this.activeSlide = true;
		this.activeElement = i;
		this.removeActiveIndex();
		this.slide();

	},
	// ************************************

	slideLeft : function() {
		if(this.activeSlide == true) return;
		this.activeSlide = true;

		this.removeActiveIndex();

		if(this.activeElement <= 0){
			this.list1.setStyle({left : '-' + this.listWidth + 'px'});
			this.list2.setStyle({left : '0px'});

			this.activeElement = this.elementCount-1;
		} else {
			this.activeElement -= this.options.step;
		}

		this.slide();

		//console.info('slide left', this.activeElement, this.elementCount);
	},

	slideRight : function() {
		if(this.activeSlide == true) return;
		this.activeSlide = true;


		this.removeActiveIndex();

		if(this.activeElement >= this.elementCount){
			this.list1.setStyle({left : '0px'});
			this.list2.setStyle({left : (this.listWidth) + 'px'});

			this.activeElement = this.options.step;
		} else {
			this.activeElement += this.options.step;
		}

		this.slide();

	},


	slide : function() {

		pos1 = -this.elementWidth * (this.activeElement);

		var that = this;
		var pos2 = pos1 + this.listWidth;

		new Effect.Parallel(
   			[
				new Effect.Morph(that.list1, {style : 'left : ' + pos1 + 'px', sync: true}),
				new Effect.Morph(that.list2, {style : 'left : ' + pos2 + 'px', sync: true})
			], {duration: 1.0, afterFinish: function() {
				that.afterSlide();
				//console.info('morph left ready');
			}}
		);


	},

	afterSlide : function(){

	    if(this.options.showControlls){
		this.setActiveIndex();
	    }

	    this.activeSlide = false;

	    if(this.controllsActive != true) {
		this.slideTimer_start(this.options.slideDelay);
	    }

	},

	setActiveIndex : function(){
		if(this.activeElement >= this.elementCount) {
			a = this.elementCount-this.activeElement;
		} else {
			a = this.activeElement;
		}
		this.indexLinks[a].addClassName('active');
	},

	removeActiveIndex : function(){
		this.indexLinks.each(function(elm){elm.removeClassName('active')});
	},


	dummy : function(){
	}
}








