/*
** alexher@gmail.com - 2010 - v1.0
**
** requires: mootools 1.2.4
*/

if (!alexher) alexher = {};

alexher.Diaporama = new Class({
    option: null,
    cur_rank: 0, // rank of currently displayed picture
    nb_images: 0,
    cur_img: 0,
    cur_mini: null,

    /*
    ** Launches Diaporama building...
    **
    ** options :
    **  - target (required): object that contains list (mainly <ul>)
    **  - childrenTagName (default='li'): tagname of each list wrapper
    **  - commentTagName (default='div'): tagname of comment wrapper (inside list wrapper)
    **  - miniWidth (default=64): width of miniature
    **  - miniHeight (default=64): height of miniature
    **  - prev (default=''): DOM element used for prev button (if none, imagePrevURL must be specified)
    **  - next (default=''): DOM element used for next button (if none, imageNextURL must be specified)
    **  - nocomment (default=false): you don't want nor next/prev embed arrow, nor comment text for each img
    **  - nominis (default=false): you don't want miniatures on top of images
    **  - imagePrevURL (default=''): URL of left arrow (prev image)
    **  - imageNextURL (default=''): URL of right arrow (next image)
    **  - transition (default='fade'): way to display next image: fade | slide-h | slide-v | zoom | random
    **  - commentClass (default=null): class to be applied to comment's wrapper (<table>)
    **  - miniHoverClass (default=null): class to be applied to mini's wrapper when mouse 'hovers' it
    **  - demoMode (default=null): makes diaporama run automatically
    **  - auto (default=null): if true, makes diaporama run automatically
    **  - auto_time: (default=3 sec) time to wait before automatically displaying next image
    */
    initialize: function(option)
    {
	if (!option || !option.target) return false;
	if (!option.childrenTagName) option.childrenTagName = 'li';
	if (!option.commentTagName) option.commentTagName = 'div';
	if (!option.miniWidth) option.miniWidth = 64;
	if (!option.miniHeight) option.miniHeight = 64;
	if (!option.transition) option.transition = 'fade';
	if (!option.auto_time) option.auto_time = 3;
	this.option = option;
	this.option.mini = new Array();
	this.Build();
    },

    /*
    ** Builds diaporama from given target
    */
    Build: function()
    {
	// Attaches this object to target
	this.option.target.alexher_diaporama = this;
	// Children :
	//var c = this.option.target.getElements(this.option.childrenTagName);
	if (!this.option.target.getElements) $(this.option.target);
	var c = this.option.target.getElements(this.option.childrenTagName);
	// Wraps all into a <div>
	this.option.wrap = new Element('div', {
	    styles: {
		'position': 'relative',
		'overflow': 'hidden',
		'height': this.option.miniHeight + 8
	    }
	});
	this.option.wrap.injectAfter(this.option.target);
	this.option.wrap.adopt(this.option.target);
	// Resets target's styles + sets width
	this.option.target.setStyles({
	    'width': (this.option.miniWidth + 8) * c.length,
	    'height': this.option.miniHeight + 8,
	    'padding': 0,
	    'margin': 0
	});
	// Wraps target into a <div> (for automatic scrolling)
	this.option.target_wrap = new Element('div', {
	    styles: {
		'position': 'absolute',
		'overflow': 'hidden',
		'height': this.option.miniHeight + 16,
		'z-index': 2600
	    }
	});
	this.option.target_wrap.injectAfter(this.option.target);
	this.option.target_wrap.adopt(this.option.target);

	// Retrieves first image's URI
	var link0_url = c[0].getElement('a').getAttribute('href');
	// Loads first image to know its sizes
	// NB: +'?1' Is a trick to force IE to load image
	//     It is performed for 1st image only !
	this.option.img = new Element('img', {
	    src: link0_url +'?1',
	    events: {
		'load': this.BuildFinish.bind(this)
	    }
	});
	// Updates miniatures appearance
	var img, a;
	for (k = 0; k < c.length; k++, this.nb_images++)
	{
	  if (c[k].get('tag') == 'li')
	    c[k].setStyle('list-style-type', 'none');
	  c[k].setStyles({
	      'display': 'block',
	      'float': 'left',
	      'width': this.option.miniWidth,
	      'height': this.option.miniHeight + 8,
	      'padding': 4,
	      'margin': 0
	  });
	  var commentTag = c[k].getElement(this.option.commentTagName);
	  // Updates links with events
	  a = c[k].getElement('a');
	  img = c[k].getElement('img');
	  img.alexher_diaporama = {
	      'rank': k,
	      'src': a.getAttribute('href'),
	      'comment': (commentTag ? commentTag.innerHTML : ''),
	      'hoverclass': this.option.miniHoverClass
	  };
	  // Applies hover class if needed
	  if (this.option.miniHoverClass)
	  {
	    c[k].addEvent('mouseenter', function (e) {this.addClass(this.getElement('img').alexher_diaporama.hoverclass);}.bind(c[k]));
	    c[k].addEvent('mouseleave', function (e) {this.removeClass(this.getElement('img').alexher_diaporama.hoverclass);}.bind(c[k]));
	  }
	  // Removes comments
	  if (commentTag) {commentTag.dispose();}

	  img.setStyles({
	      'cursor': 'pointer',
	      'width': this.option.miniWidth,
	      'height': this.option.miniHeight
	  });
	  img.addEvents({
	      'click': this.LoadImage.bind(this)
	  });
	  img.injectAfter(a);
	  a.dispose();
	  // Stores miniature
	  this.option.mini.push(img);
	}
	// Waits for image to be loaded to go ahead upon diaporama building...
    },

    /*
    ** Finishes building of diporama
    */
    BuildFinish: function()
    {
	// Removes event from image
	this.option.img.removeEvents('load');
	// Inserts img into diaporama area
	this.option.wrap.adopt(this.option.img);
	// Records image size
	this.option.img_width = (this.option.width ? this.option.width : parseInt(this.option.img.getStyle('width')));
	this.option.img_height = (this.option.height ? this.option.height : parseInt(this.option.img.getStyle('height')));
	this.option.img.setStyles({
	    'width': this.option.img_width,
	    'height': this.option.img_height
	});
	var img_wrap_styles = {
	      'position': 'absolute',
	      'overflow': 'hidden',
	      'width': this.option.img_width,
	      'height': this.option.img_height,
	      'margin-top': this.option.nominis ? 0 : this.option.miniHeight + 8,
	      'z-index': 2200
	    }
	    img_wrap = new Element('div', {
	      'styles': img_wrap_styles
	    }),
	    img2_wrap = new Element('div', {
	      'styles': img_wrap_styles
	    });
	// Second image (for transitions)
	this.option.img2 = new Element('img', {
	    'styles': {
		'width': this.option.img_width,
		'height': this.option.img_height,
		'opacity': 0
	    }
	});
	// Moves images into their wrappers
	img_wrap.injectAfter(this.option.img);
	img_wrap.adopt(this.option.img);
	img2_wrap.injectAfter(img_wrap);
	img2_wrap.adopt(this.option.img2);
	// Sets wrap size
	this.option.wrap.setStyles({
	    'width': this.option.img_width,
	    'height': this.option.img_height + this.option.miniHeight + 8
	});
	// Sets target wrap (scroller) size
	this.option.target_wrap.setStyles({
	    'width': this.option.img_width
	});
	// Activates scrolling
	this.option.scroll = new Scroller(this.option.target_wrap, {area: 100, velocity: 1});
	this.option.target_wrap.addEvent('mouseover', this.option.scroll.start.bind(this.option.scroll));
	this.option.target_wrap.addEvent('mouseout', this.option.scroll.stop.bind(this.option.scroll));
	if (this.option.nominis)
	  this.option.target_wrap.dispose();
	// Builds comments field (on image)
	if (!this.option.nocomment)
	{
	    this.option.comment_wrap = new Element('table', {
		    'class': this.option.commentClass,
		    'styles': {
			'position': 'absolute',
			'overflow': 'hidden',
			'width': this.option.img_width,
			'margin-top': this.option.miniHeight + 8,
			'z-index': 2300
		    }
		});
	    var tbody = new Element('tbody'),
		tr = new Element('tr'),
		td_styles = {
		  'cursor': 'pointer',
		  'vertical-align': 'middle',
		  'padding-top': 12,
		  'padding-bottom': 12,
		  'text-align': 'center',
		  'width': 50
	        },
		td_prev = new Element('td', {
		  'styles': td_styles
		}),
		td_next = new Element('td', {
		  'styles': td_styles
		}),
		td_comment = new Element('td', {
		  'styles': {
		      'vertical-align': 'middle',
		      'width': this.option.img_width - 100,
		      'padding-top': 10,
		      'padding-bottom': 10
		  }
		});
	    this.option.comment_wrap.setAttribute('cellpadding', 0);
	    this.option.comment_wrap.setAttribute('cellspacing', 0);
	    this.option.comment = td_comment;
	    td_prev.adopt(new Element('img', {
		'src': this.option.imagePrevURL,
		'alt': '<<',
		'events': {
		    'click': this.LoadPrevImage.bind(this)
	    }
	    }));
	    td_next.adopt(new Element('img', {
	        'src': this.option.imageNextURL,
		'alt': '>>',
	        'events': {
		    'click': this.LoadNextImage.bind(this)
		}
	    }));
	    this.option.comment_wrap.adopt(tbody); tbody.adopt(tr);
	    this.option.comment.set('html', this.option.mini[0].alexher_diaporama.comment);
	    this.option.comment_wrap.injectAfter(img2_wrap);
	    tr.adopt(td_prev, td_next, td_comment);
	}
	else
	{ 
	    if (this.option.prev)
	      this.option.prev.addEvent('click', this.LoadPrevImage.bind(this));
	    if (this.option.next)
	    this.option.next.addEvent('click', this.LoadNextImage.bind(this));
	}
	// Arrow keys events
	document.removeEvent('keyup', this.LoadNextPrevImage.bind(this));
	document.addEvent('keyup', this.LoadNextPrevImage.bind(this));
	// Adds events to images
	this.option.img.alexher_event = false;
	this.option.img2.alexher_event = true;
	this.option.img2.addEvent('load', this.LoadImage_do.bind(this));

	img_wrap.addEvent('click', this.LoadNextImage.bind(this));
	img2_wrap.addEvent('click', this.LoadNextImage.bind(this));

	// Automatic next image
	if (this.option.auto) setInterval(this.LoadNextImage.bind(this), this.option.auto_time * 1000);
    },

    /*
    ** Updates image from miniature
    */
    LoadImage: function(e, mini)
    {
	var e = (e ? new Event(e) : false),
	    mini = (mini ? mini : e.target),
	    cur_img = (this.cur_img == 0 ? this.option.img : this.option.img2),
	    next_img = (this.cur_img == 0 ? this.option.img2 : this.option.img);
	// Aborts if same image
	if (mini.alexher_diaporama.rank == this.cur_rank) return false;

	if (!next_img.alexher_event)
	{
	  next_img.alexher_event = true;
	  next_img.addEvent('load', this.LoadImage_do.bind(this));
	}

	this.cur_mini = mini;
	next_img.setAttribute('src', '');
	next_img.setAttribute('src', mini.alexher_diaporama.src);
    },
    /*
    ** Updates image after it is loaded
    */
    LoadImage_do: function()
    {
	var cur_img = (this.cur_img == 0 ? this.option.img : this.option.img2),
	    next_img = (this.cur_img == 0 ? this.option.img2 : this.option.img);
	
	// Images animation
	cur_img.getParent().setStyle('z-index', '2200');
	next_img.getParent().setStyle('z-index', '2201');
	anim_cur_img = new Fx.Morph(cur_img, {wait:false, duration: 500});
	anim_next_img = new Fx.Morph(next_img, {wait:false, duration: 500});
	var transition = this.option.transition;
	if (transition == 'random') transition =
	  new Array('fade', 'slide-h', 'slide-v', 'zoom', 'fade', 'slide-v', 'zoom', 'slide-h')[Math.floor(Math.random() * 8)];
	switch (transition)
	{
	case 'fade':
	    next_img.setStyles({'width':this.option.img_width,'height':this.option.img_height,
				'margin-top':0,'margin-left':0});
	    anim_cur_img.start({
		'opacity': 0
	    });
	    anim_next_img.start({
	      'opacity': 1
	    });
	    break;
	case 'slide-h':
	    cur_img.setStyles({'width':this.option.img_width,'height':this.option.img_height,
			       'margin-top':0});
	    next_img.setStyles({'width':this.option.img_width,'height':this.option.img_height,
				'margin-top':0});
	    anim_cur_img.start({
	      'margin-left': (this.cur_rank < this.cur_mini.alexher_diaporama.rank
			      ? [0, -this.option.img_width]
			      : [0, this.option.img_width]),
	      'opacity': 1
	    });
	    anim_next_img.start({
	      'margin-left': (this.cur_rank < this.cur_mini.alexher_diaporama.rank
			      ? [this.option.img_width, 0]
			      : [-this.option.img_width, 0]),
	      'opacity': 1
	    });
	    break;
	case 'slide-v':
	    cur_img.setStyles({'width':this.option.img_width,'height':this.option.img_height,
			       'margin-left':0});
	    next_img.setStyles({'width':this.option.img_width,'height':this.option.img_height,
				'margin-left':0});
	    anim_cur_img.start({
	      'margin-top': (this.cur_rank < this.cur_mini.alexher_diaporama.rank
			      ? [0, -this.option.img_height]
			      : [0, this.option.img_height]),
	      'opacity': 1
	    });
	    anim_next_img.start({
	      'margin-top': (this.cur_rank < this.cur_mini.alexher_diaporama.rank
			      ? [this.option.img_height, 0]
			      : [-this.option.img_height, 0]),
	      'opacity': 1
	    });
	    break;
	case 'zoom':
	    var width_small = Math.floor(this.option.img_width / 2),
		width_big = Math.floor(this.option.img_width * 1.5),
		height_small = Math.floor(this.option.img_height / 2),
		height_big = Math.floor(this.option.img_height * 1.5);
	    anim_cur_img.start({
	      'width': (this.cur_rank < this.cur_mini.alexher_diaporama.rank
			      ? [this.option.img_width, width_big]
			      : [this.option.img_width, width_small]),
	      'height': (this.cur_rank < this.cur_mini.alexher_diaporama.rank
			      ? [this.option.img_height, height_big]
			      : [this.option.img_height, height_small]),
	      'margin-top': (this.cur_rank < this.cur_mini.alexher_diaporama.rank
			      ? [0, Math.floor((this.option.img_width - width_big) / 2)]
			      : [0, Math.floor((this.option.img_width - width_small) / 2)]),
	      'margin-left': (this.cur_rank < this.cur_mini.alexher_diaporama.rank
			      ? [0, Math.floor((this.option.img_height - height_big) / 2)]
			      : [0, Math.floor((this.option.img_height - height_small) / 2)]),
	      'opacity': [1, 0]
	    });
	    anim_next_img.start({
	      'width': (this.cur_rank < this.cur_mini.alexher_diaporama.rank
			      ? [width_small, this.option.img_width]
			      : [width_big, this.option.img_width]),
	      'height': (this.cur_rank < this.cur_mini.alexher_diaporama.rank
			      ? [height_small, this.option.img_height]
			      : [height_big, this.option.img_height]),
	      'margin-top': (this.cur_rank < this.cur_mini.alexher_diaporama.rank
			      ? [Math.floor((this.option.img_width - width_small) / 2), 0]
			      : [Math.floor((this.option.img_width - width_big) / 2), 0]),
	      'margin-left': (this.cur_rank < this.cur_mini.alexher_diaporama.rank
			      ? [Math.floor((this.option.img_height - height_small) / 2), 0]
			      : [Math.floor((this.option.img_height - height_big) / 2), 0]),
	      'opacity': [0, 1]
	    });
	    break;
	}
	// Updates infos
	this.cur_rank = this.cur_mini.alexher_diaporama.rank;
	if (!this.option.nocomment)
	  this.option.comment.set('html', this.cur_mini.alexher_diaporama.comment);
	this.cur_img = 1 - this.cur_img;
    },

    /*
    ** Asks for displaying previous image
    */
    LoadPrevImage: function(e)
    {
	var rank = this.cur_rank - 1;
	if (rank < 0) rank = this.nb_images - 1;
	this.LoadImage(false, this.option.mini[rank]);
    },

    /*
    ** Asks for displaying next image
    */
    LoadNextImage: function(e)
    {
	var rank = this.cur_rank + 1;
	if (rank + 1 > this.nb_images) rank = 0;
	this.LoadImage(false, this.option.mini[rank]);
    },

    LoadNextPrevImage: function(e)
    {
	var e = new Event(e);
	if (e.wheel > 0 || e.key == 'left')
	  this.LoadPrevImage(e);
	else if (e.wheel < 0 || e.key == 'right')
	  this.LoadNextImage(e);
	e.stop();
    }
});

