define(["jquery", "globals"], function($, globals) {
	"use strict";
	
	var pathParamRe = /\{([a-zA-Z0-9]+)\}/;
	
	function Route(uri) {
		if( !(this instanceof Route) ) return new Route(uri);
		this._uri = $.trim(uri);
	}
	
	Route.prototype = {
		_uri: null,
		_uriComponents: null,
		_uriParams: null,
		
		applyParams: function(params) {
			var x, ret, comp, val;
			if( this._uriParams === null ) this._extractUriComponents();
			params = $.extend({}, params);
			ret = {
				uri: null,
				queryParams: params
			};
			comp = this._uriComponents.slice(0);
			for( x in this._uriParams ) {
				if( !this._uriParams.hasOwnProperty(x) ) continue;
				val = params[x];
				if( val == null ) throw new Error("required path param " + x + " missing from params - Route(" + this._uri + ")");
				if( $.isFunction(val) ) val = val();
				comp[this._uriParams[x]] = val;
				delete params[x];
			}
			ret.uri = "/" + comp.join("/");
			return ret;
		},
		
		_extractUriComponents: function() {
			var split, tmp, i, params={}, components=[];
			split = this._uri.split("/");
			for( i=0; i < split.length; i++ ) {
				if( !split[i] ) continue;
				if( pathParamRe.test(split[i]) ) {
					tmp = pathParamRe.exec(split[i])[1];
					params[tmp] = i;
					components.push(tmp);
				}
				else components.push(split[i]);
			}
			this._uriComponents = components;
			this._uriParams = params;
		},
		
		append: function(path) {
			var newUri = appendPath(this._uri, path);
			return new Route(newUri);
		}
	};
	
	function appendPath(pathNow, path) {
		if( path != null ) {
			path = ""+path;
			var nowEndsWithSlash = (pathNow.length > 0 && pathNow.charAt(pathNow.length-1) === "/"),
			    pathStartsWithSlash = (path.length > 0 && path.charAt(0) === "/");
			if( nowEndsWithSlash && pathStartsWithSlash ) {
				pathNow += path.substring(1);
			}
			else if( (nowEndsWithSlash && !pathStartsWithSlash) || (!nowEndsWithSlash && pathStartsWithSlash) ) {
				pathNow += path;
			}
			else {
				pathNow += "/" + path;
			}
		}
		return pathNow;
	}
	
	function makeContextPath(path) {
		return appendPath(globals.contextPath.substr(1), path);
	}
	
	return {
		contextPath: globals.contextPath,
		Route: Route,
		appendPath: appendPath,
		makeContextPath: makeContextPath
	};
});
