/**
 * myMooModal - Notifications
 *
 * @version		2.1.1
 *
 * @requires MooTools v1.2 or later
 *
 * myMooModal is based upon a script written by Augusto Becciu, which was a port to mootools of the
 * original Facebox (http://famspam.com/facebox) written by Chris Wanstrath, and an idea from
 * David Walsh for the facebook layout.  I've added my own bits to extend the class for additional flexibility
 *
 * Licensed under the MIT:
 *
 *   http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright 2007, 2008 Chris Wanstrath [ chris@ozmm.org ]
 * Copyright 2008 Augusto Becciu [ augusto@becciu.org ]
 * Copyright 2010 Peter Barkway [ peter@baytree-cs.com]
 *
 * @license		MIT-style license
 * @author		Peter Barkway <peter [at] baytree-cs.com>
 * @copyright	Author
 *
 * Usage:
 *
 *  window.addEvent('domready', function() {
 *      var myModal = new myMooModal();
 *  });
 *
 *
 *  <a href="#terms" rel="mymoomodal">Terms</a>
 *    Loads the #terms div in the box
 *
 *  <a href="terms.html" rel="mymoomodal">Terms</a>
 *    Loads the terms.html page in the box
 *
 *  <a href="terms.png" rel="mymoomodal">Terms</a>
 *    Loads the terms.png image in the box
 *
 * Dynamic:
 *
 *   var myFacebox = new myMooModal({
 *					title: 'This is a test title',
 *					summary: 'This is a test summary line',
 *					content: 'This is some test content',
 *		});
 *
 *
 * positions: topLeft, topCenter, topRight, centerLeft, center, centerRight, bottomLeft, bottomCenter, bottomRight
 * open & close effects: fadeIn, fadeOut, fromTop, fromBottom, fromLeft, fromRight, fromCenter, toCenter
 *
 *
 *
 *
 */

var myMooModal = new Class({

	Implements: [Options, Events, Chain],

	options: {
		pathToFiles						:'',
    draggable							: 1,
		modal									: 0,
		dropShadow						: 0,
    elementsSelector			: 'a[rel="mymoomodal"]',
    image_types   				: [ 'png', 'jpg', 'jpeg', 'gif' ],
    zIndex								: 65555,
		container							: null,
		stylesheet						: 'myMooModal.css',
		useCss								: 1,
		title									: '',
		summary								: '',
		message								: '',
		onOpen								: function(){},
		onOpenEnd							: function(){},
		onClose								: function(){},
		onCloseEnd						: function(){},
		closeContent 					: '<a href="#" id="close" class="close"><img src="{pathToFiles}images/closelabel.gif" title="close" class="close_image" width="66" height="22" /></a>',
		display								: {
															'duration': 500,
															'effect': 'fadeIn',
															'transition': '',
															'position': 'center'
														},
		close									: {
															'duration': 500,
															'effect': 'fadeOut',
															'transition': ''
														},
		move									: {
															'duration': 500,
															'transition': '',
															'startPosition': ''
														},
		classTitle						: '.dialog_title',
		classSummary					: '.dialog_summary',
		classMessage					: '.dialog_body',
		classClose						: '.dialog_buttons',
		modalStyles						: {
															'background-color': '',
															'margin-top': 10,
															'margin-bottom': 10,
															'margin-left': 10,
															'margin-right': 10,
															'max_width': '',
															'max_height': '',
															'min_width': '',
															'min_height': ''
														},
		overlayStyles					: {
															'background-color': '#000',
															'opacity': 0.15
														},
    modalHtml  						: '\
    <table class="pop_dialog_table"> \
      <tbody> \
        <tr> \
          <td class="pop_topleft" /> \
          <td class="pop_border pop_top" /> \
          <td class="pop_topright" /> \
        </tr> \
        <tr> \
          <td class="pop_border pop_side"/> \
          <td class="pop_content"> \
            <h2 class="dialog_title"></h2> \
						<div class="dialog_summary"></div> \
						<div class="dialog_body"></div> \
						<div class="dialog_buttons"></div> \
          </td> \
          <td class="pop_border pop_side" /> \
        </tr> \
        <tr> \
          <td class="pop_bottomleft" /> \
          <td class="pop_border pop_bottom" /> \
          <td class="pop_bottomright" /> \
        </tr> \
      </tbody> \
    </table>'
	},

	initialize: function(options) {
		this.setOptions(options);
		this.modalSize = {x: 0, y: 0};
		this.container = $(this.options.container) || document.body;
		var preloadImages = [];

		// make paths dynamic
		this.options.stylesheet = this.options.pathToFiles + this.options.stylesheet;
		this.options.closeContent = this.options.closeContent.replace('{pathToFiles}',this.options.pathToFiles)
		
		if(this.options.useCss) this.addCss();

		Keyboard.manager.addEvents({
				'esc': function(){
								Keyboard.stop;
								this.close();			
							}.bind(this)
		});

    var image_types = this.options.image_types.join('|');
    image_types = new RegExp('\.' + image_types + '$', 'i');

    if(this.options.message == '') {
			var elements = $$(this.options.elementsSelector);
			elements.addEvent('click', function(e) {
				e = new Event(e);
				e.stop();

				// This should cope with an image, for example, being used within the a tag (as target would be the image)
				if(!e.target.rel) {
					e.target = $(e.target).getParent('a');
				}

				this.options.title = $(e.target).get('title');
				this.options.summary = $(e.target).get('mooSummary');

				this.buildModal();
				if(this.options.modal) this.buildOverlay();
				this.setTitle();
				this.setSummary();

				if (e.target.href.match(/#/)) { // div
					var url = window.location.href.split('#')[0];
					var target = e.target.href.replace(url+'#','');
					this.options.message = $(target).get("html");
					this.setMessage();
				} else if (e.target.href.match(image_types)) {  // image
			    this.messageEl = this.modalEl.getElement(this.options.classMessage);
					this.options.message = '<div class="mmmImage"><img src="' + e.target.href + '" height="' + $(e.target).get('height') + '" width="' + $(e.target).get('width') + '" /></div>';
					this.setMessage();
				} else { // ajax
					new Request({
						url: e.target.href,
						async: false,
						onComplete: function(response) {
							this.options.message = response;
							this.setMessage();
						}.bind(this)
					}).send();
				}
				this.setClose();
				this.modalDisplay();
			}.bind(this));
		} else {
			this.buildModal();
			if(this.options.modal) this.buildOverlay();
			this.setTitle();
			this.setSummary();
			this.setMessage();
			this.setClose();

			this.modalDisplay();
		}
	},

	/*
	Property: buildModal
		Generate the modal window
	*/	
	buildModal: function(){
		if(this.modalEl) this.modalEl.destroy();
    this.modalEl = new Element('div', {
    									'class': 'myMooModal', 
    									'styles': { 
													  			'opacity': 0,
																	'z-index': this.options.zIndex + 2,
																	'position': 'absolute',
																	'background-color': this.options.modalStyles['background-color'],
																	'top': '0',
																	'left': '0',
																	'overflow': 'hidden'
    														}
    									});
    this.modalEl.set('html', this.options.modalHtml);
    this.modalEl.inject(this.container);

		this.tweens = {
			'box': new Fx.Morph(this.modalEl, ((MooTools.version>=1.3)?((MooTools.version>=1.3)?Object.merge:$merge):$merge)({
					'duration': this.options.display['duration'],
					'unit': 'px',
					'transition': this.options.display['transition'],
					'chain': 'cancel'
				})
			),
			'move': new Fx.Move(this.modalEl, ((MooTools.version>=1.3)?Object.merge:$merge)({
					'duration': this.options.move['duration'],
					'unit': 'px',
					'transition': this.options.move['transition'],
					'chain': 'cancel'
				})
			),
			'fade': new Fx.Tween(this.modalEl, ((MooTools.version>=1.3)?Object.merge:$merge)({
					'property': 'opacity',
					'duration': this.options.display['duration'],
					'chain': 'cancel'
				})).addEvents({
					'onComplete': function() {
						if (!this.element.get('opacity')) this.element.setStyle('display', 'none');
					},
					'onStart': function() {
						if (!this.element.get('opacity')) this.element.setStyle('display', '');
					}
				}
			)
		};
	},
	
	/*
	Property: buildOverlay
		If modality required, this will generate the overlay
	*/	
	buildOverlay: function(){
		this.overlayEl = new Element('div', {
											'id': 'mmmOverlay',
											'styles': {
												'opacity': 0,
												'z-index': this.options.zIndex,
												'position': 'absolute',
												'top': '0',
												'left': '0',
												'background-color': this.options.overlayStyles['background-color'],
												'height': window.getScrollSize().y + 'px',
												'width': window.getScrollSize().x + 'px'
											}
										});
    this.overlayEl.inject(this.container);
	},

	/*
	Property: setTitle
		generate title bar for modal window
	*/	
  setTitle: function() {
   	this.titleEl = this.modalEl.getElement(this.options.classTitle);
    if (this.options.title) {
	    this.titleEl.set('html', this.options.title);

			if (this.options.draggable) {
					this.drag = this.modalEl.makeDraggable({handle: this.titleEl});
					this.titleEl.setStyle('cursor', 'move');
			}
  	} else {
  		this.titleEl.setStyles({
  			display: "none",
  			height: 0
  		});
  	}
  },

	/*
	Property: setSummary
		generate title bar for modal window
	*/	
  setSummary: function() {
	  this.summaryEl = this.modalEl.getElement(this.options.classSummary);
    if (this.options.summary) {
	    this.summaryEl.set('html', this.options.summary);
  	} else {
  		this.summaryEl.setStyles({
  			display: "none",
  			height: 0
  		});
  	}
  },

	/*
	Property: setMessage
		generate title bar for modal window
	*/	
  setMessage: function() {
    this.messageEl = this.modalEl.getElement(this.options.classMessage);
    if (this.options.message) {
	    this.messageEl.set('html', this.options.message);
  	} else {
  		this.messageEl.setStyles({
  			display: "none",
  			height: 0
  		});
  	}
  },

	/*
	Property: setClose
		generate title bar for modal window
	*/	
  setClose: function() {
    if (this.options.closeContent) {
	    this.closeEl = this.modalEl.getElement(this.options.classClose);
	    this.closeEl.set('html', this.options.closeContent);
	    if(this.modalEl.getElement('.close')) 
	    	this.modalEl.getElement('.close').addEvent('click', this.close.bind(this));
  	}
  },

	finishOpen: function() {
		var vars = {position: 'upperLeft',edge: 'upperLeft',offset: {x: this.finishPos.x, y: this.finishPos.y}};
		if(this.options.move['startPosition'] != '') this.tweens.move.start(vars);
		if(this.options.dropShadow) this.dropShadow();
		this.fireEvent('onOpenEnd').callChain();
	},

	finishClose: function() {
		if(this.options.dropShadow) {
			var rel = this.modalEl.get("data-related");
			if ($(rel)) {
				$(rel).setStyle('display', 'none');
				$(rel).destroy();
			}
		}
		this.modalEl.setStyle('opacity', 0);
		this.modalEl.destroy();
		this.modalEl = this.tweens = this.options.title = this.options.summary = this.options.message = null;

		if(this.options.modal) {
			this.overlayEl.setStyle('opacity', 0);
			this.overlayEl.destroy();
		}
		this.fireEvent('onCloseEnd').callChain();
	},

	/*
	Property: modalDisplay
		Show modal window
	*/	
	modalDisplay: function(){
		this.opened = true;
		
		if(this.options.modal) {
			this.overlayEl.setStyle('opacity', this.options.overlayStyles['opacity']);
		}

		this.setModalSize();
		this.startPos = (this.options.move['startPosition'] != '')?this.setModalPosition(this.options.move['startPosition']):this.setModalPosition(this.options.display['position']);
		this.modalEl.setStyles({
			'left': this.startPos.x,
			'top': this.startPos.y
		});
		this.finishPos = this.setModalPosition(this.options.display['position']);
		//alert(this.startPos.y+':'+this.startPos.x+','+this.finishPos.y+':'+this.finishPos.x+','+this.startPos.height+':'+this.startPos.width+','+this.finishPos.height+':'+this.finishPos.width);
		switch(this.options.display['effect']) {
			case 'fromTop':
				this.modalEl.setStyles({
					opacity: 1,
					display: 'block',
					height: 0
				});
				var vars = {left: this.startPos.x, top: this.startPos.y, width: this.modalSize.x, height: this.modalSize.y};
				this.tweens.box.start(vars).chain(this.finishOpen.bind(this));
				break;
			
			case 'fromBottom':
				var bottom = this.startPos.y+this.modalSize.y+this.options.modalStyles['margin-top'];
				var top = this.startPos.y+this.options.modalStyles['margin-top'];
				this.modalEl.setStyles({
					opacity: 1,
					display: 'block',
					top: bottom,
					bottom: bottom,
					width: this.modalSize.x,
					height: 0
				});
				var vars = {left: this.startPos.x, top: this.startPos.y+this.options.modalStyles['margin-top'], width: this.modalSize.x, height: this.modalSize.y};
				this.tweens.box.start(vars).chain(this.finishOpen.bind(this));
				break;

			case 'fromLeft':
				this.modalEl.setStyles({
					opacity: 1,
					display: 'block',
					height: this.modalSize.y,
					width: 0
				});
				var vars = {left: this.startPos.x, top: this.startPos.y, width: this.modalSize.x, height: this.modalSize.y};
				this.tweens.box.start(vars).chain(this.finishOpen.bind(this));
				break;
			
			case 'fromRight':
				var right = this.startPos.x+this.modalSize.x;
				var left = this.startPos.x;
				this.modalEl.setStyles({
					opacity: 1,
					display: 'block',
					left: right,
					right: right,
					height: this.modalSize.y,
					width: 0
				});
				var vars = {left: this.startPos.x, top: this.startPos.y, width: this.modalSize.x, height: this.modalSize.y};
				this.tweens.box.start(vars).chain(this.finishOpen.bind(this));
				break;
			
			case 'fromCenter':
				var bottom = this.startPos.y+this.modalSize.y;
				var top = this.startPos.y;
				var right = this.startPos.x+this.modalSize.x;
				var left = this.startPos.x;
				var center_y = this.startPos.y+(this.modalSize.y/2);
				var center_x = this.startPos.x+(this.modalSize.x/2);
				this.modalEl.setStyles({
					opacity: 1,
					display: 'block',
					left: center_x,
					right: center_x,
					top: center_y,
					bottom: center_y,
					height: 0,
					width: 0
				});
				var vars = {left: this.startPos.x, top: this.startPos.y, width: this.modalSize.x, height: this.modalSize.y};
				this.tweens.box.start(vars).chain(this.finishOpen.bind(this));
				break;
			
			default:
				this.modalEl.setStyles({
					display: 'block',
					opacity: 0
				});
				this.tweens.fade.start(1).chain(this.finishOpen.bind(this));
				break;
		}
		this.fireEvent('onOpen');
	},

	/*
	Property: close
		close the modal window
	*/	
  close: function() {
		if (!this.opened) return this;
		this.opened = false;
		this.fireEvent('onClose');
		this.tweens.box.cancel();
		this.tweens.fade.cancel();
		this.tweens.move.cancel();
    Keyboard.manager.removeEvent('keydown', 'esc');

		switch(this.options.close['effect']) {
			case 'fromTop':
				var bottom = this.finishPos.y+this.modalSize.y;
				var vars = {top: bottom, width: this.modalSize.x, height: 0};
				if (this.tweens.box.timer) this.tweens.box.clearChain();
				this.tweens.box.start(vars).chain(this.finishClose.bind(this));
				break;
			
			case 'fromBottom':
				var vars = {height: 0};
				if (this.tweens.box.timer) this.tweens.box.clearChain();
				this.tweens.box.start(vars).chain(this.finishClose.bind(this));
				break;
						
			case 'fromLeft':
				var right = this.finishPos.x+this.modalSize.x;
				var vars = {left: right, width: 0};
				if (this.tweens.box.timer) this.tweens.box.clearChain();
				this.tweens.box.start(vars).chain(this.finishClose.bind(this));
				break;
			
			case 'fromRight':
				var vars = {width: 0};
				if (this.tweens.box.timer) this.tweens.box.clearChain();
				this.tweens.box.start(vars).chain(this.finishClose.bind(this));
				break;
			
			case 'toCenter':
				var bottom = this.finishPos.y+this.modalSize.y;
				var top = this.finishPos.y;
				var right = this.finishPos.x+this.modalSize.x;
				var left = this.finishPos.x;
				var center_y = this.finishPos.y+(this.modalSize.y/2);
				var center_x = this.finishPos.x+(this.modalSize.x/2);

				var vars = {left: center_x, top: center_y, right: center_x, bottom: center_y, width: 0, height: 0};
				if (this.tweens.box.timer) this.tweens.box.clearChain();
				this.tweens.box.start(vars).chain(this.finishClose.bind(this));
				break;
			
			default:
				this.tweens.fade.start(0).chain(this.finishClose.bind(this));
				break;
		}

    return false;
  },

	/*
	Property: setModalSize
		set the modal window size before displaying
	*/	
	setModalSize: function() {
		var size = this.modalEl.getCoordinates();
		var width = '';
		var height = '';

		if(this.options.modalStyles['min_width'] != '' &&  size.width <= parseFloat(this.options.modalStyles['min_width']))
			width = this.options.modalStyles['min_width'];
		if(this.options.modalStyles['max_width'] != '' &&  size.width >= parseFloat(this.options.modalStyles['max_width']))
			width = this.options.modalStyles['max_width'];
		if(this.options.modalStyles['min_height'] != '' &&  size.height <= parseFloat(this.options.modalStyles['min_height']))
			height = this.options.modalStyles['min_height'];
		if(this.options.modalStyles['max_height'] != '' &&  size.height >= parseFloat(this.options.modalStyles['max_height']))
			height = this.options.modalStyles['max_height'];

		if(width != '') this.modalEl.setStyle('width',width);
		if((this.modalEl.getSize().x + this.options.modalStyles['margin-left'] + this.options.modalStyles['margin-right']) > window.getSize().x) {
			width = window.getSize().x - this.options.modalStyles['margin-left'] - this.options.modalStyles['margin-right'];
			this.modalEl.setStyle('width',width);
		}

		var sizeW = this.modalEl.getSize().y;
		this.titleSize = this.titleEl.getSize();
		this.summarySize = this.summaryEl.getSize();
		this.messageSize = this.messageEl.getSize();
		this.closeSize = this.closeEl.getSize();
		
		if(height != '') this.modalEl.setStyle('height',height);
		if((this.modalEl.getSize().y + this.options.modalStyles['margin-top'] + this.options.modalStyles['margin-bottom']) > window.getSize().y){
			height = window.getSize().y - this.options.modalStyles['margin-top'] - this.options.modalStyles['margin-bottom'];
			this.modalEl.setStyle('height',height);
		}

		// Now work out what height the message body area should be so that we can have scroll bar just for that area
		this.modalSize = this.modalEl.getSize();
		this.modalEl.setStyle('height',this.modalSize.y);
		
		// Take away main block heights from the modal window to find out the height taken up by modal related stuff
		var j = sizeW - this.titleSize.y - this.summarySize.y - this.messageSize.y - this.closeSize.y;
		var julie = this.modalSize.y - this.titleSize.y - this.summarySize.y - this.closeSize.y - j - this.options.modalStyles['margin-top'] - this.options.modalStyles['margin-bottom'];
			this.messageSize.y = julie;
  		this.messageEl.setStyles({
				height: this.messageSize.y,
				overflow: 'auto'
  		});
  		//alert(this.dimensions(this.messageEl).totalHeight);
		//alert(julie+':'+j+':'+this.modalSize.y+'='+this.titleSize.y +':'+ this.summarySize.y +':'+ this.messageSize.y +':'+ this.closeSize.y)
	},

	/*
	Property: setModalPosition
		place modal window in the right place before displaying
	*/	
	setModalPosition: function(pos) {
		this.position = pos;
		if (((MooTools.version>=1.3)?typeOf:$type)(this.position) == 'string') {
			var position = {x: 'center', y: 'center'};
			this.align = {x: 'left', y: 'top'};
			if ((/left|west/i).test(this.position)) position.x = 'left';
			else if ((/right|east/i).test(this.position)) this.align.x = position.x = 'right';
			if ((/upper|top|north/i).test(this.position)) position.y = 'top';
			else if ((/bottom|lower|south/i).test(this.position)) this.align.y = position.y = 'bottom';
			this.position = position;
		}
		var scroll = window.getScroll();
		var left = 0;
		var top = 0;
		switch(this.position.x) {
			case 'left':
				left = (this.modalSize.x >= window.getSize().x)?scroll.x:scroll.x+this.options.modalStyles['margin-left'];
				break;
			case 'right':
				left = (this.modalSize.x >= window.getSize().x)?scroll.x:scroll.x+(window.getSize().x - this.modalSize.x - this.options.modalStyles['margin-right']);
				break;
			default:
			left = (this.modalSize.x >= window.getSize().x)?scroll.x:scroll.x+(window.getSize().x - this.modalSize.x - this.options.modalStyles['margin-left'] - this.options.modalStyles['margin-right'])/2;
				break;
		}
		switch(this.position.y) {
			case 'top':
				top = (this.modalSize.y >= window.getSize().y)?scroll.y:scroll.y+this.options.modalStyles['margin-top'];
				break;
			case 'bottom':
				top = (this.modalSize.y >= window.getSize().y)?scroll.y:scroll.y+(window.getSize().y - this.modalSize.y - this.options.modalStyles['margin-top'] - this.options.modalStyles['margin-bottom']);
				break;
			default:
				top = (this.modalSize.y >= window.getSize().y)?scroll.y:scroll.y+(window.getSize().y - this.modalSize.y - this.options.modalStyles['margin-top'] - this.options.modalStyles['margin-bottom'])/2;
				break;
		}
		return {x:left, y:top, width:this.modalSize.x, height:this.modalSize.y};
	},

	/*
	Property: addCss
		load css on the fly - called by initialization
	*/	
  addCss: function() {
  	var julie = this.options.stylesheet;
  	var found = 0;
		Array.each(document.styleSheets, function(sheet, j){ 
			if(sheet.href != null && sheet.href.test(julie,"i")) found = 1;
		}); 

  	if(!found) this.css = new Asset.css(this.options.stylesheet, { });
	},

    // show the box if necessary, resize the box to fit the next content, then apply it.
    resize_and_apply : function(renderable){
      var fn = function(){
        var size = this.cumulative_size(renderable);
        if(size.width > this.opt.box.max_width || size.height > this.opt.box.max_height) {
          renderable.shrink(size.width <= this.opt.box.max_width);
          size = this.cumulative_size(renderable);
        }
        if(size.width < this.opt.box.min_width || size.height < this.opt.box.min_height) {
          renderable.expand();
          size = this.cumulative_size(renderable);
        }
        var pos = this.next_position(size);
        this.fx.resize.start({
          width : size.width,
          height : size.height,
          left : pos.left,
          top : pos.top
        }).chain(function(){
          this.apply_content(renderable);
        }.bind(this));
      }.bind(this);
      if(this.showing()){
        fn();
      } else {
        this.show(fn);
      }
    },
  
    // the cumulative size of the window based on specific content
    cumulative_size : function(renderable){
      return {
        width : (renderable.dimensions().totalWidth + this.content_padding().width),
        height : (renderable.dimensions().totalHeight + this.content_padding().height)
      };
    },

  // what are the dimensions of the produced element. insert them in a hidden test box, measure, then remove them.
    dimensions : function(el){
      if(!el) return undefined;
      var test = $('diabox_test_box');
      if(!test) (test = new Element('div', {id : 'diabox_test_box'}).setStyle('display', '')).inject(this.modalEl);
      test.grab(el);
      var dim = el.measure(function(){
        return this.getComputedSize();
      });
      test.empty();
      return dim;
    },
    
    dropShadow: function(options) {
		// creates a shadow effect to a rectangular element

		// define defaults
			var options = ((MooTools.version>=1.3)?Object.merge:$merge)({
					id: "dropShadow" + Number.random(100,1000),
					x: 3, // offset from parent
					y: 3,
					border: "1px solid #000",
					background: "#555",
					opacity: .5,
					zIndex: this.modalEl.getStyle("z-index").toInt() - 1 // behind parent
			}, options);

			// only apply shadow on absolutely positioned elements
			if (this.modalEl.getStyle("position") != "absolute")
					return this;

			var c = this.modalEl.getCoordinates();

			new Element("div", {
					id: options.id,
					styles: {
							position: "absolute",
							left: c.left + options.x,
							top: c.top + options.y,
							width: c.width,
							height: c.height,
							background: options.background,
							zIndex: options.zIndex
					},
					opacity: 0
			}).inject(this.modalEl,"before").fade(0, options.opacity);

			// store the shadow id into the element
			this.modalEl.set("data-related", options.id);
	} // end dropShadow

});
