

/**
 * jCarousel - Riding carousels with jQuery
 *   http://sorgalla.com/jcarousel/
 *
 * Copyright (c) 2006 Jan Sorgalla (http://sorgalla.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * Built on top of the jQuery library
 *   http://jquery.com
 *
 * Inspired by the "Carousel Component" by Bill Scott
 *   http://billwscott.com/carousel/
 */
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(9($){$.1v.C=9(o){z 4.1b(9(){3p r(4,o)})};8 q={Z:F,25:1,21:1,u:7,1c:3,15:7,1K:\'2X\',2c:\'2Q\',1q:0,B:7,1j:7,1G:7,2F:7,2B:7,2z:7,2x:7,2v:7,2s:7,2p:7,1S:\'<P></P>\',1Q:\'<P></P>\',2m:\'2l\',2k:\'2l\',1O:7,1L:7};$.C=9(e,o){4.5=$.16({},q,o||{});4.Q=F;4.D=7;4.H=7;4.t=7;4.U=7;4.R=7;4.N=!4.5.Z?\'1H\':\'26\';4.E=!4.5.Z?\'24\':\'23\';8 a=\'\',1e=e.K.1e(\' \');1r(8 i=0;i<1e.I;i++){6(1e[i].2y(\'C-2w\')!=-1){$(e).1E(1e[i]);8 a=1e[i];1p}}6(e.2t==\'3o\'||e.2t==\'3n\'){4.t=$(e);4.D=4.t.19();6(4.D.1o(\'C-H\')){6(!4.D.19().1o(\'C-D\'))4.D=4.D.B(\'<P></P>\');4.D=4.D.19()}10 6(!4.D.1o(\'C-D\'))4.D=4.t.B(\'<P></P>\').19()}10{4.D=$(e);4.t=$(e).3h(\'>2o,>2n,P>2o,P>2n\')}6(a!=\'\'&&4.D.19()[0].K.2y(\'C-2w\')==-1)4.D.B(\'<P 3g=" \'+a+\'"></P>\');4.H=4.t.19();6(!4.H.I||!4.H.1o(\'C-H\'))4.H=4.t.B(\'<P></P>\').19();4.R=$(\'.C-11\',4.D);6(4.R.u()==0&&4.5.1Q!=7)4.R=4.H.1z(4.5.1Q).11();4.R.V(4.K(\'C-11\'));4.U=$(\'.C-17\',4.D);6(4.U.u()==0&&4.5.1S!=7)4.U=4.H.1z(4.5.1S).11();4.U.V(4.K(\'C-17\'));4.H.V(4.K(\'C-H\'));4.t.V(4.K(\'C-t\'));4.D.V(4.K(\'C-D\'));8 b=4.5.15!=7?1k.1P(4.1m()/4.5.15):7;8 c=4.t.32(\'1F\');8 d=4;6(c.u()>0){8 f=0,i=4.5.21;c.1b(9(){d.1I(4,i++);f+=d.S(4,b)});4.t.y(4.N,f+\'T\');6(!o||o.u===J)4.5.u=c.u()}4.D.y(\'1y\',\'1A\');4.U.y(\'1y\',\'1A\');4.R.y(\'1y\',\'1A\');4.2G=9(){d.17()};4.2b=9(){d.11()};4.1U=9(){d.2q()};6(4.5.1j!=7)4.5.1j(4,\'2a\');6($.2A.28){4.1f(F,F);$(27).1u(\'2I\',9(){d.1t()})}10 4.1t()};8 r=$.C;r.1v=r.2H={C:\'0.2.3\'};r.1v.16=r.16=$.16;r.1v.16({1t:9(){4.A=7;4.G=7;4.X=7;4.13=7;4.14=F;4.1d=7;4.O=7;4.W=F;6(4.Q)z;4.t.y(4.E,4.1s(4.5.21)+\'T\');8 p=4.1s(4.5.25);4.X=4.13=7;4.1i(p,F);$(27).22(\'2E\',4.1U).1u(\'2E\',4.1U)},2D:9(){4.t.2C();4.t.y(4.E,\'3u\');4.t.y(4.N,\'3t\');6(4.5.1j!=7)4.5.1j(4,\'2D\');4.1t()},2q:9(){6(4.O!=7&&4.W)4.t.y(4.E,r.M(4.t.y(4.E))+4.O);4.O=7;4.W=F;6(4.5.1G!=7)4.5.1G(4);6(4.5.15!=7){8 a=4;8 b=1k.1P(4.1m()/4.5.15),N=0,E=0;$(\'1F\',4.t).1b(9(i){N+=a.S(4,b);6(i+1<a.A)E=N});4.t.y(4.N,N+\'T\');4.t.y(4.E,-E+\'T\')}4.1c(4.A,F)},3s:9(){4.Q=1h;4.1f()},3r:9(){4.Q=F;4.1f()},u:9(s){6(s!=J){4.5.u=s;6(!4.Q)4.1f()}z 4.5.u},3q:9(i,a){6(a==J||!a)a=i;6(4.5.u!==7&&a>4.5.u)a=4.5.u;1r(8 j=i;j<=a;j++){8 e=4.L(j);6(!e.I||e.1o(\'C-1a-1D\'))z F}z 1h},L:9(i){z $(\'.C-1a-\'+i,4.t)},2u:9(i,s){8 e=4.L(i),20=0,2u=0;6(e.I==0){8 c,e=4.1B(i),j=r.M(i);1n(c=4.L(--j)){6(j<=0||c.I){j<=0?4.t.2r(e):c.1X(e);1p}}}10 20=4.S(e);e.1E(4.K(\'C-1a-1D\'));1R s==\'3l\'?e.3k(s):e.2C().3j(s);8 a=4.5.15!=7?1k.1P(4.1m()/4.5.15):7;8 b=4.S(e,a)-20;6(i>0&&i<4.A)4.t.y(4.E,r.M(4.t.y(4.E))-b+\'T\');4.t.y(4.N,r.M(4.t.y(4.N))+b+\'T\');z e},1V:9(i){8 e=4.L(i);6(!e.I||(i>=4.A&&i<=4.G))z;8 d=4.S(e);6(i<4.A)4.t.y(4.E,r.M(4.t.y(4.E))+d+\'T\');e.1V();4.t.y(4.N,r.M(4.t.y(4.N))-d+\'T\')},17:9(){4.1C();6(4.O!=7&&!4.W)4.1T(F);10 4.1c(((4.5.B==\'1Z\'||4.5.B==\'G\')&&4.5.u!=7&&4.G==4.5.u)?1:4.A+4.5.1c)},11:9(){4.1C();6(4.O!=7&&4.W)4.1T(1h);10 4.1c(((4.5.B==\'1Z\'||4.5.B==\'A\')&&4.5.u!=7&&4.A==1)?4.5.u:4.A-4.5.1c)},1T:9(b){6(4.Q||4.14||!4.O)z;8 a=r.M(4.t.y(4.E));!b?a-=4.O:a+=4.O;4.W=!b;4.X=4.A;4.13=4.G;4.1i(a)},1c:9(i,a){6(4.Q||4.14)z;4.1i(4.1s(i),a)},1s:9(i){6(4.Q||4.14)z;6(4.5.B!=\'18\')i=i<1?1:(4.5.u&&i>4.5.u?4.5.u:i);8 a=4.A>i;8 b=r.M(4.t.y(4.E));8 f=4.5.B!=\'18\'&&4.A<=1?1:4.A;8 c=a?4.L(f):4.L(4.G);8 j=a?f:f-1;8 e=7,l=0,p=F,d=0;1n(a?--j>=i:++j<i){e=4.L(j);p=!e.I;6(e.I==0){e=4.1B(j).V(4.K(\'C-1a-1D\'));c[a?\'1z\':\'1X\'](e)}c=e;d=4.S(e);6(p)l+=d;6(4.A!=7&&(4.5.B==\'18\'||(j>=1&&(4.5.u==7||j<=4.5.u))))b=a?b+d:b-d}8 g=4.1m();8 h=[];8 k=0,j=i,v=0;8 c=4.L(i-1);1n(++k){e=4.L(j);p=!e.I;6(e.I==0){e=4.1B(j).V(4.K(\'C-1a-1D\'));c.I==0?4.t.2r(e):c[a?\'1z\':\'1X\'](e)}c=e;8 d=4.S(e);6(d==0){3f(\'3e: 3d 1H/26 3c 1r 3b. 3a 39 38 37 36 35. 34...\');z 0}6(4.5.B!=\'18\'&&4.5.u!==7&&j>4.5.u)h.33(e);10 6(p)l+=d;v+=d;6(v>=g)1p;j++}1r(8 x=0;x<h.I;x++)h[x].1V();6(l>0){4.t.y(4.N,4.S(4.t)+l+\'T\');6(a){b-=l;4.t.y(4.E,r.M(4.t.y(4.E))-l+\'T\')}}8 n=i+k-1;6(4.5.B!=\'18\'&&4.5.u&&n>4.5.u)n=4.5.u;6(j>n){k=0,j=n,v=0;1n(++k){8 e=4.L(j--);6(!e.I)1p;v+=4.S(e);6(v>=g)1p}}8 o=n-k+1;6(4.5.B!=\'18\'&&o<1)o=1;6(4.W&&a){b+=4.O;4.W=F}4.O=7;6(4.5.B!=\'18\'&&n==4.5.u&&(n-k+1)>=1){8 m=r.Y(4.L(n),!4.5.Z?\'1l\':\'1N\');6((v-m)>g)4.O=v-g-m}1n(i-->o)b+=4.S(4.L(i));4.X=4.A;4.13=4.G;4.A=o;4.G=n;z b},1i:9(p,a){6(4.Q||4.14)z;4.14=1h;8 b=4;8 c=9(){b.14=F;6(p==0)b.t.y(b.E,0);6(b.5.B==\'1Z\'||b.5.B==\'G\'||b.5.u==7||b.G<b.5.u)b.2j();b.1f();b.1M(\'2i\')};4.1M(\'31\');6(!4.5.1K||a==F){4.t.y(4.E,p+\'T\');c()}10{8 o=!4.5.Z?{\'24\':p}:{\'23\':p};4.t.1i(o,4.5.1K,4.5.2c,c)}},2j:9(s){6(s!=J)4.5.1q=s;6(4.5.1q==0)z 4.1C();6(4.1d!=7)z;8 a=4;4.1d=30(9(){a.17()},4.5.1q*2Z)},1C:9(){6(4.1d==7)z;2Y(4.1d);4.1d=7},1f:9(n,p){6(n==J||n==7){8 n=!4.Q&&4.5.u!==0&&((4.5.B&&4.5.B!=\'A\')||4.5.u==7||4.G<4.5.u);6(!4.Q&&(!4.5.B||4.5.B==\'A\')&&4.5.u!=7&&4.G>=4.5.u)n=4.O!=7&&!4.W}6(p==J||p==7){8 p=!4.Q&&4.5.u!==0&&((4.5.B&&4.5.B!=\'G\')||4.A>1);6(!4.Q&&(!4.5.B||4.5.B==\'G\')&&4.5.u!=7&&4.A==1)p=4.O!=7&&4.W}8 a=4;4.U[n?\'1u\':\'22\'](4.5.2m,4.2G)[n?\'1E\':\'V\'](4.K(\'C-17-1w\')).1J(\'1w\',n?F:1h);4.R[p?\'1u\':\'22\'](4.5.2k,4.2b)[p?\'1E\':\'V\'](4.K(\'C-11-1w\')).1J(\'1w\',p?F:1h);6(4.U.I>0&&(4.U[0].1g==J||4.U[0].1g!=n)&&4.5.1O!=7){4.U.1b(9(){a.5.1O(a,4,n)});4.U[0].1g=n}6(4.R.I>0&&(4.R[0].1g==J||4.R[0].1g!=p)&&4.5.1L!=7){4.R.1b(9(){a.5.1L(a,4,p)});4.R[0].1g=p}},1M:9(a){8 b=4.X==7?\'2a\':(4.X<4.A?\'17\':\'11\');4.12(\'2F\',a,b);6(4.X!==4.A){4.12(\'2B\',a,b,4.A);4.12(\'2z\',a,b,4.X)}6(4.13!==4.G){4.12(\'2x\',a,b,4.G);4.12(\'2v\',a,b,4.13)}4.12(\'2s\',a,b,4.A,4.G,4.X,4.13);4.12(\'2p\',a,b,4.X,4.13,4.A,4.G)},12:9(a,b,c,d,e,f,g){6(4.5[a]==J||(1R 4.5[a]!=\'2h\'&&b!=\'2i\'))z;8 h=1R 4.5[a]==\'2h\'?4.5[a][b]:4.5[a];6(!$.2W(h))z;8 j=4;6(d===J)h(j,c,b);10 6(e===J)4.L(d).1b(9(){h(j,4,d,c,b)});10{1r(8 i=d;i<=e;i++)6(i!==7&&!(i>=f&&i<=g))4.L(i).1b(9(){h(j,4,i,c,b)})}},1B:9(i){z 4.1I(\'<1F></1F>\',i)},1I:9(e,i){8 a=$(e).V(4.K(\'C-1a\')).V(4.K(\'C-1a-\'+i));a.1J(\'2V\',i);z a},K:9(c){z c+\' \'+c+(!4.5.Z?\'-2U\':\'-Z\')},S:9(e,d){8 a=e.2g!=J?e[0]:e;8 b=!4.5.Z?a.1x+r.Y(a,\'2f\')+r.Y(a,\'1l\'):a.2e+r.Y(a,\'2d\')+r.Y(a,\'1N\');6(d==J||b==d)z b;8 w=!4.5.Z?d-r.Y(a,\'2f\')-r.Y(a,\'1l\'):d-r.Y(a,\'2d\')-r.Y(a,\'1N\');$(a).y(4.N,w+\'T\');z 4.S(a)},1m:9(){z!4.5.Z?4.H[0].1x-r.M(4.H.y(\'2T\'))-r.M(4.H.y(\'2S\')):4.H[0].2e-r.M(4.H.y(\'2R\'))-r.M(4.H.y(\'3i\'))},2P:9(i,s){6(s==J)s=4.5.u;z 1k.2O((((i-1)/s)-1k.2N((i-1)/s))*s)+1}});r.16({3m:9(d){z $.16(q,d||{})},Y:9(e,p){6(!e)z 0;8 a=e.2g!=J?e[0]:e;6(p==\'1l\'&&$.2A.28){8 b={\'1y\':\'1A\',\'2M\':\'2L\',\'1H\':\'1q\'},1Y,1W;$.29(a,b,9(){1Y=a.1x});b[\'1l\']=0;$.29(a,b,9(){1W=a.1x});z 1W-1Y}z r.M($.y(a,p))},M:9(v){v=2K(v);z 2J(v)?0:v}})})(3v);',62,218,'||||this|options|if|null|var|function||||||||||||||||||||list|size||||css|return|first|wrap|jcarousel|container|lt|false|last|clip|length|undefined|className|get|intval|wh|tail|div|locked|buttonPrev|dimension|px|buttonNext|addClass|inTail|prevFirst|margin|vertical|else|prev|callback|prevLast|animating|visible|extend|next|circular|parent|item|each|scroll|timer|split|buttons|jcarouselstate|true|animate|initCallback|Math|marginRight|clipping|while|hasClass|break|auto|for|pos|setup|bind|fn|disabled|offsetWidth|display|before|block|create|stopAuto|placeholder|removeClass|li|reloadCallback|width|format|attr|animation|buttonPrevCallback|notify|marginBottom|buttonNextCallback|ceil|buttonPrevHTML|typeof|buttonNextHTML|scrollTail|funcResize|remove|oWidth2|after|oWidth|both|old|offset|unbind|top|left|start|height|window|safari|swap|init|funcPrev|easing|marginTop|offsetHeight|marginLeft|jquery|object|onAfterAnimation|startAuto|buttonPrevEvent|click|buttonNextEvent|ol|ul|itemVisibleOutCallback|reload|prepend|itemVisibleInCallback|nodeName|add|itemLastOutCallback|skin|itemLastInCallback|indexOf|itemFirstOutCallback|browser|itemFirstInCallback|empty|reset|resize|itemLoadCallback|funcNext|prototype|load|isNaN|parseInt|none|float|floor|round|index|swing|borderTopWidth|borderRightWidth|borderLeftWidth|horizontal|jcarouselindex|isFunction|normal|clearTimeout|1000|setTimeout|onBeforeAnimation|children|push|Aborting|loop|infinite|an|cause|will|This|items|set|No|jCarousel|alert|class|find|borderBottomWidth|append|html|string|defaults|OL|UL|new|has|unlock|lock|10px|0px|jQuery'.split('|'),0,{}))


/**
 * An itinerary item
 * 
 */
ItineraryItem = function (id, destination, section, name, contact, description) {
	this.id          = id;
	this.destination = destination;
	this.section     = section;
	this.name        = name;
	this.contact     = contact;
	this.description = description
}

/**
 * The tripBuilder
 * 
 * 
 * The widget is like this:
 * 
 * <div id="td">
 * 	<ul>
 * 		<li class="destination">
 * 			<h2 class="title"><a href="/en/destinations/las-vegas">Las Vegas</a></h2>
 * 			<div>
 * 			<ul class="sections">
 * 				<li class="section">
 * 					<h3 class="title">Hotels</h3>
 * 					<ul class="items">
 * 						<li class="item">
 * 							<h4 class="name">Wynn Hotel</h4>
 *							<div class="description"> ... </div>
 * 							<p class="contact">12345 Sunset Blvd., 555-1234</p>
 * 							<a class="rem">Remove</a>
 *					...
 * 			</ul>
 * 			</div>
 * 	</ul>
 * </div>
 * 
 * @param string|jQuery el The element for the tripBuilder widget
 */
TripBuilder = function ( el ) {
	this.$el = $( el );
	this.renderer = new TripBuilderRenderer( this );
	this.items = this.renderer.parse( el );
	
	this.setupAccordion();
	this.setupEmailForm();
}
/**
 * TripBuilder translations
 */
TripBuilderTranslations = {
	'errorAddDest':   'Error Adding Destination',
	'remDest':        'Remove Destination',
	'rem':		   	  'Remove',
	'confirmRemDest': 'Are you sure you wish to remove ',
	'more':			  'More',
	'less': 		  'Less',
	'add':			  'Add'
}

/**
 * TripBuilder Class
 */
TripBuilder.prototype = {
	/**
	 * Set up the accordion functionality
	 * 
	 */
	setupAccordion: function ( ) {
		var accSelect = this.$el.find( 'h2 a[href=' + window.location.pathname + ']' ).parent().get( 0 );
		this.$el.find('> ul').tripBuilderAccordion( { select: accSelect } );
	},
	/**
	 * Set up the email form
	 * 
	 */
	setupEmailForm: function ( ) {
		var $emailForm = this.$el.find( 'form.emailform' );
		
		if ( $emailForm.length ) {

			this.$el.find( '.actions .email' ).click( function ( e ) {
				if ( $emailForm.css( 'display' ) == 'none' ) {
					$emailForm.css( 'display', '' );
					$emailForm.find( '#emailaddress' ).focus();
				} else {
					$emailForm.css( 'display', 'none' );
				}
				return false;
			} );
			
			$emailForm.hide();
			
			var action     = $emailForm.attr( 'action' );
			var submitForm = function ( value ) {
				$.post( action + '?ajax', {
					'data[recipient]': value
				}, function ( data ) {
					$emailForm.parent().append( '<p class="message">' + data.message + '</p>' );
					if ( data.success ) {
						$emailForm.hide();
					} else {
						$emailForm.find( '#emailaddress' ).focus();
					}
				}, 'json' );
			}
			
			$emailForm.submit( function ( e ) {
				$emailForm.parent().find( 'p.message' ).remove();
				submitForm( $(this).find( '#emailaddress' ).val() );
				return false;
			} );

		}
	},
	/**
	 * Bind an event listener to this instance
	 * 
	 * @param string event The name of the event
	 * @param function fn The function to call
	 */
	bind: function ( event, fn ) {
		this.$el.bind(event, fn);
	},
	/**
	 * Add an item to the tripBuilder
	 * 
	 * @param ItineraryItem item The item to add
	 */
	add: function ( item ) {
		var _this = this;
		$.post('/destinations/add_user_itinerary', {
			'data[itinerary_item_id]': item.id
		}, function ( data ) { _this._addcallback( data, item ) }, 'json');
	},
	/**
	 * Callback called on a successful add of an itinerary item
	 * 
	 */
	_addcallback: function ( data, item ) {
		if ( typeof data.message != 'undefined' ) {
			alert( TripBuilderTranslations['errorAddDest'] );
			return false;
		}
		this.items[ this.items.length ] = item;
		
		var root = this.$el.find( 'ul:first' ).get( 0 );
		if ( !root ) {
			root = document.createElement( 'ul' );
			this.$el.append( root );
		}
		
		// hides the info message
		var $intro = this.$el.find( 'div.intro' );

		if ( $intro.css( 'display' ) != 'none' ) {
			$intro.css( 'display', 'none' );
			this.$el.find( 'div.desc' ).css( 'display', '' );
			this.$el.find( 'span.code' ).text( data );
			
			this.$el.find( '#tburl' ).each(function() {
				this.value = this.value + data;
			});
		}
		
		// adds the item
		var $root = $( root );
		
		var $destination  = this._findDestination( item.destination, $root );
		var $section = this._findSection( item.section, $destination );
		var $itemEl  = this._findItem( item, $section );
		
		this.$el.trigger( 'additem', [ item, $itemEl ] );
	},
	/**
	 * Function finds or creates a new destination. The returned
	 * object is a jQuery of the destination.
	 * 
	 * @param string The destination name
	 * @param element $root The root list of the destinations
	 * @return jQuery The destination element
	 */
	_findDestination: function ( name, $root ) {
		$destination = null;
		
		$root.find( 'li.destination' ).each( function ( i, el ) {
			var $el = $( el );
			if ( $el.find( 'h2.name:first a' ).html() == name ) {
				$destination = $el;
				return false;
			}
		} );
		
		if ( ! $destination ) {
			var _this = this;
			$destination = $( document.createElement( 'li' ) );
			$destination.addClass( 'destination' )
						.append( '<h2 class="name"><a href="' + window.location.pathname + '">' + name + '</a></h2>' +
								 '<div><ul class="sections"></ul><a class="removedestination" href="#">' + TripBuilderTranslations[ 'remDest' ] + '</a></div>' );
			$root.append( $destination );
			$destination.find('h2.name').addToAccordion( true );
			$destination.find( 'a.removedestination:first' ).click( function ( e ) { _this.removeDestination( $destination ); return false; } ); 
		}
		return $destination
	},
	/**
	 * Function finds or creates a new section for a destination. The 
	 * returned object is a jQuery element for the section.
	 * 
	 * @param string name The section name
	 * @param element $destination The destination element
	 */
	_findSection: function ( name, $destination ) {
		$section = null;
		
		$destination.find( 'li.section' ).each( function ( i, el ) {
			var $el = $( el );
			if ( $el.find( 'h3.name:first' ).html() == name ) {
				$section = $el;
				return false;
			}
		} );
		
		if ( ! $section ) {
			$section = $( document.createElement( 'li' ) );
			$section.addClass( 'section' )
					.append( '<h3 class="name">' + name + '</h3><ul class="items"></ul>' );
			$destination.find( 'ul.sections' ).append( $section );
		}
		return $section
	},
	/**
	 * Find or create an item for the given section
	 * 
	 */
	_findItem: function ( item, $section ) {
		var elId  = 'id-' + item.id;
		var $item = $section.find( 'li.' + elId );
		
		if ( $item.length < 1 ) {
			var itemhtml = '<h4 class="name">' + item.name + '</h4>';
			if ( item.description ) itemhtml += '<div class="description">' + item.description + '</div>';
			itemhtml += '<p class="contact">' + item.contact + '</p><a href="#" class="remove">' + TripBuilderTranslations[ 'rem' ] + '</a>'
			 
			$item = $( document.createElement( 'li' ) );
			$item.addClass( 'item' )
				 .addClass( elId)
				 .append( itemhtml );

			$section.find( 'ul.items' ).append( $item );
			$item.css( 'backgroundColor', '#ffffcc' ).animate( {backgroundColor: '#ffffff'}, 1000 );
			this.renderer.addEvents( $item );
		}
		return $item;
	},
	/**
	 * Removes a destination
	 * 
	 * @param Node el The parent element
	 */
	removeDestination: function ( el ) {
		
		var toRemove  = {};
		var tripBuilder = this;
		var itemIDs   = new Array();
		if ( confirm( TripBuilderTranslations[ 'confirmRemDest' ] + $( el ).find( 'h2.name a' ).text() + '?' ) ) {
			$( el ).find( 'li.item' ).each( function ( i, item ) {
				var itemID = tripBuilder.renderer.getItemId( $( item ) );
				
				itemIDs[ itemIDs.length ] = itemID;
				toRemove[ 'data[itinerary_item_id][' + i + ']' ] = itemID;
			} );
		} else {
			return;
		}
		
		$.post( '/destinations/rem_user_itinerary', toRemove, function ( data ) {
			if ( typeof data.message != 'undefined' ) {
				alert( data.message ); return;
			}
			$( el ).fadeOut( 'fast', function ( ) { this.parentNode.removeChild( this ) } );
		} );
		
		this.$el.trigger( 'remitem', [ itemIDs ] );
	},
	/**
	 * Remove one item from the tripBuilder
	 * 
	 * @param string itemid The id of the item
	 */
	rem: function ( itemid ) {
		var _this = this;
		$.post('/destinations/rem_user_itinerary', {
			'data[itinerary_item_id]': itemid
		}, function ( data ) { _this._remcallback( data, itemid ) }, 'json');
	},
	/**
	 * Callback called when an item is removed from the
	 * user's listing
	 * 
	 */
	_remcallback: function ( data, itemid ) {
		if ( typeof data.message != 'undefined' ) {
			alert( data.message ); return false;
		}

		var tripBuilder  = this;
		var remove     = function ( ) {
			var p = this.parentNode;
			p.removeChild( this );
			if ( $( p ).find( '> li' ).length == 0 )
				p.parentNode.parentNode.removeChild( p.parentNode );
		}

		// removes all items of id in itemid
		this.$el.find( 'li.item' ).each( function ( i, item ) {
			var $item = $( item );
			if ( tripBuilder.renderer.getItemId( $item ) == itemid ) {
				$item.fadeOut( 'fast', remove );
				return false;
			}
		} );
				
		this.$el.trigger( 'remitem', [ new Array( itemid ) ] );
	}
}

/**
 * TripBuilder renderer
 * 
 */
TripBuilderRenderer = function ( tripBuilder ) {
	this.tripBuilder = tripBuilder;
}
TripBuilderRenderer.prototype = {
	/**
	 * Regular expression for matching the id of an item
	 * 
	 */
	idRegex: new RegExp('id-([a-zA-Z0-9]+)'),
	/**
	 * Parse the tripBuilder widget for items already added
	 * 
	 */
	parse: function ( el ) {
		var $el = $( el );
		var items = [];
		
		var renderer = this;
		var c = this.tripBuilder;
		
		$el.find( '.destination' ).each( function ( e, del ) {
			$( del ).find( 'div:first' ).append( '<a href="#" class="removedestination">' + TripBuilderTranslations[ 'remDest' ] + '</a>' );
			$( del ).find( 'a.removedestination' ).click( function ( e ) { return c.removeDestination( e.target.parentNode.parentNode ) } );
		} );
		
		$el.find( '.item' ).each( function ( i, iel ) {
			var $iel = $( iel );
			
			var idMatch = renderer.idRegex.exec( $iel.attr( 'class' ) );
			if ( idMatch.length > 0 ) {
				var id = idMatch[ 1 ];
				var item = new ItineraryItem( id, null, null, $iel.find( '.name:first' ).text(), $iel.find( '.contact:first' ).html() );
				items[ items.length ] = item;
				renderer.addEvents( $iel );
			}
			
			renderer.parseDescription( $iel.find( '.description' ) );
		} );
		
		this.tripBuilder.bind( 'additem', function ( e, item, $el ) {
			renderer.parseDescription( $el.find( '.description' ) );
		} );
		
		$el.find( '#tripBuilderurl' ).click( function ( ) {
			this.focus();
			this.select();
		} );
		
		return items;
	},
	/**
	 * Adds events to the itinerary item element
	 * 
	 */
	addEvents: function ( $el ) {
		$el.hover( this._itemOver, this._itemOut );

		var c = this.tripBuilder;
		var r = this;
 
		$el.find( 'a.remove' ).click( function ( e ) {
			// clicking removes the item
			var el = e.target.parentNode;
			if ( el.tagName != 'LI' ) el = el.parentNode;
			c.rem( r.getItemId( $( el ) ) );
			return false;
		} );
	},
	_itemOver : function ( e ) { $( this ).addClass( 'over' ); },
	_itemOut  : function ( e ) { $( this ).removeClass( 'over' ); },
	/**
	 * Returns the id of an item element
	 * 
	 */
	getItemId: function ( $el ) {
		var id      = null;
		var idMatch = this.idRegex.exec( $el.attr( 'class' ) );
		if ( idMatch.length > 0 ) {
			id = idMatch[ 1 ];
		}
		return id;
	},
	/**
	 * Parses an item's description
	 * 
	 */
	parseDescription: function ( $el ) {
		$el.wrapInner( '<span class="content"></span>' )
		   .append( ' <a href="#" class="more">' + TripBuilderTranslations.more + '</a> <a href="#" class="less">' + TripBuilderTranslations.less + '</a>' )
		   .click( this.toggleDescription )
		   .trigger( 'click', [ true ] );
	},
	/**
	 * Function added to each .more or .less anchor 
	 * that is part of the description. Added to a .description
	 * node.
	 *
	 * @param Boolean hide True to hide the container
	 */
	toggleDescription: function ( e, hide ) {
		if ( e.target.nodeName.toUpperCase() != 'A' && ! hide )
			return;
		var span = $( this ).find( 'span:first' );
   		if ( ! span )
   			return;
   		if ( typeof span.data( 'content' ) == 'undefined' ) {
   			span.data( 'content', span.html() );
   			var content_short = span.text();
   			if ( content_short.length > 97 ) 
   				content_short = content_short.substr( 0, 97 ) + '...'; 
   			span.data( 'content_short', content_short );
   		}
		if ( hide || e.target.className == 'less' ) {
			span.text( span.data( 'content_short' ) );
			$( this ).addClass( 'short' ).removeClass( 'full' );			
		} else if ( e.target.className == 'more' ) {
			span.html( span.data( 'content' ) );
			$( this ).addClass( 'full' ).removeClass( 'short' );
		}
		e.preventDefault();
		return false;
	}
}

/**
 * Create a new destination parser with the tripBuilder object.
 * 
 */
DestinationParser = function (tripBuilder) {
	this.tripBuilder = tripBuilder;
	
	var _this = this;
	this.tripBuilder.bind( 'additem', function ( e, item ) { _this.onadditem( item ) } );
	this.tripBuilder.bind( 'remitem', function ( e, item ) { _this.onremitem( item ) } );
}

DestinationParser.prototype = {
	/**
	 * The regular expression matching an ID
	 * 
	 */
	idRegex: new RegExp('id-([a-zA-Z0-9]+)'),
	/**
	 * A reference between destination items and
	 * their ids.
	 * 
	 */
	itemRef: {},	
	/**
	 * Parse the content of a destination.
	 *  
	 */
	parse: function (el) {
		var parser = this;
	
		var $d = $(el);
		$d.click(function (e) {
			return parser.onclick(e);
		});
		
		
		var dTitle = $d.find('.title:first').html();
		var sections = $d.find('.sections .section');
		
		var items  = [];
		var itemover = function ( ) { $( this ).addClass( 'hover' ); if ( $( this ).hasClass( 'added' ) ) $( this ).addClass( 'added-hover' ); };
		var itemout  = function ( ) { $( this ).removeClass( 'added-hover' ).removeClass( 'hover' ); }
		
		sections.each(function (i, el) {
			
			var $s = $(el);
			var elTitle = $s.children('.title:first');

			if ( elTitle.size() > 0 ) {
				
				if ( elTitle.attr('href').substr(0, 1) == '#' ) {
					var sectionItems = $(elTitle.attr('href')).find('.item');
				} else {
					var sectionItems = $s.find('.item');
				}
				
				sectionItems.each(function (c, i) {
					// TODO: Move this to the destination part, 1 event for all
					var $i = $(i).hover( itemover, itemout );
					
					var id      = '';
					var idMatch = parser.idRegex.exec($i.attr('class'));
					if (idMatch && idMatch.length > 0) {
						id = idMatch[1];
						
						var item = new ItineraryItem();
						item.id      = id;
						item.destination = dTitle;
						item.section = elTitle.html();
						item.name    = $i.children( '.name' ).text();
						item.description = $i.children('.desc').html(); 
						item.contact = $i.children('.contact').html();
						
						parser.itemRef[id] = $i;
						parser.addControls( $i, item );
					}
				});
				
			}
			
		});
		
		$.each( this.tripBuilder.items, function ( i, item ) {
			parser.onadditem( item );
		} );
		
		this.items = items;
	},
	
	/**
	 * Function adds the controls for adding or removing the item
	 * to/from the tripBuilder
	 * 
	 */
	addControls: function ( itemNode, item ) {
		var tripBuilder = this.tripBuilder;
		
		var $add = $( document.createElement('a') );
		$add.attr('href', '#')
		    .attr('class', 'add')
		    .data('item', item)
		    .text(TripBuilderTranslations['add']);
		
		var $rem = $( document.createElement('a') );
		$rem.attr('href', '#')
			.attr('class', 'rem')
			.data('item', item)
			.text(TripBuilderTranslations['rem']);

		itemNode.append(document.createTextNode(' '))
			    .append($add)
			    .append(document.createTextNode(' '))
			    .append($rem);
	},
	
	/**
	 * Function called when the destination is clicked
	 * 
	 * @return False if the event must not continue
	 */
	onclick: function ( event ) {
		var $t = $( event.target );
		if ( $t.hasClass('add') && $t.data('item') ) {
			this.tripBuilder.add( $t.data('item') );
			return false;
		} else if ( $t.hasClass('rem') && $t.data('item') ) {
			this.tripBuilder.rem( $t.data('item').id );
			return false;
		}
		return true;
	},
	
	/**
	 * Listener to the tripBuilder's additem event
	 * 
	 */
	onadditem: function ( item ) {
		if ( typeof this.itemRef[item.id] != 'undefined' ) {
			this.itemRef[item.id].addClass( 'added' );
		}
	},
	
	/**
	 * Listener to the tripBuilder's remitem event
	 * 
	 * @param Array itemids A list of removed items
	 */
	onremitem: function ( itemIDs ) {
		for ( var i = 0, c = itemIDs.length; i < c; i++ ) {
			var itemID = parseInt( itemIDs[ i ] );
			if ( typeof this.itemRef[ itemID ] != 'undefined' ) {
				this.itemRef[ itemID ].removeClass( 'added' );
			}
		}
	}
}


/**
 * Original script by Jan Jarfalk (http://www.unwrongest.com/about/).
 * 
 * Modified for enRoute by Dimitry Zoltaryov (http://webit.ca)
 * 
 */
$.fn.extend({
	/** Trigger the accordion functionality **/
    activateAccordion: function ( effect, parents ) {
	    this[(parents || 'parent')]('li').toggleClass('active').siblings().removeClass('active').children('div').slideUp('fast');
		this.siblings('div')[(effect || 'slideToggle')]((!effect)?'fast':null);
		return this;
	},
	/** Add the trigger to the list of accordion triggers. Pass TRUE to activate the trigger **/
	addToAccordion: function ( activate ) {
		this.click( function (e) {
			$(e.target).activateAccordion();
			return void(0);
		});
		this.hover(
			function () { $(this).addClass( 'over' ) },
			function () { $(this).removeClass( 'over' ) }
		);
		if (activate) {
			this.siblings('div').data('accordiated', true);
			this.activateAccordion('show', 'parents');
		} else {
			this.siblings('div').data('accordiated', true).hide();
		}
	},
	/** Create the accordion **/
	tripBuilderAccordion: function( options ) {
		var selected = options.select || null;
	 
        return this.each(function() {
        	
        	var active = false;
        	var $this  = $( this );
        	
			if($this.data('accordiated'))
				return false;
			
			$.each($this.find('h2.name'), function(){
				if (this == selected) {
					active = this;
				}
				$(this).addToAccordion();
			});
			
			if (active) {
				$(active).activateAccordion('show', 'parents').parents().show();
			}
			
        });
    } 
}); 

$(document).ready(function () {
	
	var tabEls = $('#sectiontabs');
	if ( tabEls.length > 0 ) {
		// populates a list of tabs for use by the next/previous links
		var tablist = {};
		$('#centralPanel ul.tabs:first a').each(function () {
			tablist[this.href.replace(/^.*#/, '')] = $(this);
		});

		// adds the next/prev controls
		$('div.destination a.prev, div.destination a.next').click(function () {
			tablist[this.href.replace(/^.*#/, '')].click();
			$('html, body').scrollTop(0);
			return false;
		});
		
		var $tabs = $('ul.tabs:first', tabEls).tabs();
	}
	
	var tb     = new TripBuilder('#tb');
	var parser = new DestinationParser(tb);
	parser.parse('div.destination');
	
	var $help = $( 'div.help_message' );
	if ( $help.length ) {
		
		// hide the message trigger
		$help.find( 'a.hide_message' ).click( function ( ) {
			$.get( $( this ).attr( 'href' ), { 'ajax': true } );
			$( this.parentNode.parentNode ).fadeOut( 'fast' );
			return false;
		} );
		
		// flag javascript as okay
		$help.find( 'a.js' ).addClass( 'okay' );
		
		// test for cookies, assuming that at least one cookie exists
		if ( document.cookie.length > 0 ) $help.find( 'a.cookie' ).addClass( 'okay' );
		
	}
	
	// builds the map links
	var $carousel = $( '#mycarousel' );
	var hide      = function () { this.style.visibility = 'hidden' };
	var dotOver   = function ( e, $dot ) { var $a = $dot || $( this ); $a.data( 'span' ).stop().css( { 'margin-top': '-6px', 'visibility': 'visible', 'opacity': 0.6 } ).animate( { marginTop: 0, opacity: 1.0 }, 200 ) };
	var dotOut    = function ( e, $dot ) { var $a = $dot || $( this ); $a.data( 'span' ).stop().animate( { marginTop: 0, opacity: 0.1 }, 200, null, hide ) };
	var thumbOver = function ( e ) { var $this = $( this ); dotOver( null, $this.data( 'dot' ) ); $this.addClass( 'over' ); };
	var thumbOut  = function ( e ) { var $this = $( this ); dotOut( null, $this.data( 'dot' ) ); $this.removeClass( 'over' ); };
	
	if ( $carousel.length > 0 ) {
		
		// create a dot on the map
		var createDot = function ( name, href, position ) {
            var tipOffset = {y: -22, x: -3};

            var $li  = $('<li />');
            var $a   = $('<a />').attr('href', href);
            var $tip = $('<span />').html('<b>' + name + '</b>');

            $li.append($a).append($tip).appendTo('#map');

            $a.css({
                'top': position.y + 'px',
                'left': position.x + 'px'});

            var tippos = {
                y: position.y + tipOffset.y,
                x: position.x + tipOffset.x};

            $tip.css({
                'top' : tippos.y + 'px',
                'left': tippos.x + 'px'});
            
            $a.data('span', $tip)
                .hover(dotOver, dotOut);
			
			return $a;
		}
		
		$carousel.find( 'li' ).each( function( i, li ) {
			var position = {x: -1, y: -1};
			var klass = $( li ).attr( 'class' );
			if ( klass.match(/posx/) ) {
				// looking for class="posx-99999 posy-99999 otherclassname"
				var coord = klass.split( ' ' );
				for ( var i = 0, c = coord.length; i < c; i++ ) {
					var parts = coord[ i ].split( '-' );
					if ( parts[ 0 ] == 'posx' ) {
						position.x = parseInt(parts[ 1 ]);
					} else if ( parts[ 0 ] == 'posy' ) {
						position.y = parseInt(parts[ 1 ]);
					}
				}
			}
			if ( position.x > -1 ) {
				var href = $( li ).find( 'a' ).attr( 'href' );
				var name = $( li ).find( 'a.name' ).text();
				$( li ).data( 'dot', createDot( name, href, position ) ).hover( thumbOver, thumbOut );
			}
		} );
		
		$carousel.jcarousel({ scroll: 3 });
	}
});
