/**
 * jQuery route
 * Version 1.0.0 (18/11/2009)
 * @requires jQuery v1.2.1 or later
 *
 * Copyright (c) 2009 Michel Meyer
 */
var Route = function(name, url, module, action, parameters){
	this.name        = name;
	this.module      = module; 
	this.action      = action;
	this.parameters  = parameters;
	this.relativeUrl = null;
};

Route.prototype.getModule = function(){
	return this.module;
};

Route.prototype.getAction = function(){
	return this.action;
};

Route.prototype.getParameter = function(name){
	return this.parameters[name] ? this.parameters[name] : null;
};

Route.prototype.getParameters = function(){
	return this.parameters;
};

Route.prototype.getRelativeUrl = function(){
	return this.relativeUrl;
};

/**
 * jQuery routingRule
 * Version 1.0.0 (18/11/2009)
 * @requires jQuery v1.2.1 or later
 *
 * Copyright (c) 2009 Michel Meyer
 */
RoutingRule = function(parameters){
	
	var noHttpUrlPattern  = /^\//i; 
	this.urlPattern       = parameters[0];
	this.matchPattern     = new RegExp($.posixToPerlRegExp(parameters[1]).replace(noHttpUrlPattern, '.*(/|.*\.php/)'), 'i');
	this.parameters       = parameters[2];
	this.parameterDefault = parameters[3];
	this.module           = parameters[4].module;
	this.action           = parameters[4].action;
	this.postfix          = parameters[5];

	
};



RoutingRule.prototype.getMatchingRoute = function(url, name)
{
	var matches         = url.match(this.matchPattern);
	var route           = false;
	var currentUrl      = url;
	var currentRuleName = name;
	
	if(matches)
	{
		var parameters    = {};
		var defaultValues = this.parameterDefault;
		
		$(this.parameters).each(function(index){
			if(matches[index + 2])
			{
				parameters[this] = matches[index + 2];
			}
			else 
			{
				parameters[this] = defaultValues[this];
			}
		});

		route =  new Route(currentRuleName, currentUrl, this.module, this.action, parameters);
	}
	
	return route;
};


/**
 * jQuery routingManager
 * Version 1.0.0 (18/11/2009)
 * @requires jQuery v1.2.1 or later
 *
 * Copyright (c) 2009 Michel Meyer
 */
RoutingManager = function(rulesConfig){
	this.routingRules = new Array();
	
	for(ruleConfig in rulesConfig){
		this.routingRules[ruleConfig] = new RoutingRule(rulesConfig[ruleConfig]);
	}
};

RoutingManager.prototype.findRoute = function(url)
{
	var rule = false;
	var routingRule = null;
	
	for(routingRuleName in this.routingRules){	
		
		routingRule = this.routingRules[routingRuleName];		
		if(rule = routingRule.getMatchingRoute(url, routingRuleName))
		{
			return rule;
		}
	}
	return rule;
	
}



/**
 * extend jQuery Methods
 */

$.fn.addRoute = function (){
	
	this.each(function(){
		if($(this).attr('href'))
		{
			var rule = routingRules.findRoute($(this).attr('href'));
	        
	        if(rule)
	        {
	        	this.route = rule;
	        }
	    }
	});
};

/**
 * return a routing object
 * 
 * @return Route
 */
$.fn.getRoute = function(){
	var route = null;
	
	if($(this)[0] != undefined)
	{
		if($(this)[0].route == undefined)
		{
			$(this).addRoute();
		}
		route = $(this)[0].route ? $(this)[0].route : null;
	}
	
	return route;
};

/**
 * return a collection of a named routing parameter
 * 
 * @param string routing parameter name
 * @return Array parameters collection 
 */
$.fn.routeParameterToArray = function(name){
	var parameterName = name;
	var parameters = [];
	
	
	$(this).each(function(){
		if(this.route == undefined)
		{
			$(this).addRoute();
		}
		
		if($(this).getRoute() && $(this).getRoute().getParameter(parameterName))
		{
			parameters.push($(this).getRoute().getParameter(parameterName));
		}
	});
	
	return parameters;
};

/**
 * return element with a specific routing value
 * 
 * @param string routing parameter name
 * @param string routing searched value (not required)
 * @return jQuery jQuery DOM Element collection 
 */
$.fn.withRoutingValue = function(name, value){
	
	var foundedElements = null;
	
	$(this).each(function(){
		if(this.route == undefined)
		{
			$(this).addRoute();
		}
		if($(this).getRoute() && $(this).getRoute().getParameter(name))
		{
			if($(this).getRoute().getParameter(name) == value)
			{
				foundedElements = foundedElements == null ? $(this) : foundedElements.add($(this)); 
			}
			else if(value == undefined)
			{
				foundedElements = foundedElements == null ? $(this) : foundedElements.add($(this)); 
			}
		}
	});
	
	return foundedElements;
};


