// +---------------------------------------------------------------------------+
// | This file is part of the Mootools Addon project.                          |
// | Copyright (C) Lemieux Bdard Communication                                |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * Extends the native element in order to add the container properties. The
 * container is basically the reference of the class which is holding an
 * element.
 * @package core
 * @subpackage element
 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
 * @copyright Lemieux Bedard Communication (francois.patry@lemieuxbedard.com)
 * @since 1.0.0
 * @version 1.0.0
 */
Element.implement
({
	/**
	 * @var array The array of object used as actors.
	 */
	actors : null,
	
	/**
	 * @var int The count of actors.
	 */
	actorsCount : 0,

	/**
	 * Set the id of an element. This method is simply a shortcut to the common
	 * set property method allready in place.
	 * @param string The id.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	setId : function(id) {
		this.set('id', id);
	},

	/**
	 * Return the id of an element. This method is simply a shortcut to the common
	 * get property method allready in place.
	 * @return string The id.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getId : function() {
		return this.get('id');
	},
	
	/**
	 * Return the text of an element.
	 * @return string The text.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getText : function() {
		return this.get('text');
	},
	
	/**
	 * Set the text of an element.
	 * @param string The text.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	setText : function(text) {
		this.set('text', text);
	},
	
	/**
	 * Set the inside html of an element.
	 * @param array The html.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	setHtml : function(html) {
		return this.set('html', html);
	},
	
	/**
	 * Return the inside html of an element.
	 * @return array The html.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getHtml : function() {
		return this.get('html');
	},

	/**
	 * Show teh current element.
	 * @param string The display mode.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	show : function(method) { 
		this.setStyle('display', method === undefined ? 'inline' : method); 
	},
	
	/**
	 * Hide teh current element.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	hide : function() { 
		this.setStyle('display', 'none'); 
	},
	
	/**
	 * Set the row id for this element. The row id allows to store the id which
	 * is related to this element in the database.
	 * @param int The row id.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	setRowId : function(id) {
		this.store('rowid', id);
	},
	
	/**
	 * Return the row id for this element. The row id allows to store the id which
	 * is related to this element in the database.
	 * @param int The row id.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getRowId : function() {
		return this.retrieve('rowid');
	},
	
	/**
	 * This method will dispose of an attribute but the attribute will be stored
	 * in the internal class properties using the store method.
	 * @param string The property name.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	disposeProperty : function(property) {
		this.store(property, null);
		this.store(property, this.getProperty(property));
		this.removeProperty(property);
	},
	
	/**
	 * Return the property that was disposed before it was removed.
	 * @param string The property name.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getDisposedProperty : function(property) {
		return this.retrieve(property);
	},
	
	/**
	 * This method will dispose the href attribute but the attribute will be stored
	 * in the internal class properties using the store method.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	disposeHrefProperty : function() {
		this.disposeProperty('href');
		this.setStyle('cursor', 'pointer');
	},
	
	/**
	 * Return the href property that was disposed before it was removed.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getDisposedHrefProperty : function() {
		return this.getDisposedProperty('href');
	},
	
	/**
	 * Initialize the actor array.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	initializeActors : function() {
		if (this.actors == null) this.actors = new Array();
	},
	
	/**
	 * Add an actor to the current element. An actor is basically a class
	 * which will act as a complex event.
	 * @param object The actor object.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	addActor : function(actor) {
		this.initializeActors();
		this.actors.push(actor);
		this.actorsCount++;
		actor.applyOn(this);
	},
	
	/**
	 * Return an actor based on the instance name.
	 * @param object The actor class.
	 * @return object The actor.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getActor : function(actorName) {
		this.initializeActors();
		for (var i = 0; i < this.actors.length; i++) {
			if (this.actors[i] instanceof actorName) {
				return this.actors[i];
			}
		}
		return null;
	},
	
	/**
	 * Return the ammount of actors used on this element.
	 * @return int The actor count.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	getActorCount : function() {
		return this.actorCount;
	},
	
	/**
	 * Indicate whether or not a given actor is acting in this object.
	 * @param object The actor class.
	 * @return bool True if the actor is present.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	hasActor : function(actorName) {
		this.initializeActors();
		for (var i = 0; i < this.actors.length; i++) {
			if (this.actors[i] instanceof actorName) {
				return true;
			}
		}
		return false;
	}
});// +---------------------------------------------------------------------------+
// | This file is part of the Mootools Addon project.                          |
// | Copyright (C) Lemieux BĂ©dard Communication                                |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * An actor is a class that will basically activate itself upon an element using
 * the actAs method of the element.
 * @package core
 * @subpackage actor
 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
 * @copyright Lemieux Bedard Communication (francois.patry@lemieuxbedard.com)
 * @since 1.0.0
 * @version 1.0.0
 */
var MooActor = new Class
({
	/**
	 * @var implements MooElement, Event, Options
	 */
	Implements : [Events, Options],
	
	/**
	 * @var object The element on which the actor will act on.
	 */
	element : null,
	
	/**
	 * Initialize the actor by setting the options.
	 * @param object The options.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	initialize : function(options) {
		this.setOptions(options);
		return this;
	},
	
	/**
	 * This method is called when an object is given as an actor to an element.
	 * @param object The element to apply everything's on.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	applyOn : function(element) {
		this.element = element;
		return this;
	}	
});// +---------------------------------------------------------------------------+
// | This file is part of the Mootools Addon project.                          |
// | Copyright (C) Lemieux BĂ©dard Communication                                |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * This actor will handle the look of the different navigation element.
 * @package core
 * @subpackage actor
 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
 * @copyright Lemieux Bedard Communication (francois.patry@lemieuxbedard.com)
 * @since 1.0.0
 * @version 1.0.0
 */
var MooNavigationElementActor = new Class
({
	/**
	 * @extends MooActor
	 */
	Extends : MooActor,
	
	/**
	 * @var object The options.
	 */
	options : {
		onEmphasize : $empty,
		onNormalize : $empty,
		css : {
			current : 'cur',
			alternate : 'alt'
		}
	},
		
	/**
	 * This method is called when an object is given as an actor to an element.
	 * @param object The element to apply everything's on.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	applyOn : function(element) {
		this.parent(element);
		this.element.addEvent('mouseenter', this.onEmphasize.bind(this));
		this.element.addEvent('mouseleave', this.onNormalize.bind(this));
		return this;
	},
	/**
	 * This event is called when the mouse moves over the tab for the first
	 * time. This method will basically highlight the tab.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	onEmphasize : function() {
		if (this.isCurrent() == false) {
			this.element.addClass(this.options.css.alternate);
			this.fireEvent('onEmphasize');
		}
	},

	/**
	 * This event is called when the mouse moves out the tab for the first
	 * time. This method will basically unhighlight the tab.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	onNormalize : function() {
		if (this.isCurrent() == false) {
			this.element.removeClass(this.options.css.alternate);
			this.fireEvent('onNormalize');
		}
	},

	/**
	 * Indicate wheter or not the tab is considered has the current tab. This
	 * is given by the class named current.
	 * @return bool True if the tab is a current one.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	isCurrent : function() {
		return this.element.hasClass(this.options.css.current);
	}
});// +---------------------------------------------------------------------------+
// | This file is part of the Mootools Addon project.                          |
// | Copyright (C) Lemieux Bdard Communication                                |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * MooFader is a class used to handling fading in and out.
 * @package core
 * @subpackage finder
 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
 * @copyright Lemieux Bedard Communication (francois.patry@lemieuxbedard.com)
 * @since 1.0.0
 * @version 1.0.0
 */
Fx.Fade = new Class
({
	/**
	 * @extends Fx.Tween.
	 */
	Extends: Fx.Tween,
		
	/**
	 * Initialize the fading tween.
	 * @param object The element.
	 * @return object The object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	initialize : function(element) {
		this.parent(element, {'property' : 'opacity', 'duration' : 'short'});
	}
});	 
 
/* A workaround for IE issues in mootools 1.2.1
 * - Recreates FX.Scroll() but utilises 1.2.0's getPosition/getOffset routines.
 */
Fx.ScrollTo = new Class({
 
    'Extends': Fx.Scroll,
 
    'styleString': Element.getComputedStyle,
    'styleNumber': function(element, style) {
        return this.styleString(element, style).toInt() || 0;
    },
    'borderBox': function(element) {
        return this.styleString(element, '-moz-box-sizing') == 'border-box';
    },
    'topBorder': function(element) {
    return 0;
        return this.styleNumber(element, 'border-top-width');
    },
    'leftBorder': function(element) {
    return 0;
        return this.styleNumber(element, 'border-left-width');
    },
    'isBody': function(element) {
        return (/^(?:body|html)$/i).test(element.tagName);
    }, 
    'toElement': function(el) {
        var offset   = {x: 0, y: 0};
        var element  = $(el);
       
        if (this.isBody(element)) {
            return offset;
        }
        var scroll = element.getScrolls();
               
        while (element && !this.isBody(element)){
            offset.x += element.offsetLeft;
            offset.y += element.offsetTop;
           
            if (Browser.Engine.gecko){
                if (!this.borderBox(element)){
                    offset.x += this.leftBorder(element);
                    offset.y += this.topBorder(element);
                }
                var parent = element.parentNode;
                if (parent && this.styleString(parent, 'overflow') != 'visible'){
                    offset.x += this.leftBorder(parent);
                    offset.y += this.topBorder(parent);
                }
            } else if (Browser.Engine.trident || Browser.Engine.webkit){
                offset.x += this.leftBorder(element);
                offset.y += this.topBorder(element);
            }
 
            element = element.offsetParent;
            if (Browser.Engine.trident) {
                while (element && !element.currentStyle.hasLayout) {
                    element = element.offsetParent;
                }
            }
        }
        if (Browser.Engine.gecko && !this.borderBox(element)){
            offset.x -= this.leftBorder(element);
            offset.y -= this.topBorder(element);
        }
       
        var relative = this.element;
        var relativePosition = (relative && (relative = $(relative))) ? relative.getPosition() : {x: 0, y: 0};
        var position = {x: offset.x - scroll.x, y: offset.y - scroll.y};
       
        return this.start(position.x - relativePosition.x, position.y - relativePosition.y);
    }
});
 
 // +---------------------------------------------------------------------------+
// | This file is part of the Mootools Addon project.                          |
// | Copyright (C) Lemieux Bdard Communication                                |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * MooSelector is a mootools implementation of the original event selector.
 * This been ported to mootools by rossco.
 * @package core
 * @subpackage selector
 * @author Ross Lawley
 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
 * @copyright Ross Lawley
 * @since 1.0.0
 * @version 1.0.0
 */
var MooSelector = new Class
({
	/**
	 * Apply the selector rules when the dom ready event is called. This event
	 * is similar to the load event except it does not wait until the image are
	 * fully loaded. This is much faster.
	 * @param object The rules.
	 * @return object This class.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	start : function(rules) {
		window.addEvent('domready', function() {
			this.assign(rules);
		}.bind(this));
		return this;
	},

	/**
	 * Assign the selector rules when the dom ready event is called. This event
	 * is similar to the load event except it does not wait until the image are
	 * fully loaded. This is much faster.
	 * @param object The rules.
	 * @return object This class.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	assign : function(rules) {
		for (var key in rules) {
			var rule = rules[key];
			key.clean().split(',').each(function(selector) {
				var pair = selector.split('::');
				$$(pair[0]).each(function(elem) {
					if (pair.length == 1) return rule(elem);
					// attach the event on the selector
					elem.addEvent(pair[1], rule.pass(elem));
				});
			});
		}
	}
});// +---------------------------------------------------------------------------+
// | This file is part of the Mootools Addon project.                          |
// | Copyright (C) Lemieux BĂ©dard Communication                                |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * MooElementFinder is a class used to find an element using a selector from
 * a given context. The context can be a dom tree or a text tree given by an
 * ajax response.
 * @package core
 * @subpackage finder
 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
 * @copyright Lemieux Bedard Communication (francois.patry@lemieuxbedard.com)
 * @since 1.0.0
 * @version 1.0.0
 */
var MooElementFinder = new Class
({
	/**
	 * @var object The context to search in.
	 */
	context : null,

	/**
	 * Constructor. Set the context used to search in. The context may be a
	 * simple dom object or an ajax response object. This object will search
	 * in both type.
	 * @param object The context.
	 * @return object This class.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	initialize : function(context) {
		this.setContext(context);
		return this;
	},

	/**
	 * Set the context used to search in. The context may be a simple dom object
	 * or an ajax response object. This object will search in both type.
	 * @param object The context.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	setContext : function(context) {
		if (context) { 
			if (typeof context == 'string') { 			
				var html = context.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
				html = (html) ? html[1] : context;		
				this.context = new Element('div').setHtml(html);
			}
		}
		return this;
	},

	/**
	 * Return the context used to search in. The context may be a simple dom object
	 * or an ajax response object. This object will search in both type.
	 * @return object The context.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getContext : function() {
		return this.context;
	},

	/**
	 * Try to find an element in the current context. It's important to specify
	 * both the element id and tag so the search will be successfully in a
	 * ajax response type of context.
	 * @param string The search id.
	 * @param string The search type.
	 * @return object The result.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	find : function(selector) {
		if (this.context == null) return document.getElement(selector);
		// the getElement method will only for some reason find class selectors and
		// not selectors with an id. If we are looking for an id we must search it
		// the old string way
		if (selector.search('#') > -1) {
			selector = selector.replace('#', '');
			selector = selector.replace(' ', '');
			return this.context.getElement('*[id=' + selector + ']');
		} else {
			return this.context.getElement(selector);
		}
	}
});// +---------------------------------------------------------------------------+
// | This file is part of the Mootools Addon project.                          |
// | Copyright (C) Lemieux BĂ©dard Communication                                |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * MooForm is a class which sends a form through an ajax query and handle
 * the result. 
 * @package core
 * @subpackage finder
 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
 * @copyright Lemieux Bedard Communication (francois.patry@lemieuxbedard.com)
 * @since 1.0.0
 * @version 1.0.0
 */
var MooForm = new Class
({
	/**
	 * @implements Events Options The basic element methods.
	 */
	Implements : [Events, Options],
	
	/**
	 * @var object The main element used.
	 */
	element : null,
	
	/**
	 * @var object The options.
	 */
	options : {
		onRequest : $empty,     // this event is called when the request is sent.
		onSuccess : $empty,     // this event is called when the request is completed.
		onError   : $empty,     // this event is called when the form have errors on the response.
		updateOnSuccess : true, // replace the current form with the success selector on success.
		inputSelector : '',     // the selector used to find the input form.
		successSelector : ''    // the selector used to find the success element.
	},
	
	/**
	 * Constructor. Initialize the form handler.
	 * @param object The form element.
	 * @param object The options. 
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	initialize : function(form, options) {
		this.setOptions(options);
		this.element = $(form);
		return this;
	},

	/**
	 * Submit the form by creating the ajax request.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	submit : function() {
		this.fireEvent('request');
		this.element.set('send', { method : 'post', headers: {'X-Request': 'text/html'}, onComplete : this.onComplete.bind(this), evalScripts : true });
		this.element.send();
		return this;
	},

	/**
	 * Find the errors or the success page in the response and update it.
	 * @param object The response. 
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	complete : function(response) {
		var error = false;			
		var oldFormFinder = new MooElementFinder();
		var newFormFinder = new MooElementFinder(response);
		var oldForm = oldFormFinder.find(this.options.inputSelector);
		var newForm = newFormFinder.find(this.options.inputSelector);	
		if (newForm) {			
			var newFormLabels = newForm.getElements('label');
			var oldFormLabels = oldForm.getElements('label');			
			newFormLabels.each(function(label, index) {
				var newLabel = newFormLabels[index];
				var oldLabel = oldFormLabels[index];												
				var newField = newForm.getElement('*[id=' + newLabel.get('for') + ']');
				var oldField = oldForm.getElement('*[id=' + oldLabel.get('for') + ']');				 								 				
				if (newLabel.hasClass('error')) {
					oldLabel.addClass('error');
					error = true;							
					if (oldField) {
						oldField.addClass('error');
					}				
					// add the error message under the field if a new message is set
					var newError = newField.getNext('div.errors');
					var oldError = oldField.getNext('div.errors');
					if (newError) {
						var update = true;
						if (oldError) {
							if (oldError.getText() == newError.getText()) {
								update = false;
							}
						}
						if (update) {
							if (oldError) {
								newError.fade('hide');
								newError.replaces(oldError);
								newError.fade(1);	
							} else {
								newError.fade('hide');
								newError.inject(oldField, 'after');
								newError.fade(1);	
							}							
						}						
					}									
				} else {				
					oldLabel.removeClass('error');							
					if (oldField) {
						oldField.removeClass('error');
						// remove the error message if it exists
						var oldError = oldField.getNext('div.errors');
						if (oldError) {
							oldError.fade(0);
							oldError.dispose();
						}
					}				
				}					
			});			
		} 
		// at this point the form does not contain any errors, we assume it's been submited
		// successfully so we show the success part using the selector
		if (error == false) {			
			if (this.options.updateOnSuccess) {
				var successFinder = new MooElementFinder(response);
				var successFinderElement = successFinder.find(this.options.successSelector);
				if (successFinderElement) {
					oldForm.fade('hide');
					successFinderElement.replaces(oldForm);
					successFinderElement.fade(1);
				}
			}
		} else {
			this.fireEvent('error', response);
		}
		this.fireEvent('success', response);
	},
		
	/**
	 * This method gets called when the request is completed.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	onComplete : function(response) {
		this.complete(response);
	}
});// +---------------------------------------------------------------------------+
// | This file is part of the Mootools Addon project.                          |
// | Copyright (C) Lemieux BĂ©dard Communication                                |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+


var MooControl = new Class
({
	/**
	 * @var implements MooElement, Event, Options
	 */
	Implements : [Events, Options],

	/**
	 * @var object The root element of the control.
	 */
	root : null,

	/**
	 * @var array The array of child elements.
	 */	
	child : {},
	
	/**
	 * @var bool Indicate whether or not the control has been drawn.
	 */
	injected : false,

	/**
	 * This method inject the control into a given object or the document. It 
	 * does not nececerally mean that the object will be visible. 
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	inject : function() {
		this.injected = true;
		return this;
	},
	
	/**
	 * Remove the control from the dom tree and by doing so make the element
	 * invisible. You must override this method. 
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	dispose : function() {
		return this;
	}
});// +---------------------------------------------------------------------------+
// | This file is part of the Mootools Addon project.                          |
// | Copyright (C) Lemieux BĂ©dard Communication                                |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * MooWindow represents an empty window. The content can be obtained by a simple
 * element or for more complex window, a MooElementContent object can be used. In
 * this case, the inject method will have to return the element to insert inside
 * the window.
 * @package mootools
 * @subpackage window
 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
 * @copyright Lemieux Bedard Communication (francois.patry@lemieuxbedard.com)
 * @since 1.0.0
 * @version 1.0.0
 */
var MooBrowserWindow = new Class
({
	/**
	 * Implements Events, Options
	 */
	Implements: [Events, Options],
	
	/**
	 * @var object The window.
	 */
	window : null,
	
	/**
	 * @var string The window location.
	 */
	location : null,
	
	/** 
	 * @var string The window name.
	 */
	name : null,
	
	/**
	 * @var object The options.
	 */
	options : {
		// onWindowOpen : $empty,
		// onWindowClose : $empty,
		alignment : 'center',
		width : 350,
		height : 350,
		showScrollBars : true,
		showLocation : false,
		showStatusBar : false,
		showMenuBar : false,
		showToolBar : false,
		isResizable : false
	},
	
	/**
	 * Initialize the new window.
	 * @param string The window location.
	 * @param object The window options.
	 * @param string The window name.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	initialize : function(location, options, name) {
		this.name = name;
		this.location = location;
		this.setOptions(options);
		return this;
	},
	
	/**
	 * Open the window.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	open : function() {	
		if (this.options.alignment == 'center') {
			var posX = (screen.availWidth) ? (screen.availWidth - this.width) / 2 : 50;
			var posY = (screen.availHeight) ? (screen.availHeight - this.height) / 2 : 50;
		}
		this.window = window.open(this.location, this.name, 'width=' + this.options.width + ',' + 'height=' + this.options.height + ',' + 'top=' + posY + ',' + 'left=' + posX + ',' + 'scrollbars=' + this.toBooleanString(this.options.showScrollBars) + ',' +  'location=' + this.toBooleanString(this.options.showLocation) + ',' +	'directories=' + this.toBooleanString(false) + ',' + 'status=' + this.toBooleanString(this.options.showStatusBar) + ',' + 'menubar=' + this.toBooleanString(this.options.showMenuBar) + ',' + 'toolbar=' + this.toBooleanString(this.options.showToolBar) + ',' + 'resizable=' + this.toBooleanString(this.options.isResizable));
		if (this.window.focus) {
			this.window.focus();
		}
		return this;
	},
	
	/**
	 * Close the window.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	close : function() {
		this.window.close();
	},
	
	/**
	 * Transform a boolean to a string containing 'yes' or 'no'.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	toBooleanString : function(value) {
		return value ? 'yes' : 'no';
	}
});// +---------------------------------------------------------------------------+
// | This file is part of the Mootools Addon project.                          |
// | Copyright (C) Lemieux BĂ©dard Communication                                |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * MooWindow represents an empty window. The content can be obtained by a simple
 * element or for more complex window, a MooElementContent object can be used. In
 * this case, the inject method will have to return the element to insert inside
 * the window.
 * @package mootools
 * @subpackage window
 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
 * @copyright Lemieux Bedard Communication (francois.patry@lemieuxbedard.com)
 * @since 1.0.0
 * @version 1.0.0
 */
var MooWindow = new Class
({
	/**
	 * @extends MooControl The base class for controls.
	 */
	Extends : MooControl,

	/**
	 * @var string The window title
	 */
	title : '',
	
	/**
	 * @var object The window cnotent.
	 */
	content : null,

	/**
	 * @var object The child used to render this control.
	 */
	child : {
		window : null,
		windowFrame : null,
		windowContent : null,
		windowTitleBarClose : null,
		windowTitleBar : null,
		windowOverlay : null
	},
		
	/**
	 * @var object The options.
	 */
	options : {
		onShow : $empty,
		onHide : $empty,
		modal : true,
		movable : false,
		position : 'center',
		sizey : null,
		sizex : 500,
		closeButtonLabel : 'close',
		css : {
			window : 'window',
			windowOverlay : 'window-overlay',
			windowFrame : 'window-frame',
			windowContent : 'window-content',
			windowTitleBar : 'window-title',
			windowTitleBarClose : 'window-close'
		}
	},
	
	/**
	 * Constructor. Set the child required to make the window work.
	 * @param object The window content.
	 * @param string The window title.
	 * @param object The window option.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	initialize : function(content, title, options) {
		this.setOptions(options);
		this.title = title;
		this.content = content;
		this.content.setWindow(this);
		this.inject();
		this.initializeEvents();
	},
	
	/**
	 * Initialize all the events.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	 
	initializeEvents : function() {
		window.addEvent('resize', this.onWindowResize.bind(this));
		this.child.windowTitleBarClose.addEvent('click', this.onWindowTitleBarCloseClick.bind(this));
		return this;
	},
	
	/**
	 * This method inject the control into a given object or the document. It 
	 * does not nececerally mean that the object will be visible. 
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	inject : function() {
		if (this.injected == false) {
			this.parent();
			if (this.options.modal) this.createModalOverlay();
			this.createWindow();
		}
		return this;
	},
		
	/**
	 * This method injects the modal windowOverlay into the document. 
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	createModalOverlay : function() {
		this.child.windowOverlay = new Element('div');
		this.child.windowOverlay.addClass(this.options.css.windowOverlay);
		this.child.windowOverlay.setStyle('top', '0');
		this.child.windowOverlay.setStyle('left', '0');
		this.child.windowOverlay.setStyle('width', '100%');
		this.child.windowOverlay.setStyle('position', 'absolute');
		this.child.windowOverlay.hide();
		this.child.windowOverlay.inject(document.body);
		this.adjustModalOverlay();
		return this;
	},
	
	/**
	 * This method injects the window frame into the document. 
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	 
	 createWindow : function() {
	 	this.createWindowFrame();
	 	this.root.setStyle('position', 'absolute');
	 	if (this.options.sizex != '') this.root.setStyle('width', this.options.sizex);
	 	if (this.options.sizey != '') this.root.setStyle('height', this.options.sizey);
	 	if (this.options.modal == true) this.root.addClass('modal');
	 	if (this.options.movable == true) this.root.addClass('movable');
	 	this.root.hide();
	 	this.root.inject(document.body);
	 	this.adjustWindowPosition();
	 	if (this.options.movable) this.root.makeDraggable();
	 	return this;
	 },
	 
	/**
	 * Draw the window frame element.
	 * @return object A reference to the created element.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	createWindowFrame : function() {
	 	this.root = new Element('div');
	 	this.root.addClass(this.options.css.windowFrame);
	 	this.createWindowTitleBar();
	 	this.createWindowTitleBarClose();
	 	this.createWindowContent();
	 },
	 
	/**
	 * Draw the window windowTitle bar.
	 * @return object A reference to the created element.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	createWindowTitleBar : function() {
		this.child.windowTitleBar = new Element('div');
		this.child.windowTitleBar.addClass(this.options.css.windowTitleBar);
		this.child.windowTitleBar.setHtml(this.title);
		this.child.windowTitleBar.inject(this.root);
		return this;
	},
	
	/**
	 * Draw the window windowTitle bar close button.
	 * @return object A reference to the created element.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	createWindowTitleBarClose : function() {
		this.child.windowTitleBarClose = new Element('div');
		this.child.windowTitleBarClose.addClass(this.options.css.windowTitleBarClose);
		this.child.windowTitleBarClose.setText(this.options.closeButtonLabel);
		this.child.windowTitleBarClose.inject(this.child.windowTitleBar);
		return this;
	},

	/**
	 * Draw the window windowContent element.
	 * @return object A reference to the created element.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	 createWindowContent : function() {
		this.child.windowContent = new Element('div');
		this.child.windowContent.addClass(this.options.css.windowContent);
		this.child.windowContent.inject(this.root);
		this.content.inject(this.child.windowContent);
	},
	
	/**
	 * Adjust the window position based on the position option.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	adjustWindowPosition : function() {
		switch (this.options.position) {
			case 'center' :
			case 'right' :
			case 'left' :
				var l = (this.getViewableSize().x / 2) - (this.root.getSize().x / 2);
		 		var t = (this.getViewableSize().y / 2) - (this.root.getSize().y / 2);
		 		var scroll = window.getScroll();
		 		if (scroll.y > 0) t = t + scroll.y;
		 		this.root.setStyle('top', t + 'px');
	 			this.root.setStyle('left', l + 'px');
	 			break;
		} 
		return this;		
	},
	
	/**
	 * Adjust the window windowContent size.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	adjustWindowSize : function() {
		if (this.options.height != null) {
			var head1 = this.child.windowTitleBar.getSize().y;
			var head2 = this.child.windowTitleBarClose.getSize().y;
			var size  = head1 > head2 ? head1 : head2; 
			var paddingTop = parseInt(this.child.windowContent.getStyle('padding-top'));
			var paddingBot = parseInt(this.child.windowContent.getStyle('padding-bottom'));
			var height = this.options.height - size - paddingTop - paddingBot;
			this.child.windowContent.setStyle('height', height);
		}
	},
	
	/**
	 * This methods adjust the windowOverlay size on the screen.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	adjustModalOverlay : function() {
		this.child.windowOverlay.setStyle('height', this.getDocumentSize().y);
		return this;
	},
		
	/**
	 * Return the viewable size of the current screen.
	 * @return object The viewable size.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	getViewableSize : function() {
		return window.getSize();
	},			
	
	/**
	 * Return the entire document size.
	 * @return object The document size.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	getDocumentSize : function() {
		return window.getScrollSize();
	},
	
	/**
	 * Show the window and the windowOverlay if this window is modal.
	 * @return object A reference to the this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	show : function() {
		if (this.injected) {
			this.fireEvent('show');
			this.root.show('block');
			if (this.options.modal == true) this.child.windowOverlay.show('block');
			if (this.options.movable == false) this.adjustWindowPosition();
			else if (this.options.movable == true && this.adjusted == false) {
				this.adjustWindowPosition();
				this.adjusted = true;
			}			
			this.adjustWindowSize();		
		}
		return this;
	},
	
	/**
	 * Hide the window and the windowOverlay if this window is modal.
	 * @return object A reference to the this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	hide : function() {
		if (this.injected) {
			this.fireEvent('hide');
			this.root.hide();
			if (this.options.modal) this.child.windowOverlay.hide();
		}
		return this;	
	},
	
	/**
	 * Remove the control from the dom tree and by doing so make the element
	 * invisible. You must override this method. 
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	dispose : function() {
		if (this.injected) {
			this.root.dispose();
			if (this.options.modal) this.child.windowOverlay.dispose();
		}
		return this;
	},
	
	/**
	 * This event is called when the window or the browse gets resized.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	onWindowResize : function() {
		if (this.options.modal == true) this.adjustModalOverlay();
		if (this.options.movable == false) this.adjustWindowPosition();
	},
		
	/**
	 * This event is called when the window or the close button gets clicked.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	onWindowTitleBarCloseClick : function() {
		this.hide();
	}
});// +---------------------------------------------------------------------------+
// | This file is part of the Mootools Addon project.                          |
// | Copyright (C) Lemieux BĂ©dard Communication                                |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * MooWindow content is the base class of any content that will be displayed 
 * inside a window. 
 * @package mootools
 * @subpackage window
 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
 * @copyright Lemieux Bedard Communication (francois.patry@lemieuxbedard.com)
 * @since 1.0.0
 * @version 1.0.0
 */
var MooWindowContent = new Class
({
	/**
	 * @extends MooControl The base class for controls.
	 */
	Extends : MooControl, 
	
	/**
	 * @var object The window.
	 */ 
	window : null,

	/**
	 * Initialize the object by setting the root element.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	initialize : function(options) {
		this.setOptions(options);
		this.root = new Element('div');
		return this;
	},

	/**
	 * In the case of a window content, the inject method will return the root
	 * element which contains the window content.
	 * @param object The window.
	 * @return object The root element.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	inject : function(inside) {
		this.root.inject(inside, 'inside');
		return this;
	},
	
	/**
	 * Set the window containing this content.
	 * @param object The window.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	setWindow : function(win) {
		this.window = win;
		return this;
	},
	
	/**
	 * Return the window containing this content.
	 * @return object The window.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getWindow : function() {
		return this.window;
	},
	
	/**
	 * Return the root element of the window content.
	 * @return object The root element.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getRoot : function() {
		return this.root;
	}
});// +---------------------------------------------------------------------------+
// | This file is part of the Cotravel project.                                |
// | Copyright (C) Jean-Philippe Dery                                          |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

var MOO_MAP_LAT = 1;
var MOO_MAP_LNG = 0;

/**
 * MooGMap is a class that automate the process of showing a google map.
 * @package cotravel
 * @subpackage map
 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @copyright Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @since 1.0.0
 * @version 1.0.0
 */
var MooMap = new Class
({
	/**
	 * @implements Event, Options.
	 */	 
	Implements : [Events, Options],
	
	/**
	 * @var object The element where the map is rendered.
	 */
	element : null,
	
	/**
	 * @var object The google map object.
	 */
	map : null,
	
	/**
	 * @var object The google map geocoder object.
	 */
	geo : null,
	
	/**
	 * @var object The options.
	 */
	options : {
		onSearchRequest : $empty,
		onSearchSuggest : $empty,
		onSearchSuccess : $empty,
		onSearchError : $empty
	},
	
	/**
	 * Initialize the google map object.
	 * @param string The map element.
	 * @param object The options,
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	initialize : function(map, options, sizex, sizey) {
		this.setOptions(options);
		this.element = $(map);
		this.initializeMap(sizex, sizey);
		this.initializeGeoCoder();
		return this;
	},
	
	start : function() {
	
	},
	
	/**
	 * Initialize the geo coder client.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	initializeMap : function(sizex, sizey) {
		if (sizex && sizey) {
			// sometime it's required to speciy a size, especially if the map is loaded
			// inside a hidden div. In this case google map cannot find the real size
			// of the map thus centering is not possibe
			this.map = new GMap2(this.element, { size : new GSize(sizex, sizey) });		
		} else {
			this.map = new GMap2(this.element);				
		}
		this.map.addControl(new GLargeMapControl());
		this.map.addControl(new GMapTypeControl());
		// this.map.enableScrollWheelZoom();
		return this;
	},
	
	/**
	 * Initialize the geo coder client.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	initializeGeoCoder : function() {
		this.geo = new GClientGeocoder();
		return this;
	},
			
	/**
	 * Search for an address and trigger the right event.
	 * @param string The address to search.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	search : function(address) {
		this.fireEvent('search');
		this.geo.getLocations(address, function(result) {
			if (result.Status.code == G_GEO_SUCCESS) {
				if (result.Placemark.length > 1) { 
					// if there was more than one result we fire the 
					//suggest event to build a  did you mean service
					this.fireEvent('searchSuggest', [result.Placemark]);
				} else {
					// we have a single marker do we fire the success 
					// event with the placemark
					this.fireEvent('searchSuccess', result.Placemark[0]);
				}
			} else {
				// at this point we have an error. This fires up 
				// the error event with the error code as parameter 
				// so we can treat the error	
				this.fireEvent('searchError', result.Status.code);
            }
		}.bind(this));
		return this;
	},
	
	/**
	 * Center the map from a latitude and a longitude.
	 * @param float The latitude.
	 * @param float The longitude.
	 * @param int The zoom level.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	setCenter : function(lat, lng, zoom) {
		var point = new GLatLng(lat, lng);
		var level = zoom ? zoom : 1;
		this.map.setCenter(point, level);
		return this;
	},
	
	/**
	 * Add a marker at a latitude and a longitude.
	 * @param float The latitude.
	 * @param float The longitude.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */	
	addMarker : function(lat, lng, options) {
		var point = new GLatLng(lat, lng);
		var markr = new GMarker(point, options);
		this.map.addOverlay(markr);
		return markr;
	},
	
	/**
	 * Add a polygon to the map.
	 * @param array The array of points.
	 * @param string The stroke color.
	 * @param int The stroke weight.
	 * @param int The stroke opacity.
	 * @param string The fill color;
	 * @param string The fill opacity.
	 * @return object A reference to the polygon.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	addPolygon : function(points, strokeColor, strokeWeight, strokeOpacity, fillColor, fillOpacity) {
		var polygon = new GPolygon(this.convertPointArrayToLatLngArray(points), strokeColor, strokeWeight, strokeOpacity, fillColor, fillOpacity);
		this.map.addOverlay(polygon);
		return polygon;
	},
	
	/**
	 * @return array An array of points.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	convertPointArrayToLatLngArray : function(arr) {
		var points = new Array();
		for (var i = 0; i < arr.length; i += 2) {
			var lat = arr[i + 0];
			var lng = arr[i + 1];
			points.push(new GLatLng(lat, lng));
		}
		return points;
	},
	
	/**
	 * Remove all the overlays.
	 * @param float The latitude.
	 * @param float The longitude.
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */	
	clearOverlays : function() {
		this.map.clearOverlays();
		return this;
	},
	
	/**
	 * Change the map type.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */	
	setMapTypeToNormal : function() {
		this.map.setMapType(G_NORMAL_MAP);
	},
	
	/**
	 * Change the map type.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */	
	setMapTypeToSatellite : function() {
		this.map.setMapType(G_SATELLITE_MAP);
	},
	
	/**
	 * Change the map type.
	 * @return void
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */	
	setMapTypeToHybrid : function() {
		this.map.setMapType(G_HYBRID_MAP);
	}
});// +---------------------------------------------------------------------------+
// | This file is part of the Estrie 05 project.                               |
// | Copyright (C) Jean-Philippe Dery                                          |
// |                                                                           |
// | For the full copyright and license information, please view the LICENSE   |
// | file that was distributed with this source code.                          |
// +---------------------------------------------------------------------------+

/**
 * EstrieMap is a class that automate the process of showing a google map.
 * @package estrie05
 * @subpackage map
 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @copyright Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @since 1.0.0
 * @version 1.0.0
 */
var EstrieMap = new Class
({
	/**
	 * @extends MooMap
	 */
	Extends: MooMap,

	/**
	 * @var int The current region id.
	 */
	regionId : 0,
	
	/**
	 * @var int The current mrc id.
	 */
	mrcId : 0,

	/**
	 * @var int The current sector id.
	 */
	sectorId : 0,	
	
	/**
	 * @var int The sector code.
	 */
	sectorCode : 0,
	
	/**			
	 * @var int The current page id.
	 */
	pageId : 0,
		
	/**
	 * @var bool Is the map loading or not.
	 */
	loading : true,
	
	/**
	 * @var object The region.
	 */
	region : null,
	
	/**
	 * @var array The list of mrc.
	 */
	mrcs : null,
	
	/**
	 * @var array the list of industrial parks.
	 */
	parks : null,
	
	/**
	 * @var object The current directory.
	 */
	currentDirectory : null,
	
	/**
	 * @var int The current directory index.
	 */
	currentDirectoryIndex : -1,

	/**
	 * @var string The current display.
	 */
	currentDisplay : 'enterprises',
	
	/**
	 * @var object a few objects needed.
	 */
	legend : null,
	
	listboxShowIndustrialPakers : null,
	
	listboxShowEnterprises : null,
	
	/**
	 * @var array The current directory.
	 */
	directory : null,
		
	/**
	 * @var object The options.
	 */
	options : {
		// onLoadingCompleted   : $empty,
		defaultLng: 20,
		defaultLat: 0,
		defaultZoom: 5,
		loadingLayerElement: null,
		loadingTextElement: null,
		generalMrcFillStyle: {opacity : 0.4},
		selectedMrcFillStyle: {opacity : 0.1},
		locationUrl: '',
		directoryUrl: '',
		regionUrl: '',
		mrcUrl: '',
		draggeableMarkers: false
	},
	
	/**
	 * Initialize the google map object.
	 * @param string The map element.
	 * @param object The options,
	 * @return object A reference to this object.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	initialize : function(map, options, sizex, sizey) {
		this.parent(map, options, sizex, sizey)
		this.setCenter(this.options.defaultLat, this.options.defaultLng, this.options.defaultZoom);
		this.setMapTypeToHybrid();
		this.setOptions({
			onSearchRequest : this.directoryGeoCodeRequest.bind(this),
			onSearchSuggest : this.directoryGeoCodeSuggest.bind(this),
			onSearchSuccess : this.directoryGeoCodeSuccess.bind(this),
			onSearchError   : this.directoryGeoCodeError.bind(this)
		});		
		this.directory = [];
		this.markers = [];
		this.parks = [];
		this.mrcs = [];
	},
	
	/**
	 * Starts the map.
	 * @return void.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	start : function() {
		this.getRegion(this.regionId, function(region, mrcs) {
			this.region = region;
			// at this point the zones are loaded, we need to show the list
			// on the map and only when it's over we can display the directory
			// of enterprises
			if (this.mrcId == 0) {
				this.setCenter(
					parseFloat(region.center_lat), 
					parseFloat(region.center_lng), 
					parseInt(region.center_zoom)
				);
			}
			this.initializeMrcs(mrcs);
			this.getDirectory(this.mrcId, this.sectorId, this.sectorCode, function(directory) {
				this.processDirectory(directory);
			});
		});
	},
	
	/**
	 * Update the map to reflect the data given.
	 * @return void.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since 1.0.0
	 */
	update : function(regionId, mrcId, sectorId, sectorCode, pageId, onCompleteCallback) {
		this.clearDirectoryMarkers();
		this.setMapTypeToHybrid();
		this.hideIndustrialParks();
		if (this.currentDisplay != 'enterprises') {
			this.toggleEnterprisesAndIndustrialParks();
		}
		this.currentDisplay = 'enterprises';
		if (mrcId == 0) {
			this.setMrcFillStyleToGeneral(this.mrcId);
			this.setCenter(
				parseFloat(this.region.center_lat), 
				parseFloat(this.region.center_lng), 
				parseInt(this.region.center_zoom)
			);
			this.regionId = regionId;
			this.mrcId = mrcId;
			this.sectorId = sectorId;
			this.sectorCode = sectorCode;
			this.pageId = pageId;
			this.loading = true;
			this.showLoadingAnimation();
			this.getDirectory(mrcId, sectorId, sectorCode, function(directory) {
				this.markers = [];
				this.directory = [];
				this.currentDirectory = null;
				this.currentDirectoryIndex = -1;
				this.processDirectory(directory);
				if (onCompleteCallback) {
					onCompleteCallback.run(null, this);
				}
				this.loading = false;
				this.hideLoadingAnimation();
			});
		} else {
			this.loading = true;
			this.showLoadingAnimation();
			this.setSelectedMrc(mrcId, pageId, function() {
				this.getDirectory(mrcId, sectorId, sectorCode, function(directory) {
					this.mrcId = mrcId;
					this.regionId = regionId;					
					this.sectorId = sectorId;
					this.sectorCode = sectorCode;
					this.pageId = pageId;
					this.directory = [];
					this.markers = [];
					this.currentDirectory = null;
					this.currentDirectoryIndex = -1;
					this.processDirectory(directory);
					if (onCompleteCallback) {
						onCompleteCallback.run(null, this);
					}
				}.bind(this));
			}.bind(this));
		}
	},

	/**
	 * Set the zone id.
	 * @param int The zone id.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	setRegionId : function(regionId) {
		this.regionId = regionId ? regionId : 0;
	},
	
	/**
	 * Return the region id.
	 * @return int The zone id.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getRegionId : function() {
		return this.regionId;
	},
	
	/**
	 * Set the zone id.
	 * @param int The zone id.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	setMrcId : function(mrcId) {
		this.mrcId = mrcId ? mrcId : 0;
	},
	
	/**
	 * Return the zone id.
	 * @return int The zone id.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getMrcId : function() {
		return this.mrcId;
	},
	
	/**
	 * Set the page id.
	 * @param int The page id.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	setPageId : function(pageId) {
		this.pageId = pageId ? pageId : 0;
	},
	
	/**
	 * Return the page id.
	 * @return int The page id.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getPageId : function() {
		return this.pageId;
	},
	
	/**
	 * Set the sector id.
	 * @param int The sector id.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	setSectorId : function(sectorId) {
		this.sectorId = sectorId ? sectorId : 0;
	},
	
	/**
	 * Return the sector id.
	 * @return int The sector id.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getSectorId : function() {
		return this.sectorId;
	},

	/**
	 * Set the sector code.
	 * @param int The sector code.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	setSectorCode : function(sectorCode) {
		this.sectorCode = sectorCode ? sectorCode : 0;
	},
	
	/**
	 * Return the sector code.
	 * @return int The sector code.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getSectorCode : function() {
		return this.sectorCode;
	},

	/**
	 * Set the loading flag.
	 * @param bool The loading flag.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	setLoading : function(loading) {
		this.loading = loading;
	},
	
	/**
	 * Return the loading flag.
	 * @return bool The loading flag.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getLoading : function() {
		return this.loading;
	},
	
	/**
	 * Show the loading animation.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	showLoadingAnimation : function() {
		this.options.loadingLayerElement.show();
		this.options.loadingTextElement.show();
	},
	
	/**
	 * Hide the loading animation.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	hideLoadingAnimation : function() {
		this.options.loadingLayerElement.hide();
		this.options.loadingTextElement.hide();
	},
	
	/**
	 * Retrieve the data of a region using an ajax request.
	 * @param int The region id.
	 * @param object The callback function.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getRegion : function(regionId, onCompleteCallback) {
		new Request.JSON({url : this.parseRegionUrl(regionId), onComplete : function(response) {
			var region = response.region;
			var mrcs = response.mrcs;
			onCompleteCallback.run([region, mrcs], this);
		}.bind(this)}).send();
	},
	
	/**
	 * Add the right parameters to the region url.
	 * @param int The region id.
	 * @return string The region url with parameters.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	parseRegionUrl : function(regionId) {
		var url = this.options.regionUrl;
		url = url.replace('11', regionId);
		return url;
	},	
	
	/**
	 * Retrieve the data of a mrc using an ajax query.
	 * @param int The mrc id.
	 * @param int The page id.
	 * @param function The callback
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getMrc : function(mrcId, pageId, onCompleteCallback) {
		new Request.JSON({url : this.parseMrcUrl(mrcId, pageId), onComplete : onCompleteCallback.bind(this)}).send();
	},
	
	/**
	 * Add the right parameters to the region url.
	 * @param int The region id.
	 * @return string The region url with parameters.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	parseMrcUrl : function(mrcId, pageId) {
		var url = this.options.mrcUrl;
		url = url.replace('11', this.regionId);
		url = url.replace('22', mrcId);
		url = url.replace('33', pageId);
		return url;
	},
	
	/**
	 * Initialize all the pieces of the map.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	initializeMrcs : function(mrcs) {
		mrcs.each(function(mrc) {
			var shape = mrc.shape.split(',');
			var layer = this.addPolygon(shape, '#ffffff', 2, 1, mrc.color, 0.4);
			this.mrcs[mrc.id] = {
				id : mrc.id,
				color : mrc.color,
				shape : shape,
				layer : layer,
				center_lat : mrc.center_lat,
				center_lng : mrc.center_lng,
				center_zoom : mrc.center_zoom
			};
			// hide the current zone and update the position to
			// make it fit correctly on the map			
			if (mrc.id == this.mrcId) {
				this.setMrcFillStyleToSelected(mrc.id);
				this.setCenter(
					parseFloat(mrc.center_lat), 
					parseFloat(mrc.center_lng), 
					parseInt(mrc.center_zoom)
				);
			}
		}.bind(this));
	},
	
	/**
	 * Set the selected mrc.
	 * @param int The mrc id.
	 * @param int The page id.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	setSelectedMrc : function(mrcId, pageId, onCompleteCallback) {
		this.getMrc(mrcId, pageId, function(response) {
			var mrc = response.mrc;
			var parks = response.parks;
			if (mrc) {
				this.setMrcFillStyleToGeneral(this.mrcId);
				this.setMrcFillStyleToSelected(mrcId);
				if (this.mrcId != mrcId) {
					this.removeIndustrialParks();
					// we only try to center the zone and adjust the zoom if
					// we changed the mrc
					this.setCenter(
						parseFloat(mrc.center_lat), 
						parseFloat(mrc.center_lng), 
						parseInt(mrc.center_zoom)
					);
					// add the industrial pakers		
					parks.each(function(park, i) {
						if (this.parks[park.id] == undefined ||
							this.parks[park.id] == null) {
							var shape = park.shape.split(',');
							var layer = this.addPolygon(shape, park.color, 2, 1, park.color, 0.4);
							this.parks[park.id] = {
								id : park.id,
								color : park.color,
								shape : shape,
								layer : layer		
							};
							layer.hide();
							var originalZoom = this.map.getZoom();
							var originalBounds = this.map.getBounds();
							GEvent.addListener(layer, 'click', function() {
								if (layer.zoomedToIndustrialPark == true) {
									layer.zoomedToIndustrialPark = false;
									this.map.setCenter(originalBounds.getCenter(), originalZoom);
								} else {
									layer.zoomedToIndustrialPark = true;
									var bounds = layer.getBounds();
									var center = layer.getBounds().getCenter();
									this.map.setCenter(center, this.map.getBoundsZoomLevel(bounds));
								}						
							}.bind(this));	
						};
						this.parks[park.id].layer.show();
					}.bind(this));
				} 
				this.mrcId = mrcId;
				this.pageId = pageId;
			}			
			onCompleteCallback.run(null, this);
		}.bind(this));
	},
	
	/**
	 * Hide all the industrial parks.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	hideIndustrialParks : function() {
		this.parks.each(function(park, i) {
			if (park) {
				park.layer.hide();
			}
		});
	},
	
	/**
	 * Hide a given industrial park.
	 * @param object The industrial park.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	hideIndustrialPark : function(id) {
		this.parks.each(function(park) {
			if (park) {
				if (park.id == id) {
					park.layer.hide();
					return;
				}
			}
		});
	},
	
	/**
	 * Show all the industrial parks.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	showIndustrialParks : function() {
		this.parks.each(function(park) {
			if (park) {
				park.layer.show();
			}
		});	
	},
	
	/**
	 * Show a given industrial park.
	 * @param object The industrial park.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	showIndustrialPark : function(id) {
		this.parks.each(function(park) {
			if (park) {
				if (park.id == id) {
					park.layer.show();
					return;
				}
			}
		});
	},
	
	removeIndustrialParks : function() {
		this.parks.each(function(park, i) {
			if (park) {
				this.map.removeOverlay(park.layer);
			}
		}.bind(this));
		this.parks = null;
		this.parks = [];
	},
				
	/**
	 * Apply the general fill style on a zone.
	 * @param object The zone.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */		
	setMrcFillStyleToGeneral : function(mrcId) {
		if (this.mrcs[mrcId]) {
			this.mrcs[mrcId].layer.setFillStyle(this.options.generalMrcFillStyle);
		}
	},
	
	/**
	 * Apply the selected fill style on a zone.
	 * @param object The zone.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */	
	setMrcFillStyleToSelected : function(mrcId) {
		if (this.mrcs[mrcId]) {
			this.mrcs[mrcId].layer.setFillStyle(this.options.selectedMrcFillStyle);
		}
	},
	
	/**
	 * Retrieve all the directory records.
	 * @param int The zone id.
	 * @param int The sector id.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	getDirectory : function(mrcId, sectorId, sectorCode, onCompleteCallback) {
		new Request.JSON({url : this.parseDirectoryUrl(mrcId, sectorId, sectorCode), onComplete : onCompleteCallback.bind(this)}).send();
	},
	
	/**
	 * Add the right parameters to the region url.
	 * @param int The region id.
	 * @return string The region url with parameters.
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	parseDirectoryUrl : function(mrcId, sectorId, sectorCode) {
		var url = this.options.directoryUrl;
		url = url.replace('11', this.regionId);
		url = url.replace('22', mrcId);
		url = url.replace('33', sectorId);
		url = url.replace('44', sectorCode);
		return url;
	},				
	
	/**
	 * Process the directory recursively, sometime using ajax request to geocode
	 * some locations.
	 * @param int The zone id.
	 * @param int The sector id.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philippe.dery@lemieuxbedard.com)
	 * @since 1.0.0
	 */
	processDirectory : function(directory) {
		if (directory) this.directory = directory;
		this.currentDirectoryIndex++;
		this.currentDirectory = this.directory[this.currentDirectoryIndex];		
		if (this.currentDirectory == null ||Â this.currentDirectory == undefined) {
			// there is no directory data at this position so we can assume this is done loading
			this.setLoading(false);
			this.hideLoadingAnimation();
			this.fireEvent('loadingCompleted');
			return;
		}
		if (this.currentDirectory.lat == 0 && this.currentDirectory.lng == 0) {
			// at this point the enterprise does not have any coordinates we can use. we must
			// put the geocoding hat on but before we must be sure this enterprise is geocodable
			// otherwise we will try to geocode it forever
			if (this.currentDirectory.dirty && 
				this.currentDirectory.exist) {
				// geocode the address using google map
				this.search([this.currentDirectory.adresse, this.currentDirectory.ville, 'QC', 'CANADA'].join(' '));
			} else {
				// processDirectory the next entry in the stack
				this.processDirectory();
			}
		} else {
			// at this point the current directory item allready have a longitude and
			// latitude so there is no need to regeocode it
			this.addDirectoryMarker(this.currentDirectory);
			this.processDirectory();
		}
	},

	/**
	 * Add a marker.
	 * @param object The directory item.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philipe.dery@lemieuxbedard.ca
	 * @since 1.0.0
	 */
	addDirectoryMarker : function(directory) {
		var sectorIcon = 'map_icon_' + directory.sector_id + '.png';
		if (directory.sector_id)   sectorIcon = 'map_icon_' + directory.sector_id + '.png';
		if (directory.sector_code) sectorIcon = 'map_icon_code_' + directory.sector_code + '.png';
		if (this.sectorId != 0)   sectorIcon = 'map_icon_' + this.sectorId + '.png';
		if (this.sectorCode != 0) sectorIcon = 'map_icon_code_' + this.sectorCode + '.png';
		var icon = new GIcon();
		icon.image = 'http://www.estrie05.ca/images/icons/' + sectorIcon;
		icon.shadow = 'http://www.estrie05.ca/images/icons/map_icon_shadow.png';
		icon.iconSize = new GSize(20, 28);
		icon.shadowSize = new GSize(40, 28);
		icon.iconAnchor = new GPoint(17, 28);
		icon.infoWindowAnchor = new GPoint(17, 28);
		var options = { 'icon' : icon, draggable : this.options.draggeableMarkers };
		var marker = this.addMarker(directory.lat, directory.lng, options);
		marker.database_id = directory.id;
		directory.marker = marker;
		// add the description bubble on the of of hte marker
		var description = '<p class="h1"><strong>' + directory.raison_sociale + '</strong></p><br />';
		description += directory.description + ' <br /> ';
		description += directory.adresse + ' ';
		description += directory.ville   + ' ';
		if (directory.website) description += 'Site Web : <a target="_blank" href="' + directory.website + '">' + directory.website + '</a>' + ' <br />';
		description += 'TĂ©lĂ©phone : ' + directory.phone;
		GEvent.addListener(marker, 'click', function() {
			marker.openInfoWindowHtml(description);
		});	
	},

	/**
	 * Clear all the directory markers.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philipe.dery@lemieuxbedard.ca
	 * @since 1.0.0
	 */			
	clearDirectoryMarkers : function() {
		this.directory.each(function(directory, i) {
			if (directory.marker) this.map.removeOverlay(directory.marker); 
		}.bind(this));
	},
	
	hideDirectoryMarkers : function() {
		this.directory.each(function(directory, i) {
			if (directory.marker) directory.marker.hide(); 
		}.bind(this));
	},

	showDirectoryMarkers : function() {
		this.directory.each(function(directory, i) {
			if (directory.marker) directory.marker.show(); 
		}.bind(this));
	},

	toggleEnterprisesAndIndustrialParks : function() {
		if (this.currentDisplay == 'enterprises') {
			this.currentDisplay = 'industrial_parks';
			this.hideDirectoryMarkers();
			this.showIndustrialParks();
			this.setMapTypeToNormal();
			this.listboxShowIndustrialPakers.addClass('dn');
			this.listboxShowEnterprises.removeClass('dn');
			this.legend.show('block');			
		} else {
			this.currentDisplay = 'enterprises';
			this.showDirectoryMarkers();
			this.hideIndustrialParks();
			this.setMapTypeToHybrid();
			this.listboxShowIndustrialPakers.removeClass('dn');
			this.listboxShowEnterprises.addClass('dn');
			this.legend.hide();		
		}
	},

	/**
	 * Reinitialize the directory array.
	 * @return void.
	 * @author Jean-Philippe Dery (jean-philipe.dery@lemieuxbedard.ca
	 * @since 1.0.0
	 */
	resetDirectory : function() {
		this.directory = [];
		this.currentDirectory = null;
		this.currentDirectoryIndex = -1;
	},

	/**
	 * Save the enterprise information. This method will make sure the processDirectorying
	 * continues once the data is saved.
	 * @param object The directory item.
	 * @return void
	 * @author Jean-Philippe Dery (jean-philipe.dery@lemieuxbedard.ca
	 * @since 1.0.0
	 */
	saveDirectoryLocation : function(directory) {
		var parameters = '';
		parameters += 'cid=' + directory.cld_id;
		parameters += '&eid=' + directory.enterprise_id;
		parameters += '&coordinate[address]=' + directory.adresse;
		parameters += '&coordinate[city]=' + directory.ville;
		parameters += '&coordinate[postal_code]=' + directory.code_postal;
		parameters += '&coordinate[lat]=' + directory.lat;
		parameters += '&coordinate[lng]=' + directory.lng;	
		new Request.JSON({url : this.options.locationUrl,  onComplete : function() { 
			this.processDirectory(); 
		}.bind(this)}).send(parameters);
	},

	/**
	 * A request has been sent to google.
	 * @author Jean-Philippe Dery (jean-philipe.dery@lemieuxbedard.ca
	 * @since 1.0.0
	 */			
	directoryGeoCodeRequest : function() {
		// nothing special
	},

	/**
	 * Google map returned suggestions.
	 * @author Jean-Philippe Dery (jean-philipe.dery@lemieuxbedard.ca
	 * @since 1.0.0
	 */	
	directoryGeoCodeSuggest : function(locations) {
		this.directoryGeoCodeSuccess(locations[0]);
	},

	/**
	 * Google map found the address.
	 * @author Jean-Philippe Dery (jean-philipe.dery@lemieuxbedard.ca
	 * @since 1.0.0
	 */				
	directoryGeoCodeSuccess : function(location) {
		this.currentDirectory.lat = location.Point.coordinates[MOO_MAP_LAT];
		this.currentDirectory.lng = location.Point.coordinates[MOO_MAP_LNG];
		this.addDirectoryMarker(this.currentDirectory);
		this.saveDirectoryLocation(this.currentDirectory);
	},

	/**
	 * Google map did not found the address.
	 * @author Jean-Philippe Dery (jean-philipe.dery@lemieuxbedard.ca
	 * @since 1.0.0
	 */	
	directoryGeoCodeError : function(e) {
		this.currentDirectory.lat = 0;
		this.currentDirectory.lng = 0;
		this.saveDirectoryLocation(this.currentDirectory);
	}
});
