window.DEBUG=true;//(function() {
	eval(liligo.namespace);
	
	
/*
 * Included file begin: /seo/v3/common/js/hotel/core.js
 * Included from:       /seo/v3/common/js/hotel/_main.js:4
 */

var language = language || labels;

/*
 * extended liligo:Observable,
 * an addition _aspect paramater has been added to addEventListener, _fireEvent method
 * with it you can subscribe to an event of a specific source object
 * aim was that the Mediator event dispatcher doesn't have to call all subscribed
 * event handler only that its claimed really (a little bit optimalization)
 */
var myObservable = new Singleton(Observable,{

	_fireEvent: function(_eventName,_source) {
		if (this["_eventMap"] && this["_eventMap"][_eventName]) {
			var eventHandlerCollection = this["_eventMap"][_eventName];
			for (var eventHandlerName in eventHandlerCollection) {
				var eventHandler = eventHandlerCollection[eventHandlerName];
				if (eventHandler.aspect == _source || !eventHandler.aspect){
					eventHandler.observer.apply(eventHandler.context || this, Array.prototype.slice.apply(arguments, [2]));
				};
			};
		}
	}
});

/*
 * Mediator, collect and dispatch object events using Observable push modell
 * it implements 1:n modular object connectivity, instead of n:m harcoded
 * more richly in the literature :)
 *
 * Example:
 * Mediator.dispatchEvent(
 * this, 	//object, _sourceObject of the event - mandatory
 * 		 	//mandatory the _sourceObject.getName() method too,
 * 			//it contains the name of the actual source Object (in this demo)
 * _action  //string, optional, it contains the name of the actual event
 * _params  //mixed but usually an object, optional, contains the params of the actual event
 */
var Mediator = new Singleton(myObservable,{
	dispatchEvent : function(_sourceObject,_action,_params){
		//if ( DEBUG && _sourceObject.getName() == "App.State" ) console.log(_sourceObject.getName()+ ":" + _action);
		this._fireEvent("Mediator:dispatchEvent",_sourceObject.getName(),_sourceObject,_action,_params);
	},
	addEventListener: function(_aspect, _observer,_context) {
		var map = this["_eventMap"] || (this["_eventMap"] = {});
		(map["Mediator:dispatchEvent"] =  map["Mediator:dispatchEvent"] || []).push({
			observer : _observer,
			aspect	 : _aspect,
			context  : _context
		});
	}
});

/*
 * common base methods for modules
 */
var ModuleBase = new Abstract({

	// checking _$XYZ properity to generate auto getter/setter/resetter
	// if they are exist already skip autogeneration
	init : function(){
		var that = this;
		for (var prop in this){
			// just if the prop start with _$
			if (!( /_\$.+/.test(prop) )) continue;
			// convert _$fooBar to FooBar
			(function(){
				var property = prop,
					method	= prop.replace(/_\$(.)(.+)/, function(s,p1,p2){ return p1.toUpperCase() + p2; });
				// set getter/setter/resetters if there are no exist already
				if (!that["set" + method]) {
					that["set" + method] = function(_to){
						that[property] = _to;
					};
				};
				if (!that["get" + method]) {
					that["get" + method] = function(){
						return that[property];
					};
				};
				if (!that["reset" + method]) {
					that["reset" + method] = function(){
						that["set" + method](null)
					};
				}
			})();
		};
	},

	// Mediator uses these to figure out the source of a custom event
	// this is why _name,getName() is must have property in all ModulBase(d) Singleton
	_name	: null,

	getName : function(){
		return this._name;
	}
});
/*
 * Included file end: /seo/v3/common/js/hotel/core.js
 * Included from:     /seo/v3/common/js/hotel/_main.js:4
 */

	
	var i0, i1, i2;
	window.templates = {
		resultitem				: new liligo.VTemplate("/seo/v3/common/templates/hotel/resultitem.vm", function (context) { 
var text = new liligo.__VT_StringCat(), _function = 'function', 
velocityCount = 0;
if (context.velocityCount) velocityCount=context.velocityCount;

text.push('<div id="resultitem-');
text.push( context.acc.id);
text.push('" class="item">	<div class="sideinfo">		<div class="stars"><div class="star-');
text.push( context.acc.acc_stars);
text.push('"></div></div>		');
if (context.acc.acc_star_url && context.acc.acc_stars != 0) {
text.push('			<div class="stars-link">				<a href="');
text.push( context.acc.acc_star_url);
text.push('" title="');
text.push( context.labels.hotel_name_prefix_lowercase);
text.push(' ');
text.push( context.acc.acc_city);
text.push(' ');
text.push( context.acc.acc_stars);
text.push('">');
text.push( context.acc.acc_stars);
text.push(' ');
if (context.acc.acc_stars > 1) {
text.push(' ');
text.push( context.labels.SEOV2_Hotel_Directory_Stars_Title);
}
else {
text.push(' ');
text.push( context.labels.SEOV2_Hotel_Directory_Star_Title);
}
text.push('</a>			</div>		');
}
text.push('		<div class="button-small" onclick="hotelWidget.show(');
text.push( context.acc.id);
text.push(', this)">');
text.push( context.labels.SEOV2_Hotel_Directory_City_HotelList_VerifyButton);
text.push('</div>	</div>	<div class="result-content">		<div class="result-header">			<h2><a href="');
text.push( context.acc.acc_url);
text.push('" title="');
text.push( context.acc.acc_name);
text.push(' - ');
text.push( context.labels.hotel_name_prefix_lowercase);
text.push(' ');
text.push( context.acc.acc_city);
text.push('" >');
text.push( context.acc.acc_name);
text.push('</a></h2>			<strong>');
text.push( context.acc.acc_address);
text.push('</strong> ');
if (context.acc.acc_distance != context.labels.not_defined) {
text.push('(');
text.push( context.labels.SEOV2_Hotel_Directory_CenterPoint);
text.push(' <strong>');
text.push( context.acc.acc_distance);
text.push(' km</strong>) ');
}
text.push('		</div>		<div class="description">			<p id="imgwrapper-');
text.push( context.acc.id);
text.push('"><img id="img-');
text.push( context.acc.id);
text.push('" onerror="javascript:this.src=\'/hotel_v3/img/hotel-default.png\'" src="');
if (context.acc.acc_picture) {
text.push('/servlet/im?url=');
text.push( context.acc.acc_picture);
text.push('&width=57');
}
text.push('" width="57" alt="');
text.push( context.labels.hotel_name_prefix);
text.push(' ');
text.push( context.acc.acc_name);
text.push('"/>');
text.push( context.acc.acc_remark);
text.push('</p>			<p class="links"><a title="');
text.push( context.labels.hotel_name_prefix_seo_country);
text.push(' ');
text.push( context.acc.acc_country);
text.push('" href="');
text.push( context.labels.hotelCountryDirectory_page_url);
text.push( context.labels.hotel_name_prefix_url);
text.push( context.acc.acc_country_url);
text.push('/">');
text.push( context.acc.acc_country);
text.push('</a> > <a title="');
text.push( context.labels.hotel_name_prefix_seo_city);
text.push(' ');
text.push( context.acc.acc_city);
text.push('" href="');
text.push( context.labels.hotelCountryDirectory_page_url);
text.push( context.labels.hotel_name_prefix_url);
text.push( context.acc.acc_city_url);
text.push('_');
text.push( context.acc.acc_country_code);
text.push('/">');
text.push( context.acc.acc_city);
text.push('</a></p>			<div class="amenities">		');
for (var i1 in context.acc.acc_amenities) {
var acc_amenity = context.acc.acc_amenities[i1];
if (typeof acc_amenity == _function) continue;
velocityCount = i1;
text.push('			<img src="/hotel_v3/img/amenities/amenity-');
text.push( acc_amenity.amenity_code);
text.push('.gif" alt="');
text.push( acc_amenity.amenity_name);
text.push('" title="');
text.push( acc_amenity.amenity_name);
text.push('" />		');
}
velocityCount = 0;
text.push('			</div>		</div>	</div>	<div class="result-footer">		<span></span>	</div></div>');
return text.toString();
}
),
		resultitem_photo		: new liligo.VTemplate("/seo/v3/common/templates/hotel/resultphoto.vm", function (context) { 
var text = new liligo.__VT_StringCat(), _function = 'function', 
velocityCount = 0;
if (context.velocityCount) velocityCount=context.velocityCount;

if (!( context.img.zoom ) || !( context.modules.Photo )) {
text.push('	<img class="photo" style="');
text.push( context.style);
text.push('" id="img-');
text.push( context.img.id);
text.push('" src="');
text.push( context.img.src);
text.push('" width="');
text.push( context.img.pictureWidth);
text.push('" height="');
text.push( context.img.pictureHeight);
text.push('" />');
}
else {
text.push('	<a onclick="Photo.show(');
text.push( context.img.id);
text.push(');return false;" href="');
text.push('#" title="');
text.push( context.l.result_resultitem_image_open);
text.push('">		<img class="zoom" src="');
text.push( context.baseUrl);
text.push('/img/loupe.png" alt="" />		<img class="photo" style="');
text.push( context.style);
text.push('" id="img-');
text.push( context.img.id);
text.push('" src="');
text.push( context.img.src);
text.push('" width="');
text.push( context.img.pictureWidth);
text.push('" height="');
text.push( context.img.pictureHeight);
text.push('" title="');
text.push( context.l.result_resultitem_image_open);
text.push('" alt="');
text.push( context.l.result_resultitem_image_open);
text.push('" />	</a>');
}
return text.toString();
}
),
		resultpager				: new liligo.VTemplate("/seo/v3/common/templates/hotel/resultpager.vm", function (context) { 
var text = new liligo.__VT_StringCat(), _function = 'function', 
velocityCount = 0;
if (context.velocityCount) velocityCount=context.velocityCount;

text.push('<div class="prevnext previous" ');
if (context.isfirst) {
text.push(' style="visibility: hidden;" ');
}
text.push(' >	<a href="javascript:void(0)" onclick="Layout.ResultDisplay.setPage(Layout.ResultDisplay.getPage()-1); scrollTo(0,0); return(false);">		<span class="icon">&laquo;&nbsp;</span>		<span>');
text.push( context.l.result_footer_previous);
text.push('</span>	</a></div><ul class="pages" ');
if (context.isfirst && context.islast) {
text.push(' style="visibility: hidden;" ');
}
text.push(' >');
for (var i1 in context.pages) {
var page = context.pages[i1];
if (typeof page == _function) continue;
velocityCount = i1;
text.push('	');
if (!( page.hidden )) {
text.push('		');
var liClass = "default";
text.push('		');
if (page.actual) {
liClass = "actual";
text.push('		');
}
text.push('		');
if (page.last) {
liClass = "last";
text.push('		');
}
text.push('		');
if (page.inSpektrum) {
liClass = ( liClass + "  inspektrum" );
text.push(' ');
text.push('		');
}
text.push('		');
if (page.actual) {
liClass = ( liClass + "  actual" );
text.push(' ');
text.push('		');
}
text.push('		');
text.push('		');
if (page.spekStart) {
text.push('			<li class="filler"><span>...</span></li>		');
}
text.push('		<li class="');
text.push( liClass);
text.push('">			<a href="javascript:void(0)" onclick="Layout.ResultDisplay.setPage(');
text.push( page.page);
text.push('); return(false);">				<span>');
text.push( page.page);
text.push('</span>			</a>		</li>		');
if (page.spekEnd) {
text.push('			<li class="filler"><span>...</span></li>		');
}
text.push('	');
}
text.push(' ');
}
velocityCount = 0;
text.push('</ul><div class="prevnext next" ');
if (context.islast) {
text.push(' style="visibility: hidden;" ');
}
text.push(' >	<a href="javascript:void(0)" onclick="Layout.ResultDisplay.setPage(Layout.ResultDisplay.getPage()+1); scrollTo(0,0); return(false);">		<span>');
text.push( context.l.result_footer_next);
text.push('</span>		<span class="icon">&raquo;&nbsp;</span>	</a></div>');
return text.toString();
}
)
	};

	
/*
 * Included file begin: /seo/v3/common/js/hotel/Layout.js
 * Included from:       /seo/v3/common/js/hotel/_main.js:13
 */

/**
 * Layout
 * package for the presentation related things
 * and the ResultDisplay Singleton which displays
 * the template of the result items
 */

var Layout = (function(){

	return {

		/**
		 * Set style.display = "" of an element, list of elements, or more than one element
		 * @param string || strings || array
		 */
		show : function(){
			Style.show.apply(Style, typeof arguments[0] == "array" ? arguments[0] : arguments);
		},

		/**
		 * Set style.display = "none" of an element, list of elements, or more than one element
		 * @param string || strings || array
		 */
		hide : function(){
			Style.hide.apply(Style, typeof arguments[0] == "array" ? arguments[0] : arguments);
		},

		/**
		 * Set the innerHTML property of an element
		 * @param HTMLElement
		 * @param string
		 */
		setText : function(_element,_htmlString){
			var element = typeof _element == "string" ? $(_element) : _element;
			if (!element) return;
			element.innerHTML = _htmlString;
		},

		/**
		 * Get the value of input element
		 * @param {String} _element
		 */
		getValue : function(_element){
			var value;
			try{ value = $(_element).value; }catch(e){};
			return value
		},

		/**
		 * Set the value of input element
		 * @param {String} _element
		 * @param {String} _to
		 */
		setValue : function(_element,_to){
			try{ $(_element).value = _to; }catch(e){};
		},

		/**
		 * Add a class to an element
		 * @param {String}
		 */
		addClass : function(){
			Style.addClass.apply(this,arguments);
		},

		/**
		 * Set the class of an element
		 * @param {Object} _element
		 * @param {Object} _to
		 */
		setClass : function(_element,_to){
			var element = typeof _element == "string" ? $(_element) : _element;
			if (!element) return;
			element.className = _to;
		},

		/**
		 * Remove a class from the target element
		 * @param {String}
		 */
		removeClass : function(){
			Style.removeClass.apply(this,arguments);
		},

		/**
		 * Pipe to the functions above
		 * @param {Object} _actions
		 */
		pipe: function(_actions){
			for (var i in _actions) {
				forEach(_actions[i],function(el){
					if ((el.indexOf("|")>0) && (el = el.split("|"))) Layout[i](el[0], el[1]);
						else Layout[i](el);
				});
			}
		},

		/**
		 * ResultDisplay
		 * displaying result items using different environment variables
		 */
		ResultDisplay : (function(){

			/**
			 * ResultImgLoader
			 * preload result item images
			 */
			var _ResultImgLoader = {
				_resultElems	: [],
				_images 		: {},
				_imgHolder		: 'hotel-photo',

				/**
				 * Collect result items ids from ids of the result item DOM nodes
				 * @param array
				 */
				getImgs : function(_items){
					var that = this, idsArray =[];
					forEach(_items,function(item){						
						var id = item.id.replace("resultitem-","");						
						idsArray.push(item.id.replace("resultitem-",""));
						Style.set($("img-" + id),{visibility:"hidden"});
					});					
					setTimeout(function(){that._getImgsDo(idsArray);},0);
				},

				_getImgsDo : function(_idsArray){
					forEach(_idsArray,function(_id){
						if (!this._images[_id]){						
							var tempImg = new Image();							
							var imgSrc = $("img-" + _id).src;													
							tempImg.src = imgSrc ?
												imgSrc + (imgSrc.indexOf("?") != -1 ? '&' : '?') + 'rand='+Math.random() :
												Layout.ResultDisplay._defaultResultPicture;
												
							tempImg.onload = bind(function(){
								if ($("imgwrapper-" + _id)){
									Style.set($("img-" + _id),{visibility:"visible"});
									this._images[_id] = $("imgwrapper-" + _id).innerHTML;
								}
							},this);
											
							tempImg.onerror = tempImg.onabort = bind(function(){
								if ($("imgwrapper-" + _id)){								
									$("img-" + _id).src = "/hotel_v3/img/hotel-default.png"
									$("img-" + _id).width = "55";
									$("img-" + _id).height = "55";
									Style.set($("img-" + _id),{visibility:"visible"});
									this._images[_id] = $("imgwrapper-" + _id).innerHTML;
								}			
							},this);
						}else{
							 $("imgwrapper-" + _id).innerHTML = this._images[_id];
						}						
					},this);
				}
			};

			/**
			 * ResultDisplay
			 * displaying result items using different environment variables
			 */
			return Singleton(ModuleBase,{

				_name					: "Layout.ResultDisplay",
				_defaultResultPicture	: config.baseUrl+"/img/hotel-default.png",
				_maxSpektrum			: 7,				//the number of boxes in the absolute middle of the pager
				_noSpektTrigger 		: 5,				//bellow this number of pages zones will not be created
				_resultSetId			: "resultset", 		// wrapper of the displayed results
				_resultpagerId			: "resultpager",	// wrapper of the pager
				_$page					: 1,				//vars with autogeneretad setters/getters, (must)begin with _$
				_$itemPerPage			: window.itemPerPage || 10,

				/**
				 * Set the actual result page number
				 * @param {Object} _page
				 * @param {Object} _dontRefresh
				 */
				setPage : function(_page,_dontRefresh){
					var that = this;
					Mediator.dispatchEvent(this,"before_setPage",_page);
					that._$page = _page;
					if(!_dontRefresh ){
						setTimeout(function(){							
							that.updateResultItems();
						},0);	
					}					
					Mediator.dispatchEvent(that,"after_setPage",_page);
				},

				/**
				 * Update the content of the result wrapper
				 */
				updateResultItems : function(){
					Mediator.dispatchEvent(this,"before_updateResultItems");

					var that			= this;
						page			= that.getPage(),
						itemPerPage 	= that.getItemPerPage(),
						htmlTemplates	= [];

					// fetch the resultContainers
					forEach(Results.ActiveGroups.getGroupContainerFrom((page-1)*itemPerPage,itemPerPage),function(_groupContainer,_index){
						var groupContainer = _groupContainer;
						// if result item template has been cached
						if (groupContainer.getTemplate()) {
							htmlTemplates.push(groupContainer.getTemplate());
							Mediator.dispatchEvent(that,"processGroupContainer",{
								groupContainer : groupContainer,
								index : _index
							});
							return;
						};
						
						htmlTemplates.push(groupContainer.setTemplate(
							templates.resultitem.process({
								acc: groupContainer.getActiveGroups()[0],
								id : _groupContainer.id,
								level : level,
								lang : language
							})
						));

						Mediator.dispatchEvent(that,"processGroupContainer",{
							groupContainer : groupContainer,
							index : _index
						});
					});

					// aggregate template arrays into one string
					var html = htmlTemplates.join('');
					if (that.html != html){
						Layout.setText(that._resultSetId,html);
						that.html = html;
					};
								
					that.rebuildPager();

					Mediator.dispatchEvent(that,"after_updateResultItems");
				},

				/**
				 * Regenerate the pager
				 */
				rebuildPager: function(){
					Mediator.dispatchEvent(this,"before_rebuildPager")

					var maxSpektrum 	= this._maxSpektrum;
						noSpektTrigger	= this._noSpektTrigger;

					var pagenum 	= Math.ceil( Results.ActiveGroups.getLength() / this.getItemPerPage() ),
						page  		= this.getPage(),
						pages 		= [],
						start 		= 1,
						end 		= pagenum,
						starting 	= false,
						ending 		= false,
						spektDiv 	= (maxSpektrum % 2 == 1) ? (maxSpektrum - 1) / 2 : maxSpektrum / 2,
						spekTemp, i;

					//decide whether we're in starting/ending mode
					if (page < maxSpektrum) starting = true;
					if (page > end+1 - maxSpektrum) ending = true;

					for(var idx=start; idx<=end; idx++) {
						var tempPageObj = {
								page		: idx,
								first		: idx == 1,
								actual		: idx == page,
								last		: idx == end,
								hidden		: false,
								inSpektrum	: false,
								spekStart	: false,
								spekEnd		: false
							}, spekTemp		= false;

						//the active item is in the starting/ending zone
						if (starting || ending) {
							if ( ((starting)  && (idx <= maxSpektrum)         && (page != maxSpektrum)) ||
								 ((ending)    && (idx >= end+1 - maxSpektrum) && (page != end+1 - maxSpektrum)) ) {
								spekTemp = true;
							}
						} else { //the active item is NOT in the starting/ending area, mark surroundings
							if ((idx >= page - spektDiv) && (idx <= page + spektDiv))
								spekTemp = true;
						}
						tempPageObj["inSpektrum"] = spekTemp;
						pages.push(tempPageObj);
					};

					//mark zone edges, hide unused items
					if (pagenum > noSpektTrigger) {
						spekTemp = false;
						for (i = 0; i < pages.length; i++) {

							if (pages[i].inSpektrum == true) {
								if ((i > 0) && (spekTemp == false)) pages[i].spekStart = true;
								if ((i < pages.length - 1) && (pages[i+1].inSpektrum == false)) pages[i].spekEnd = true;
							}

							if ((i > 0) && (i < pages.length - 1) && (!pages[i].inSpektrum))
								pages[i].hidden = true;

							spekTemp = pages[i].inSpektrum;
						}
					};

					var rpPass = {
						isfirst: (page == 1),
						islast: (page == pagenum),
						itemsperpage: this.itemsperpage,
						pages: pages,
						visibleitems: Results.ActiveGroups.getLength(),
						allitems: Results.getLength(),
						pageRendered: true,
						l: language
					};
					Layout.setText(this._resultpagerId, templates.resultpager.process(rpPass));

					//align center to comply with design
					var pageList = liligo.Query.selectNode("#" + this._resultpagerId +" ul.pages");
					pageList.style.marginLeft = Math.round((592/2 - pageList.clientWidth/2 - 150)) + "px";

				}// ResultDisplay.updateResultItems
			}) // Singleton
		})() // ResultDisplay
	}//Layout
})();
/*
 * Included file end: /seo/v3/common/js/hotel/Layout.js
 * Included from:     /seo/v3/common/js/hotel/_main.js:13
 */

	
/*
 * Included file begin: /seo/v3/common/js/hotel/Results.js
 * Included from:       /seo/v3/common/js/hotel/_main.js:14
 */

/**
 * Results
 * Container for results related things
 */
var Results = (function(){

	/**
	 * GroupContainer
	 *
	 * I'd like using this class in hotel engine too
	 * it can store the common group properities like
	 * status of preloader imgs, templates etc.
	 * when the engine needs to handle multiple groups
	 */
	var _GroupContainer =  Class(ModuleBase,{

		_name : "_GroupContainer",

		//vars with autogeneretad accessor/mutators, (must)begin with _$
		// HTML template of the container see the setTemplate method for more
		_$template 			: "",
		_$imgSmallLoaded	: false,
		_$imgLargeLoaded	: false,
		_$image				: "",
		_firstActiveGroup	: null,

		/**
		 * Create a container with id and the img source of a group
		 * @param {String} _id
		 * @param {String} _image
		 */
		constructor : function(_id,_image){
			this.init();
			this.id = _id;
			this.setImage(_image);
			this.groups = [];
		},

		/**
		 * Add a group to the container
		 * @param {Object} _group
		 */
		addGroup : function(_group){
			this.groups.push(_group);
		},

		getFirstActiveGroup : function(){
			return this._firstActiveGroup;
		},

		setFirstActiveGroup : function(_group){
			return this._firstActiveGroup = _group;
		},

		/**
		 * Return all active groups, no matter in this engine
		 * @return {Object}
		 */
		getActiveGroups : function(){
			var activeGroups = [];
			for (var i=0;i<this.groups.length;i++){
				if(this.groups[i].isActive) activeGroups.push(this.groups[i]);
			};
			return activeGroups;
		},

		/**
		 * Return all groups from the container
		 * @return {Array}
		 */
		getGroups : function(){
			return this.groups;
		},

		/**
		 * Return a group from the container
		 * @param {Number} _GroupID
		 */
		getGroupById : function(_GroupID){
			for (var i=0;i<this.groups.length;i++){
				if(this.groups[i].GroupID == _GroupID) {
					var group = this.groups[i];
					break;
				};
			};
			return group;
		},

		/**
		 * Set all group to active in the actual contanier
		 */
		setGroups2Active : function(){
			forEach(this.groups,function(_group){
				_group.isActive = true;
			});
		},

		/**
		 * Set the HTML template of the given groupContainer
		 * @param {Object} _template
		 */
		setTemplate : function(_template){
			this._$template = _template;
			return _template;
		}
	});

	/**
	 * Truncate a text to the give length using the given closing string
	 * @param {Object} text
	 * @param {Number} length
	 * @param {String} truncation
	 */
	function _truncate(_text,_length,_truncation) {
	    _length = _length || 30;
	    _truncation = _truncation === undefined ? '...' : _truncation;
	    return _text.length > length ? _text.slice(0, _length - _truncation.length) + _truncation : _text;
	};

	/**
	 * Results
	 *
	 * Stores the result items and ensures all kinds of
	 * getter/setter methods to them
	 *
	 */
	return Singleton(ModuleBase,{

		_name : "Results",

		init : function(){
			this._groupsStorage = {};
			this._groupsNumber = 0;

			this._base_init();
		},

		/**
		 * Adds a new result item and fills its generated properities
		 * @param {Object} _group
		 */
		addItem : function(_group){
			var group = _group, that = this;
			group.isActive = true;

			//location
			group.longAddress	= group.acc_address;
			group.Address		= group.acc_address.replace && group.acc_address.replace(/<\/?[^>]+>/gi, '');

			//name
			group.longHotelName		= group.acc_name;
			group.shortHotelName	= group.acc_name.length > 37 ? _truncate(group.acc_name,37) : group.acc_name;
			group.HotelName			= group.acc_name.length > 47 ? _truncate(group.acc_name,47) : group.acc_name;
			//stripTags
			group.HotelName	= group.HotelName.replace && group.HotelName.replace(/<\/?[^>]+>/gi, '');

			//description>stripTags
			group.Description = group.acc_remark.replace && group.acc_remark.replace(/<\/?[^>]+>/gi, '');

			//star
			group.starRatingRounds = Math.floor(group.acc_stars);
			if (group.starRatingRounds < 1) group.starRatingRounds = 0;

				that._groupsStorage[that._groupsNumber] = new _GroupContainer(that._groupsNumber, group.PictureLink);
				var groupContainer = that._groupsStorage[that._groupsNumber];
				that._groupsNumber++;

				//group = cloneObject(group);
				groupContainer.addGroup(group);
				// generate filter parts and sets prefiltering
				Mediator.dispatchEvent(that,"after_addItem",group);
				// if not, it is added to ActiveGroups
				if (group.isActive) that.ActiveGroups.add(groupContainer);
		},

		/**
		 * Return the number of the stored groups
		 */
		getLength : function(){
			return this._groupsNumber;
        },

		/**
		 * Return the number of the active groups before begin to filtering
		 */
		getActiveGroupsLength : function(){
			return this._activeGroupsNumber;
        },

		/**
		 * Return the all groupContainer array
		 */
		getGroupStorage : function(){
			return this._groupsStorage;
		},

		/**
		 * Return a groupcontainer by its id
		 * @param {Number} _id
		 * @return {Object}
		 */
		getGroupContainerById : function(_id){
			return this._groupsStorage[_id];
		},

		/**
		 * Return a group from the a container
		 * @param {Number} _HotelId
		 * @param {Number} _GroupID
		 */
		getGroupById : function(_HotelId,_GroupID){
			return this.getGroupContainerById(_HotelId).getGroupById(_GroupID);
		},

		/**
		 * Call the same func on all groupContainer, on the actual or the given tab
		 * @param {Function} _func
		 * @param {Object} _context
		 */
		eachGroupContainer : function(_func,_context){
			var counter = 0, context = _context || Results;
			for (var groupContainerId in this._groupsStorage){
				_func.apply(context,[this._groupsStorage[groupContainerId],counter++]);
			};
		},

		/**
		 * Delete the group templates, after currency has been changed example
		 * so we need recreate them, more in Layout.ResultDisplay.updateResultItems
		 */
		resetAllGroupTemplate : function(){
			this.eachGroupContainer(function(_groupContainer){
				_groupContainer.resetTemplate();
			},null);
		},

		/**
		 * ActiveGroups
		 *
		 * manage the active set of the active groups
		 * so those groupContainers which contains at least one active group item
		 */
		ActiveGroups :  Singleton(ModuleBase,{
			_name                   : "Results.ActiveGroups",
			_activeGroups 			: [],
			_activeGroupsIndex 		: {},
			_sortDir				: "+",
			_sortBy					: "price",
			_sortingDic				: {},

			init : function(){
				var that = this;

				// connects ids of sorting elements, check $("by_title").id example, to group properities
				that._sortingDic = {
					"desc" 		: "HotelName",
					"category"	: "StarRating"
				};

				that._sortBy    = "price"
				that._sortDir   = "+"; //"-";
			},

			/**
			 * Add and active groupContainer too the ActiveGroups
			 * @param {Object} _groupContainer
			 */
			add : function(_groupContainer){
				if (typeof this._activeGroupsIndex[_groupContainer.id] == "undefined"){
					this._activeGroups.push(_groupContainer);
					this._activeGroupsIndex[_groupContainer.id] = this._activeGroups.length-1;
				};
				var cheapestGroupIndex = false;
				forEach(_groupContainer.getGroups(),function(_group,index){
					if (_group.isActive)
						cheapestGroupIndex = cheapestGroupIndex === false ? index : cheapestGroupIndex;
				});
				_groupContainer.setFirstActiveGroup(_groupContainer.getGroups()[cheapestGroupIndex]);
			},

			/**
			 * Iterates through the array of ActiveGroups, calling the param function
			 * and conveys the actual groupContainer and a counter to it
			 * @param {Object} _func
			 * @param {Object} _context
			 */
			eachActiveGroupContainer : function(_func,_context){
				for (var i=0;i<this._activeGroups.length;i++){
					_func.apply(_context || Results.ActiveGroups,[this._activeGroups[i],i]);
				};
			},

			/**
			 * Return the number of the element of the ActiveGroups
			 */
			getLength : function(){ return this._activeGroups.length; },

			/**
			 * Add elements to the set of the ActiveGroups
			 * @param {Array} _groupContainers
			 */
			setActiveGroups : function(_groupContainers){
				this.reset();
				forEach(_groupContainers,function(_groupContainer){
					this.add(_groupContainer);
				},this);
			},

			/**
			 * Return the nth ActiveGroup Container
			 * @param {number} _idx
			 * @return {Object}
			 */
			getGroupContainer : function(_idx){
				return this._activeGroups[_idx];
			},

			getGroupContainerById : function(_idx){
				var groupContainer;
				this.eachActiveGroupContainer(function(_groupContainer,_i){
					if(_groupContainer.id == _idx){
						groupContainer = {
							container   : _groupContainer,
							index       : _i
						};
					};
				});
				return groupContainer;
			},

			/**
			 * Return x from y groupcontainer from the ActiveGroups array
			 * @param {Number} _idx
			 * @param {Number} _num
			 * @return {Array}
			 */
			getGroupContainerFrom : function(_idx,_num){
				var groupContainers = [];
				for(var i=_idx;i<_idx+_num;i++) {
					this.getGroupContainer(i) && groupContainers.push(this.getGroupContainer(i));
				};
				return groupContainers;
			},

			/**
			 * Remove all ActiveGroup elements, except the first _number
			 * @param {Number} _number
			 */
			keepOnly : function(_number){
				var groupContainers = [];
				this._activeGroupsIndex = {};
				this._activeGroups = this.getGroupContainerFrom(0,_number);
			},

			/**
			 * As you see, reseting all
			 */
			reset : function(_groupId){
				this._activeGroups = [];
				this._activeGroupsIndex = {};
			},

			/**
			 * Sorting ActiveGroup elements depending on the clicked sort elment
			 * using sorting dictionary which u can find in the init method
			 */
			// + growing / - decreasing
			sort : function(){
				var that = this;
				function sortCompare(a,b){						
						var groupA = a.getFirstActiveGroup(),
							groupB = b.getFirstActiveGroup();
						
						if (typeof groupA[that._sortingDic[that._sortBy]] == "string"){
							a = groupA[that._sortingDic[that._sortBy]].toLowerCase();
							b = groupB[that._sortingDic[that._sortBy]].toLowerCase();
						}else{
							a = groupA[that._sortingDic[that._sortBy]];
							b = groupB[that._sortingDic[that._sortBy]];
						};
						return a < b ? -1 : a != b ? 1 : (groupA.HotelName.toLowerCase() < groupB.HotelName.toLowerCase()) ? -1 : 1;
				};
				this._activeGroups.sort(function(a,b){ return that._sortDir == "+" ? sortCompare(a,b) : sortCompare(b,a); });
			},

			// set sorting method
			sortBy: function(_event){
				var target		= Event.element(_event);
					oldTarget	= $("by_" + this._sortBy);

				this._sortBy = target.id.split("_")[1];
				this._sortDir = (target == oldTarget && this._sortDir == "+") ? "-" : "+";
				this.sort();

				Layout.ResultDisplay.setPage(1);

				Mediator.dispatchEvent(this,"after_sortBy",target.id);
			}

		})
	});

})();
/*
 * Included file end: /seo/v3/common/js/hotel/Results.js
 * Included from:     /seo/v3/common/js/hotel/_main.js:14
 */

	
/*
 * Included file begin: /seo/v3/common/js/hotel/Filters.js
 * Included from:       /seo/v3/common/js/hotel/_main.js:15
 */
/**
 * Filters
 *
 * Composite Pattern has been used here (Pro JavaScript Design Patterns: Chapter 9
 * u can find the pattern above in the following book: \lilidev\BOOKS\javascript\Pro.Javascript.Design.Patterns.Apress.2007.pdf)
 * FilterContainer is the composite, and the instances of the Filters classes are the leaves
 * filters actually have three types: checkbox, slider2, and text
 */
var Filters = (function(){

	/**
	 * liligo/Abstract class has been used to check/keep the
	 * interface consistency between the items of Composite Pattern
	 */
	var FilterBase = Abstract(ModuleBase,{
		_name			: "",
		getValue		: null,
		getTemplate		: null,
		setTemplate		: null,
		fillFilterList	: null,
		sortFilterList	: null,
		isFiltered		: null
	});

	/**
	 * FilterContainer
	 *
	 * this is the composite item of the pattern, it must have same interface
	 * as the leaves (filter instances), please read the book above, I dont want to type too much :))
	 * its a long story... anyway if u check deeply the methods of the Filter Singleton at the end of this file
	 * u can find the reason (I hope)
	 */
	var FilterContainer = Singleton(FilterBase,{

		_name			: "FilterContainer",
		// it keeps the the filter instances so u can iterate between them using this.eachFilter method
		_filters		: {},
		// filter values
		_values			: {},
		// it store the HTML template of whole filter block
		_template		: "",

		/**
		 * Add filter instances to the container, u have to call it once per session
		 * @param array
		 */
		addFilter : function(_filters){
			for(var i=0;i<_filters.length;i++){
				var filter = _filters[i];
				// else put it into the container
				this._filters[filter.getName()] = {
					filter	: filter
				};
			};
		},

		/**
		 * Iterating through the filters, and call the passed funcs each of them
		 * context is the actual filter instance
		 * @param function
		 */
		eachFilter : function(_func){
			_func.apply(this._filters["stars"].filter);
		},

		/**
		 * Only used for debugging purpose, it contains the actual values of all filters
		 * @return object
		 */
		getValue : function(){
			var that = this;
			that._values = {};
			that.eachFilter(function(){
				that._values[this.getName()] = this.getValue();
			});
			return that._values;
		},

		/**
		 * If a result group has been filtered out it gives back true
		 * begin with the last clicked filter unit
		 * @param object
		 * @return boolean
		 */
		isFiltered : function(_group){
			var that = this, isFiltered = false;
			that.eachFilter(function(){
				isFiltered = isFiltered || this.isFiltered(_group);
			});
			return isFiltered;
		},

		/**
		 * Gives back the aggregated filter templates
		 * @return string
		 */
		getTemplate : function(){
			var that = this;
			that._template = [];
			that.eachFilter(function(){
				that._template.push(this.getTemplate());
			});
			that._template = that._template.join("");
			return that._template;
		},

		/**
		 * Set the templates of the filter instances
		 * @return string
		 */
		setTemplate : function(){
			var that = this;
			that.eachFilter(function(){
				this.setTemplate();
			});
		},

		/**
		 * Generate filter list elemes, calling all filter unit instance
		 * @param object
		 */
		fillFilterList : function(_group){
			var that = this;
			that.eachFilter(function(){
				this.fillFilterList(_group);
			});
		},

		/**
		 * Sorting filter list elems, default is alphabet
		 */
		sortFilterList : function(){
			var that = this;
			that.eachFilter(function(){
				this.sortFilterList();
			});
		}
	});

	if ( DEBUG ) { window.FilterContainer = FilterContainer; }

	/**
	 * FilterRadio
	 * checkbox based filter unit class, it uses FilterBase abstract class
	 * to keep interface consistency
	 */
	var FilterRadio = Class(FilterBase,{

		_name		: "FilterRadio",
		_vTemplate	:  new liligo.VTemplate("/seo/v3/common/templates/hotel/resultfilter.vm", function (context) { 
var text = new liligo.__VT_StringCat(), _function = 'function', 
velocityCount = 0;
if (context.velocityCount) velocityCount=context.velocityCount;

text.push('	<span>');
text.push( context.l.SEOV2_Hotel_Directory_Stars_CheckHotelText);
text.push('</span>	<a href="javascript:void(0)" onclick="');
text.push('$(\'filter-stars\').value = \'\'; Filters.updateFilter(\'all\'); Filters.startFiltering(event);" id="filter-stars-all" "');
if (!( context.rate )) {
text.push(' class="active" ');
}
text.push('>');
text.push( context.l.seo_filter_all);
text.push('</a>');
for (var i1 in context.filterList) {
var filter = context.filterList[i1];
if (typeof filter == _function) continue;
velocityCount = i1;
text.push('	| <a href="javascript:void(0)" onclick="');
text.push('$(\'filter-stars\').value = ');
text.push( filter.code);
text.push('; Filters.updateFilter(');
text.push( filter.code);
text.push('); Filters.startFiltering(event);" id="filter-stars-');
text.push( filter.code);
text.push('" ');
if (context.rate == filter.code) {
text.push(' class="active" ');
}
text.push(' title="');
text.push( filter.value);
text.push('">');
text.push( filter.value);
text.push('</a>');
}
velocityCount = 0;
text.push('	<input type="hidden" id="filter-stars" value="');
if (context.rate) {
text.push( context.rate);
}
text.push('" />');
return text.toString();
}
),
		// HTML template container
		_template	: "",
		// number of the filter items
		_counter	: 0,

		/**
		 * @param string
		 * @param object
		 */
		constructor : function(_name,_params){
			var that 		= this;
			that._name 		= _name;
			that._options = {
					// give back a filter list item, code:id, value:label
					getFilterListItem	: _params.getFilterListItem,
					// give back false if a group is a filterd one
					isFiltered			: _params.isFiltered || null,
					// sort filter list items, default is alphabet
					sortFilterList		: _params.sortFilterList || null
			};
			that._filterList = [];
			that._filterListIndx = {};
		},

		/**
		 * Return the HTML template of a filter instance
		 * @return string
		 */
		getTemplate : function(){
			return this._template;
		},

		/**
		 * Parse the template of a filter instance
		 */
		setTemplate : function(){
			var that = this;
			that._template = that._vTemplate.process({
				name		: that._name,
				counter		: that._counter,
				filterList	: that._filterList,
				rate		: window.rate,
				l			: language
			});
		},

		/**
		 * Add filter list element from a result item group using
		 * getFilterListItem compontent methods from the options array
		 * @param object
		 */
		fillFilterList : function(_group){
			var filterListElem = this._options.getFilterListItem(_group);
			filterListElem.code = filterListElem.code || filterListElem.value;
			if (this._filterListIndx[filterListElem.code] !== undefined) return;
			this._counter++;
			this._filterListIndx[filterListElem.code] = this._filterList.length;
			this._filterList.push(filterListElem);
		},

		/**
		 * Sort filter list elements calling sortFilterList compontent methods from the options array
		 */
		sortFilterList : function(){
			var that = this;
			that._filterList.sort(function(a,b){
				return that._options.sortFilterList ?
					that._options.sortFilterList.apply(that,[
						a.value.toLowerCase(),
						b.value.toLowerCase(),
						a.code.toLowerCase(),
						b.code.toLowerCase()
					]) :
					a.value.toLowerCase() < b.value.toLowerCase() ? -1 : 1 ;
			});
		},

		/**
		 * During filtering it gives back the array of the actualy checked filter list items,
		 * array if everything went fine, "error" if there is some none name, so idless list item in the filter
		 * false if there is no checked box in the actual filer unit
		 * @return array || "error" || false
		 */
		getValue : function(){
			var values = {};
			if ($('filter-stars').value) {
				values[$('filter-stars').value] = true;
			} else { //select all
				forEach(this._filterList, function(_filter) {
					values[_filter.code] = true;
				});
			}
			return values;
		},

		/**
		 * During filtering it calls isFiltered component method and
		 * gives back true if the _group has filtered out otherwise false
		 * @param object
		 * @return boolean
		 */
		isFiltered : function(_group){
			var value = this.getValue();
			if (this._options.isFiltered)
				return !(this._options.isFiltered.apply(this,[_group,value]));
			else
				return false;
		}

	});



	/**
	 * Add leaves(filter unit components) to the composite(FilterContainer) singleton class
	 */
	FilterContainer.addFilter([
		new FilterRadio("stars",{
			getFilterListItem : function(_group){
				return {
					code 	: _group.starRatingRounds + "",
					value	: _group.starRatingRounds == 0 ? language["not_defined"] : _group.starRatingRounds + " " + language["SEOV2_Hotel_Directory_Stars_Title"] || language.not_defined + ""
				}
			},
			isFiltered : function(_group,_checkedValues){
				return _checkedValues[_group[0].starRatingRounds];
			}
		})
	]);

	/**
	 * Filters
	 * this is the actual filtering Singleton which u can access from outside,
	 * it removes the filtered result items from the Result.ActiveGroups,
	 * resets the filtering units etc.
	 */
	return Singleton(ModuleBase,{
		_name			: "Filters",
		_initialized	: false,
		_container		: "filterset",

		// registering to different events of Mediator
		init : function(){
			var that = this;
			// after a result item has been added, it fills the different filterlists of the filter components
			// and set isActive attrib of groups if prefiltering has happend
			Mediator.addEventListener("Results", function(_source,_action,_group){
				if( _action == "after_addItem"){
					FilterContainer.fillFilterList(_group);
					_group.isActive = true;
				};
			});
			// start onInitialization which depends on progress-startfiltering state of the App
			Mediator.addEventListener("App", function(_source,_action){
				if (!that._initialized && _action == "after_startFiltering") {
					that.onInitialization();
					that._initialized = true;
					//HotelWidget.hide();
				};
			});
		},
		// displaying filter block, do the prefiltering if it needs
		onInitialization : function(){
			Mediator.dispatchEvent(this,"before_initialization");
			
			FilterContainer.sortFilterList();
			FilterContainer.setTemplate();
			Layout.setText($(this._container),FilterContainer.getTemplate());
			//this.startFiltering();
			this._recalc();

			Mediator.dispatchEvent(this,"after_initialization");
		},

		/**
		 * It begins the actual filtering
		 * _latestFilter needs to set the last clicked filtering unit
		 * see FilterContainer.updateFiltersOrder method for more
		 * @param object
		 */
		startFiltering : function(_event){
			Mediator.dispatchEvent(this,"before_startFiltering");
			this._recalc();
			Mediator.dispatchEvent(this,"after_recalc");
			Layout.ResultDisplay.setPage(1);
			Mediator.dispatchEvent(this,"after_startFiltering");
		},

		updateFilter : function(_filter){
			forEach($$("a","filterset"), function(_a){ Layout.setClass(_a,""); });
			Layout.setClass($("filter-stars-" + _filter), "active");
		},

		// set isActive attrib of result items, and
		// removes so not adds the filtered groups from/to Results.ActiveGroups
		_recalc : function(){
			Results.ActiveGroups.reset();
			Results.eachGroupContainer(function(_groupContainer){				
				var group = _groupContainer.getGroups();
				group.isActive = true;
				if (FilterContainer.isFiltered(group)){			
					group.isActive = false;
				}else{
					if(group.isActive) Results.ActiveGroups.add(_groupContainer);
				};
			});
			Results.ActiveGroups.sort();
		}

	});

})();
/*
 * Included file end: /seo/v3/common/js/hotel/Filters.js
 * Included from:     /seo/v3/common/js/hotel/_main.js:15
 */

	
/*
 * Included file begin: /seo/v3/common/js/hotel/Application.js
 * Included from:       /seo/v3/common/js/hotel/_main.js:16
 */
/**
 * Application
 * download imgs, fetching result data,
 * contains accessors/mutators to the application level globals > App.Env
 */
var App = (function(){

	return Singleton(ModuleBase,{


		/**
		 * App.Env
		 * put global/so multiple modul used VARS here
		 * global constants like header.departureDateObj etc.
		 * are still remain in headerJSON
		 */
		Env : Singleton(ModuleBase,{

			_name : "App.Env",

			// true during filtering
			_$isFiltering: false,

			init : function(){
				//call to generate mutators for private vars which begin with _$
				this._base_init();
			}
		}),

	// App starts from here
		_name: "App",

		// img preloading, start fetching..., called from _main.js
		initialization : function(){
			if (!window.results || !window.results.length) return;

			var that = this;

			// generate results from the given JSON,
			for (var idx=0; idx<window.results.length; idx++)(function(_group,_idx){
				Results.addItem(_group);
				Mediator.dispatchEvent(that,"after_addItem",_group);
			})(window.results[idx],idx);

			Results.ActiveGroups.sort();
			if (window.page && window.page>1) Layout.ResultDisplay.setPage(window.page);
			if (!window.rate) Layout.ResultDisplay.updateResultItems();
			Style.show("resultset");

			Style.show("filterset");
			Mediator.dispatchEvent(this,"after_startFiltering");
			if (window.rate) {
				Filters.updateFilter(window.rate);
				Filters.startFiltering(null);
			}
		},

		openDeepLink: function(_id,_source){			
			var url = '/hotel_v3/redirect.jsp';
			var data = {
				itemindex: _id
			}
		}
	});

})();
/*
 * Included file end: /seo/v3/common/js/hotel/Application.js
 * Included from:     /seo/v3/common/js/hotel/_main.js:16
 */

	Event.observe(window,"load",function(){
		App.initialization();	
	});
	
	
//})();


