/*v6_02_2ac-20120208200150*///
//  Copyright 2008, trivago GmbH
//  All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without modification,
//  are permitted provided that the following conditions are met:
//
//  -> Redistributions of source code must retain the above copyright notice, this
//     list of conditions and the following disclaimer.
//  -> Redistributions in binary form must reproduce the above copyright notice, this
//     list of conditions and the following disclaimer in the documentation and/or
//     other materials provided with the distribution.
//  -> Neither the name of the trivago GmbH nor the names of its contributors may
//     be used to endorse or promote products derived from this software without
//     specific prior written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
//  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
//  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
//  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//  POSSIBILITY OF SUCH DAMAGE.
//

//
//  This file represents the common functionality, respectively "the lib" of trivagos
//  JavaScript sources. It's named COM.class.js, but there's many source that is just
//  manipulating prototypes.
//  We have tried to write this as fast and save as possible. For example the logging
//  feature is often just overkill, so we decided not to take over a programmers main
//  task: thinking.
//
//  Actual this is just a beta. You can get the most actual version here:
//  http://www.trivago.com/javascript/base/COM.class.js
//
//  Note that it is NOT recommended to use for(key in array) constructs after binding
//  this source. You'll get strange results: every browser will iterate the prototype
//  methods defined here.
//

//
//  First of all we declare COM and add first basic function to extend prototypes
//  it's only temporary used until COM is redefined. We need that function only for
//  initializing some functions
//

var COM = new function()
{

  this.extendPrototype = function(t, s)
  {
    for(var property in s)
    {
      try
      {
        if(typeof t[property] == 'undefined')
        {
          t[property] = s[property];
        }
      }
      catch(e)
      {
        return null;
      }
    }
  }

};

//
//  you can't avoid such an object...
//

var Browser = {
     IE:   window.attachEvent && !window.opera,
    IE6:   /msie 6\.0/i.test(navigator.userAgent),
    IE7:   /msie 7\.0/i.test(navigator.userAgent),
    IE8:   /msie 8\.0/i.test(navigator.userAgent),
  Opera:   !!window.opera,
 WebKit:   navigator.userAgent.indexOf('AppleWebKit') != -1,
  Gecko:   navigator.userAgent.indexOf('Gecko') != -1 && navigator.userAgent.indexOf('KHTML') == -1,
  KHTML:   navigator.userAgent.indexOf('KHTML') != -1,
MacSafari: ((navigator.userAgent.indexOf('Safari') != -1) && (navigator.platform? navigator.platform: navigator.userAgent).toLowerCase().indexOf('mac') != -1),
 Safari:   navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome')==-1,
 Chrome:   navigator.userAgent.indexOf('Chrome')!=-1,
   iPad:   navigator.userAgent.indexOf('iPad') != -1
};

//
//  First of all we declare our own object. We attach some functions to that object
//  with which we'll later attach Object.prototype. Note: it is recommended to use
//  all following extensions after adopting via COM.GET.Elem(), COM.GET.All(),
//  COM.GET.First(), COM.Element()...
//

var COMObject = function(){};

//
//  We start with some overhead: member(s) that are able to tell us the type of their
//  object. Because it's really uncomfortable to overload Elements (IEs <= v7 are not
//  able to fit with) every element is getting handled like all other objects - until
//  it has passed a COM routine.
//

COMObject.prototype.isElement = function() { return false };

//
//  Often it is necessary to distinguish objects more accurate than typeof(); does...
//  Example: typeof(new Array) and typeof(new Object) will result in the same string:
//  "object". Note that these and all following prototype definitions will not effect
//  elements in IE before they've been adopted...
//

COMObject.prototype.isBoolean = function() { return this.constructor == Boolean };
COMObject.prototype.isString  = function() { return this.constructor ==  String };
COMObject.prototype.isNumber  = function() { return this.constructor ==  Number };
COMObject.prototype.isArray   = function() { return this.constructor ==   Array };
COMObject.prototype.isObject  = function() { return this.constructor ==  Object };

//
//  Here is the alternative for "typeof". The con is that it can't get called on some
//  undefined value. Even if "null" has object character in JavaScript you should use
//  COM.GET.Type(); which is wrapping this by using try/catch.
//

COMObject.prototype.getType = function()
{
  return this.isArray()   ?   'array':
         this.isElement() ? 'element':
         this.isString()  ?  'string': typeof this;
};

//
//  This will return the first index of a value appearing in an array-like object. so
//  expect a number or string. in case of failure it'll return "null". an "arguments"
//  object will get handled like arrays do.
//

COMObject.prototype.getKeyOf = function(value)
{
  if(this.isArray() || (this.callee && (this.length || (this.length === 0))))
  {
    for(var i=0, n=this.length; i!=n; ++i)
    {
      if(this[i] == value)
      {
        return i;
      }
    }
  }

  for(var key in this)
  {
    if(this[key] == value)
    {
      return key;
    }
  }

  return null;
}

//
//  Can get used in for/in loops to iterate just the "new" properties.
//

COMObject.prototype.hasNative = function(property)
{
  return typeof this.constructor.prototype[property] != 'undefined';
}

//
//  A wrapper for .getKeyOf(); that allows simple statements in boolean context with-
//  out necessity to filter undefined, null or whatever. You should note that there's
//  a bit more to do like using .getKeyOf(); and so it's not faster.
//

COMObject.prototype.hasValue = function(value)
{
  return this.getKeyOf(value) !== null;
}

//
//  The easiest way to make copies of objects. Will also work with elements. The only
//  argument tells if the cloning has to be recursive. That means: childs of elements
//  will get cloned too.
//  You can define the clone depth by passing a negative value. For example: - 2 will
//  cause a result, where the 1st and the 2nd level are containing copies, but any of
//  the following will just hold references.
//  The value of this argument doesn't effect the cloning depth of elements - in this
//  case boolean context matters.
//

COMObject.prototype.clone = function(recursive)
{
  if(typeof this.cloneNode == 'function')
  {
    return this.cloneNode(recursive);
  }

  if(typeof this != 'object')
  {
    return this.valueOf();
  }

  var clone = new this.constructor(), property;

  for(property in this)
  {
    if(clone[property] !== this[property])
    {
      try
      {
        clone[property] = recursive && this[property] &&
                                       this[property].clone?
                                       this[property].clone(recursive +1):
                                       this[property]
      } catch(e) {}
    }
  }

  return clone;
}

//
//  You can pass a routine, a routine-reference or a string of Script. Every value of
//  the array (or the array-like object) will become passed as first argument for the
//  function - which will get called for each entry.
//  This function will log errors appearing during iteration, because it wouldn't be
//  very useful if the value that has caused it will also cause a full break. If you
//  want to suppress this behavior, pass a 2nd argument with a "true" value.
//

COMObject.prototype.forEach = function(routine, stop)
{
  var result  = [];
      routine = COM.GET.Function(routine);

  for(var i=0, n=this.length; i<n; ++i)
  {
    try
    {
      result.push(routine(this[i]));
    }
    catch(e)
    {
      if(stop)
      {
        throw e;
      }

      result.push(COM.Log(this+'.forEach(['+typeof routine+'])['+i+']: '+e));
    }
  }

  return result;
}

//
//  Nearly the same like .forEach(), calls the routine as member of the entry itself,
//  but: Here is possible to define arguments. The 3rd of .withEach() will become the
//  1st of the member routine...
//

COMObject.prototype.withEach = function(routine, stop)
{
  var result = [], args = [];

  for(var i=2,n=arguments.length; i<n; ++i)
  {
    args.push(arguments[i]);
  }

  for(var i=0, n=this.length; i<n; ++i)
  {
    try
    {
      result.push(this[i][routine].apply(this[i], args));
    }
    catch(e)
    {
      result.push(COM.Log(this+'.withEach('+routine+')['+i+']: '+e+' ('+this[i]+')'));

      if(stop)
      {
        throw e;
      }
    }
  }

  return result;
}

//
//  Creates search-parts of URLs by iterating over hashes/ objects members. booleans,
//  numbers and strings get included. other stuff will be ignored.
//

COMObject.prototype.toQuery = function()
{
  var result = '';

  for(var property in this)
  {
    ({'number':1,'string':1,'boolean':1})[typeof this[property]] &&
    (result += (result? '&': '')+ encodeURI(property) +'='+ (this[property].isBoolean()? new Number(this[property]): encodeURI(this[property])));
  }

  return result;
}

//
//  We extend Array.prototype with new functions.
//

COM.extendPrototype(Array.prototype, COMObject.prototype.clone());

//
//  We extend String.prototype with new functions.
//

COM.extendPrototype(String.prototype, COMObject.prototype.clone());

//
//  Standard string functionality. Removes all whitespace characters on the [r]ight,
//  the [l]eft or the [i]side of a string.
//

String.prototype.ltrim = function() { return this.replace(/^\s+/,  '') }
String.prototype.itrim = function() { return this.replace(/\s+/g, ' ') }
String.prototype.rtrim = function() { return this.replace(/\s+$/,  '') }

//
//  Removing leading and following whitespace(s) - with or without the inside ones.
//

String.prototype.gtrim = function() { return this.trim().itrim()  }
String.prototype.trim  = function() { return this.rtrim().ltrim() }

//
//  Standard string functionality. Extends a string to given [l]ength adding [s]tring
//  on the [l]eft or the [r]ight.
//

String.prototype.lpad = function(l, s)
{
  o = this; while(o.length < l) { o = s.concat(o); }
  return o.substr(o.length-l);
}

String.prototype.rpad = function(l, s)
{
  o = this; while(o.length < l) { o = o.concat(s); }
  return o.substr(0, l);
}

//
//  Creating a valid URL query by escaping a string, but not the ampersands and equal
//  signs in it. If there's more than one equal sign between two ampersands, just the
//  first will stay unescaped. Entities will confuse this function, /&+/g won't.
//

String.prototype.toQuery = function()
{
  var split = this.replace(/&+/g, '&').split('&');

  if(split.length < 2)
  {
    return this.valueOf();
  }

  for(var i=0, n=split.length; i!=n; ++i)
  {
    split[i] = escape((split[i] = split[i].split('=')).shift()) +'='+ escape(split[i].join('='));
  }

  return split.join('&');
}

//
//We extend Date.prototype with new functions.
//

COM.extendPrototype(Date.prototype, COMObject.prototype.clone());

//
//  Stolen from the nasty DHTML calendar, translated to real source and bound here...
//

Date.prototype.oldFullYear = Date.prototype.setFullYear;
Date.prototype.setFullYear = function(year)
{
  var date = new Date(this);
      date.oldFullYear(year);

  if(date.getMonth() != this.getMonth())
  {
    this.setDate(28);
  }

  this.oldFullYear(year);
  return true;
}

//
//  Stolen from the nasty DHTML calendar, translated to real source and bound here...
//

Date.prototype.setYearMonthDay = function()
{
  var date = new Date(arguments.length == 1? arguments[0] :
                                             arguments[0] +'-'+
                                             arguments[1] +'-'+
                                             arguments[2] );
  this.setDate(1);

  this.setFullYear( date.getFullYear());
  this.setMonth(    date.getMonth());
  this.setDate(     date.getDate());

  return true;
}

//
//  Stolen from the nasty DHTML calendar, translated to real source and bound here...
//

Date.prototype.getString = function(format)
{
  var month = this.getMonth(), day = this.getDate(), year = this.getFullYear(), hash = {};

  format || (format = '%y-%m%-%d');

  hash['%y'] = year;
  hash['%m'] = ++month <10? '0'+ month: month;
  hash['%d'] =     day <10? '0'+   day:   day;

  for(var i=0, a=format.match(/%./g), n=a.length; i<n; ++i)
  {
    if(hash[a[i]])
    {
      format = format.replace(new RegExp(a[i], 'g'), hash[a[i]]);
    }
  }

  return format;
}

//
//  Stolen from the nasty DHTML calendar, translated to real source and bound here...
//

Date.prototype.compareDate = function(date)
{
  return (this.getFullYear() == date.getFullYear() ) &&
         (this.getMonth()    == date.getMonth()    ) &&
         (this.getDate()     == date.getDate()     );
}

//
//  NOT stolen from the nasty DHTML calendar, but real source by nature...
//

Date.prototype.compareTime = function(date)
{
  return (this.getHours()   == date.getHours()   ) &&
         (this.getMinutes() == date.getMinutes() ) &&
         (this.getSeconds() == date.getSeconds() );
}

//
//  Stolen from the nasty DHTML calendar, translated to real source and bound here...
//

Date.prototype.getMonthDayCount = function(month, year)
{
  year  || (year  = this.getFullYear());
  month || (month = this.getMonth());

  return ((0 == (year %4  )) &&
         ((0 != (year %100)) ||
          (0 == (year %400)) )) && month == 1? 29: ([31,28,31,30,31,30,31,31,30,31,30,31])[month];
}

//
//  Defining COMElement to extend Element.prototype later. Note again: it is recommended
//  to use all following extensions after adopting via COM.GET.Elem(), COM.GET.All(),
//  COM.GET.First(), COM.Element()... 
//

var COMElement = function(){};
COMElement.prototype = COMObject.prototype.clone();

//
//  Redefining type.
//

COMElement.prototype.isElement = function() { return true  }
COMElement.prototype.isObject  = function() { return false }

//
//  Easy getters that are returning dimension and position values or undefined; they
//  don't really do anything. but they should get used - you'll see why...
//

COMElement.prototype.getWidth  = function() { return this.offsetWidth  }
COMElement.prototype.getHeight = function() { return this.offsetHeight }
COMElement.prototype.getLeft   = function() { return this.offsetLeft   }
COMElement.prototype.getTop    = function() { return this.offsetTop    }

//
//  Some comfort...
//

document.getCoords =
    self.getCoords =

COMElement.prototype.getCoords = function()
{
  return {x:this.getLeft(), y:this.getTop()};
}

//
//  More overhead - simple setter expecting a pixel-value. It's able to become a very
//  useful shortener for your source...
//

COMElement.prototype.setWidth  = function(w) { return this.setStyle('width',  parseInt(w) +'px') }
COMElement.prototype.setHeight = function(h) { return this.setStyle('height', parseInt(h) +'px') }
COMElement.prototype.setLeft   = function(x) { return this.setStyle('left',   parseInt(x) +'px') }
COMElement.prototype.setTop    = function(y) { return this.setStyle('top',    parseInt(y) +'px') }

//
// More comfort - simple delete the attributes and set them back to default. It's able to become
// a very useful shortener for your source...
//

COMElement.prototype.delWidth  = function() { return this.setStyle('width',  'auto') }
COMElement.prototype.delHeight = function() { return this.setStyle('height', 'auto') }
COMElement.prototype.delLeft   = function() { return this.setStyle('left',   'auto') }
COMElement.prototype.delTop    = function() { return this.setStyle('top',    'auto') }

//
//  Maybe you've heard from this, and yes, they work equivalent to members of window.
//  See COM.GET.Elem() if you're interested in what to do with the <body> tag.
//

COMElement.prototype.resizeBy = function(w, h) { return (this.setWidth( this.getWidth() +w) === null) || this.setHeight( this.getHeight() +h) }
COMElement.prototype.resizeTo = function(w, h) { return (this.setWidth(                  w) === null) || this.setHeight(                   h) }
COMElement.prototype.moveBy   = function(x, y) { return (this.setLeft(  this.getLeft()  +x) === null) || this.setTop(    this.getTop()    +y) }
COMElement.prototype.moveTo   = function(x, y) { return (this.setLeft(                   x) === null) || this.setTop(                      y) }

//
//  Get the next higher bodied element that's positioned absolute, relative or fixed.
//

COMElement.prototype.getContainer = function() { return this.offsetParent }

//
//  "Abs" abbreviates "Absolute"...
//

COMElement.prototype.getAbsLeft = function() { var node = this, value = 0; do value += node.offsetLeft; while((node = node.offsetParent) && (node != document.body)); return value }
COMElement.prototype.getAbsTop  = function() { var node = this, value = 0; do value += node.offsetTop;  while((node = node.offsetParent) && (node != document.body)); return value }

//
//  Detect scroll positions. NOT the window scroll positions!
//

COMElement.prototype.getXPos = function() { return this.scrollLeft }
COMElement.prototype.getYPos = function() { return this.scrollTop  }

//
//  Trying to get "computed style". In optimal case it's possible to get also not ex-
//  plicit defined properties - But I don't care. "float"/"opacity" will get returned
//  browser-independent.
//

COMElement.prototype.getStyle = function(property)
{
  switch(property)
  {
    case 'float':    return typeof this.style.cssFloat != 'undefined'? this.style.cssFloat: this.style.styleFloat;
    case 'opacity':  return this.getOpacity();
  }

  if(typeof self.getComputedStyle == 'function')
  {
    return self.getComputedStyle(this, null).getPropertyValue(property.replace(/([A-Z])/g, "-$1").toLowerCase());
  }

  return this.style[property];
}

//
//  Maybe this is just to ensure that "float" and "opacity" will get set in the right
//  way. But maybe there are properties we forget?
//

COMElement.prototype.setStyle = function(property, value)
{
  switch(property)
  {
    case 'float':    return this.style.cssFloat = this.style.styleFloat = value;
    case 'opacity':  return this.setOpacity(value);
  }

  return this.style[property] = value;
}

//
//  Use percentage values.
//

COMElement.prototype.getOpacity = function()
{
  var style = this.style;

  if(typeof(style.MozOpacity)   != 'undefined') { return style.MozOpacity   === ''? 100: parseFloat(style.MozOpacity)   *100; }
  if(typeof(style.opacity)      != 'undefined') { return style.opacity      === ''? 100: parseFloat(style.opacity)      *100; }
  if(typeof(style.KhtmlOpacity) != 'undefined') { return style.KhtmlOpacity === ''? 100: parseFloat(style.KhtmlOpacity) *100; }
  if(typeof(style.filter)       != 'undefined')
  {
    if(!(style = style.filter))
    {
      return 100;
    }

    var pos = style.indexOf('alpha');

    if((pos == -1) && ((pos = style.indexOf('Alpha')) == -1))
    {
      return 100;
    }

    if((pos = style.indexOf("opacity='")) == -1) 
    {
    	if((pos = style.indexOf('opacity="')) == -1)
    	{
    		if((pos = style.indexOf('opacity=')) == -1)
    		{
    			return 100; 
    		}
    		--pos; 
    	}
    }

    return parseInt(style.substr(pos +9));
  }

  return null;
}

//
//  Returns percentage values.
//

COMElement.prototype.setOpacity = function(value)
{
  var style = this.style;

  value = parseInt(value);
  value = value > 99? 100: value < 1? 0: value;

  style.opacity = style.KhtmlOpacity = style.MozOpacity = (value / 100).toString();
  style.filter  = 'alpha(opacity='+ value +')';

  return value;
}

//
//  To toggle style.visibility.
//

COMElement.prototype.show = function() { return this.style.visibility = 'visible' }
COMElement.prototype.hide = function() { return this.style.visibility =  'hidden' }
COMElement.prototype.swap = function()
{
  return this.style.visibility = this.getStyle('visibility') == 'hidden'? 'visible': 'hidden';
}

//
//  Will overload the element with the current value of (computed-) style.display and
//  set this value to 'none'. If it's still none, the defaultDisplayType will not get
//  set - so we ensure not to overwrite.
//

COMElement.prototype.disappear = function()
{
	var style;
	if ((style = this.getStyle('display')) != 'none')
	{
		this.defaultDisplayType = style;
	}
	return this.style.display = 'none';
}

//
//  If the defaultDisplayType is defined, we set it back. Otherwise the value is set
//  to 'block'. Nasty, but other methods are not fast enough.
//

COMElement.prototype.appear = function()
{
  return this.style.display = this.defaultDisplayType? this.defaultDisplayType: 'block';
}

//
//  Toggle (current-) style.display.
//

COMElement.prototype.toggle = function()
{
  return this.getStyle('display') == 'none'? this.appear(): this.disappear();
}

//
//
//

COMElement.prototype.setClass = function(name) { return this.className = name }
COMElement.prototype.getClass = function()     { return this.className }
COMElement.prototype.delClass = function(name) { return this.className = this.className.replace(new RegExp('\\b'+name+'\\b', 'g'), '').gtrim() }
COMElement.prototype.hasClass = function(name) { return this.className.match(new RegExp('\\b'+name+'\\b')) }
COMElement.prototype.addClass = function(name)
{
  if(this.className)
  {
    if(!this.hasClass(name))
    {
      this.className += ' '+ name;
    }
  }
  else
  {
    this.className = name;
  }

  return true;
}

//
//  Check if an element has any tasks for a specific event. Not really nesseccary but
//  the other event-related members will use this. Note that all handlers defined via
//  attributes will get translated, unshifted to the queue and removed from dom.
//  Furthermore: it doesn't matter if you set events to body-tag, document or window,
//  they'll all become entries in the same queue.
//
//  Important: The this. keyword, referring the element, will not work any more after
//             translating javascript-strings to functions! use arguments[1] instead.
//             the event object will become the first argument.
//             Maybe it would be useful to append something like the following pregex
//             to this method, but in this case "this" referring inline-defined elems
//             won't work any more:
//
//              .replace(/([^a-zA-Z0-9_$]*)\this\./, "$1arguments[1].")
//
//             See COM.GET.Function() for further discussion.
//             Any proposals how we should decide?
//

document.hasEvent =
    self.hasEvent =

COMElement.prototype.hasEvent = function(type)
{
  var holder = this, handle = this;

  switch(type.toLowerCase())
  {
    case 'domcontentloaded':
    case 'onreadystatechange':
    case 'readystatechange':
      holder = handle = (this.attachEvent) ? document           : self;
                 type = (this.attachEvent) ? 'readystatechange' : 'DOMContentLoaded';
      break;

    default:
	  if((this.tagName && (this.tagName == 'BODY')) || (this == self))
	  {
	    holder = COM.GET.Body();
	    handle = self;
	  }
      type = type.toLowerCase().replace(/^on/, '');
  }
  
  holder = COM.GET.Elem(holder);
  handle = COM.GET.Elem(handle);

  handle.events || (handle.events = COM.GET.Elem({}));

  if(!handle.events[type])
  {
    var routine = function(event) { return handle.runEvent(type, event); };
    handle.events[type] = COM.GET.Elem([]);

    try
    {
      handle.addEventListener(type, routine, false);
    }
    catch(e)
    {
      handle['do'+ type +'Event'] = routine;
      if (type == 'readystatechange')
      {
    	  handle['on'+ type +'Event'] = function() { if (handle.readyState === "complete") {handle['do'+ type +'Event'](self.event);} };
      }
      else
      {
    	  handle['on'+ type +'Event'] = function() { handle['do'+ type +'Event'](self.event); };
    	  
      }
      handle.attachEvent('on'+ type, handle['on'+ type +'Event']);
    }
  }

  if(holder&&holder.getAttribute&&holder.getAttribute('on'+ type))
  {
    handle.events[type].push(COM.GET.Function(holder.getAttribute('on'+ type)));

    holder.setAttribute('on'+ type, null);
    holder.removeAttribute('on'+ type);
  }

  return handle.events[type].length;
}

//
//  Here the tasks get added to the event- related queue. Specify the events type you
//  want to tune ('onclick', 'mouseover'), then pass a function or function reference
//  (or string, see discussion of .hasEvent() and COM.GET.Function()).
//  With the 3rd arg it's possible to avoid validation of your function - but that is
//  deprecated and not recommended.
//

document.addEvent =
    self.addEvent =

COMElement.prototype.addEvent = function(type, routine, force)
{
  var node;

  switch(type.toLowerCase())
  {
	case 'domcontentloaded':
    case 'onreadystatechange':
    case 'readystatechange':
      node = (this.attachEvent) ? document           : self;
      type = (this.attachEvent) ? 'readystatechange' : 'DOMContentLoaded';
      break;

    default:
      node = (this.tagName && (this.tagName == 'BODY'))? self: this;
      type = type.toLowerCase().replace(/^on/, '');
  }

  node = COM.GET.Elem(node);
  node.hasEvent(type);
  node.events[type].push(force? routine: COM.GET.Function(routine));
  return true;
}

//
//  Removing elements from the queue. Leaving out the 2nd arg will cause that it gets
//  flushed. Note that there's no way to get them back if you don't hold references -
//  or catch the spliced ones.
//

document.delEvent =
    self.delEvent =

COMElement.prototype.delEvent = function(type, routine, force)
{
  var node, i;

  switch(type.toLowerCase())
  {
  	case 'domcontentloaded':
    case 'onreadystatechange':
    case 'readystatechange':
      node = (this.attachEvent) ? document           : self;
      type = (this.attachEvent) ? 'readystatechange' : 'DOMContentLoaded';
      break;

    default:
      node =(this.tagName && (this.tagName == 'BODY'))? self: this;
      type = type.toLowerCase().replace(/^on/, '');
  }
  
  node = COM.GET.Elem(node);
  if(node.hasEvent(type))
  {
    if(!routine)
    {
      node.events[type] = COM.GET.Elem([]);
      return !0;
    }

    routine = String(force? routine: COM.GET.Function(routine));

    for(i=0; node.events[type] && i<node.events[type].length; ++i)
    {
      if(routine == String(node.events[type][i]))
      {
        return node.events[type].splice(i,1);
      }
    }
  } 

  return i? null: false;
}

//
//  This is called instead of the functions you have passed. Of course it is possible
//  to simulate this call, but you should also provide the 2nd arg, the event-object.
//

document.runEvent =
    self.runEvent =

COMElement.prototype.runEvent = function(type, task)
{
  var node, i=false;
  switch(type.toLowerCase())
  {
  	case 'domcontentloaded':
    case 'onreadystatechange':
    case 'readystatechange':
      node = (this.attachEvent) ? document           : self;
      type = (this.attachEvent) ? 'readystatechange' : 'DOMContentLoaded';
      break;

    default:
      node = (this.tagName && (this.tagName == 'BODY'))? self: this;
      type = type.toLowerCase().replace(/^on/, '');
  }

  node = COM.GET.Elem(node);
  if(node.hasEvent(type))
  {
	var q = node.events[type].clone();
    for(i=0; i<q.length; ++i)
    {
      try
      {
        q[i](task, COM.GET.EventTarget(task));
      }
      catch(e)
      {
        COM.Log(node+'.runEvent('+type+'); '+i+': '+e.message);
      }
    }
  }

  return i;
}

//
//  Some wrapped stuff...
//

document.resizeTo = self.resizeTo;
document.resizeBy = self.resizeBy;

document.moveTo   = self.moveTo;
document.moveBy   = self.moveBy;

document.scrollTo   = self.scrollTo;

//
//  Our window and document seems to be the same...
//

self.getWidth  = document.getWidth  = function() { var width  = document.body.clientWidth;  return typeof width  == 'undefined'? self.innerWidth:  width  }
self.getHeight = document.getHeight = function() { var height = document.body.clientHeight; return typeof height == 'undefined'? self.innerHeight: height }

self.getAbsWidth  = document.getInnerWidth  = function() { var width  = document.documentElement.scrollWidth;  return typeof width  == 'undefined'? document.body.scrollWidth  : width  }
self.getAbsHeight = document.getInnerHeight = function() { var height = document.documentElement.scrollHeight; return typeof height == 'undefined'? document.body.scrollHeight : height }

self.getLeft = document.getLeft = function() { return self.screenX }
self.getTop  = document.getTop  = function() { return self.screenY }

self.getXPos = document.getXPos = function() { var x = ((typeof document.documentElement == 'undefined') || Browser.Chrome)? self.pageXOffset : document.documentElement.scrollLeft; return typeof x == 'undefined'? self.scrollLeft: x }
self.getYPos = document.getYPos = function() { var y = ((typeof document.documentElement == 'undefined') || Browser.Chrome)? self.pageYOffset : document.documentElement.scrollTop;  return typeof y == 'undefined'? self.scrollTop:  y }

self.setWidth  = document.setWidth  = function(w) { return self.resizeBy(w, 0) }
self.setHeight = document.setHeight = function(h) { return self.resizeBy(0, h) }

self.setLeft = document.setLeft = function(x) { return self.moveTo(x, 0) }
self.setTop  = document.setTop  = function(y) { return self.moveTo(0, y) }

self.addBookmark = document.addBookmark = function(u, t, m)
{
  try
  {
    window.external.AddFavorite(u, t);
  }
  catch (e)
  {
    try
    {
      window.external.addPanel(t, u, '');
    }
    catch (e)
    {
      alert(m);
      APP.ERROR.Log('self.addBookmark() | ' + e);
    }
  }
	
  return true;
}

self.mailTo = document.mailTo = function(m, s, b)
{
  try
  {
	  location.href = 'mailto:'+m+'?subject='+s+'&body='+encodeURIComponent(b);
  }
  catch (e)
  {
    try
    {
      var el = document.createElement('a');
      el.setAttribute('href', 'mailto:'+m+'?subject='+s+'&body='+encodeURIComponent(b));
      el.click();
    }
    catch (e)
    {
    	APP.ERROR.Log('self.mailTo() | ' + e);
    }
  }
}

//
//  Very long prelude, but now the flesh follows. We've decided to use the old object
//  notation because JSON doesn't allows us to define private variables.
//  Furthermore, "new function()" has the touch of a static class, not a singleton...
//  At this point COM.extendPrototype is deleted and all prototypes are extended.
//

COM = new function()
{

  //
  //  It is not usual to define privates at the top, but if you really want to under-
  //  stand what we're going to do, you should have a look at.
  //
  //  HEAD and BODY become references, LOAD is set after the windows load- event, LOG
  //  containes dynamic information for developers, SRC the urls of sources that have
  //  still been required, LYR is a stack of LAYER instances and DEBUG you will learn
  //  to love...
  //

  var HEAD = null, BODY = null, LOAD = false, LOG = [], SRC = {}, LYR = [];
  
  try
  {
    var DEBUG = self.opener &&
                self.opener.COM &&
                self.opener.COM.DEBUG &&
                self.opener.COM.DEBUG.Receiver? self.opener.COM.DEBUG.Receiver: null;
  }
  catch (e)
  {
    var DEBUG = null;
  }

  //
  //  Now it's time for some static getter.
  //

  this.GET = {

    //
    //  You should use this instead of document.getElementById(). It is an "adopting"
    //  routine, we've discussed before. You can pass an element reference or its id.
    //

    Elem: function(anything)
    {
      var name = 'COM.GET.Elem('+anything+'); ',
          prototype, 
          result;

      if(anything)
      {
          try
          {
    	    if(typeof anything == 'object' || (typeof anything == 'function' && anything.constructor == Object))
    	    {
    	      prototype = typeof anything.nodeName == 'string'? COMElement.prototype: COMObject.prototype;
    	      result    = anything;
    	    }
    	    else
    	    {
    	      prototype = COMElement.prototype;
    	      result    = document.getElementById(anything);
    	    }
          }
          catch(e)
          {
            COM.Log('COM.GET.Elem: '+e+' (E1)');
          }

          if(result)
          {
            var body = document.body == result;

            for(var property in prototype)
            {
              try
              {
                if(typeof result[property] == 'undefined')
                {
                  if( body &&
                      ( property == 'resizeTo' ||
                        property == 'moveTo' ||
                        property == 'resizeBy' ||
                        property == 'moveBy' ) )
                  {
                    continue;
                  }

                  result[property] = prototype[property];
                }
              }
              catch(e)
              {
                COM.Log(name+'.'+property+': '+e+' (E2)');  
              }
            }

            try
            {
              if((result == document.body) && !BODY)
              {
                for(var a=[
                  'moveTo', 'resizeTo', 'getWidth', 'getHeight', 'getLeft', 'getTop',    'getXPos', 'getYPos', 'getCoords', 
                  'moveBy', 'resizeBy', 'setWidth', 'setHeight', 'setLeft', 'setTop', /*'setXPos', 'setYPos', 'setCoords', */
                  'scrollTo'
                ], i=0; i!=a.length; ++i) { result[a[i]] = self[a[i]] }
              }
            }
            catch(e)
            {
              COM.Log(name+' BODY: '+e+' (E3)');  
            }

            return result;
          }
      }

      return new COMObject();
    },

    //
    //  Equivalent to document.getElementsByTagName, "adopting". Beside the tagName -
    //  which can be represented by a tag reference - you can pass a parent for focus
    //  and the max. number of entries in the result that are going to get adopted.
    //  The default's zero.
    //

    All: function(anything, parent, max)
    {
      parent = parent? COM.GET.Elem(parent): document;

      var result = parent.getElementsByTagName(anything.nodeName? anything.nodeName: anything);

      for(var i=0; (i!=max)&&(i!=result.length); ++i)
      {
        COM.GET.Elem(result[i]);
      }

      return result;
    },

    //
    //  Like .All(), but you'll get just the first reference. Adopting.
    //

    First: function(anything, parent)
    {
      try
      {
        return this.All(anything, parent, 1)[0];
      }
      catch(e)
      {
        return null;
      }
    },

    //
    //  Like .First(), when you pass 'head' or 'body'.
    //

    Head: function() { return HEAD? HEAD: HEAD = this.First('head'); },
    Body: function() { return BODY? BODY: BODY = this.First('body'); },

    //
    //  To catch the element which caused an event. Browser-independent. Note that it
    //  is not nesseccary to call it inside of event- handlers that have been defined
    //  by using this sources, try arguments[1].
    //

    EventTarget: function(task)
    {
      var target;

      if(task)
      {
        if(task == self)
        {
          return self;
        }

        if((typeof task.nodeName  == 'string')&&
           (typeof task.className == 'string'))
        {
          return task;
        }

        return typeof task.target == 'undefined'? task.srcElement?
                                                  task.srcElement: event.srcElement: task.target
      }
    },

    //
    //  Translates array-like objects (e.g. "arguments") to arrays.
    //  Arrays will stay arrays.
    //

    Array: function(object)
    {
      try
      {
        var result = [], i, n;

        for(i=0, n=object.length; i<n; ++i)
        {
          result.push(object[i]);
        }

        return result;
      }
      catch(e)
      {
        return COM.Log('COM.GET.Array(['+typeof object+']); '+e);
      }
    },

    //
    //  Translates strings into functions. Functions will stay functions. If you pass
    //  a string, the "this" keyword won't work anymore. That means, usually it won't
    //  refer what it has referred before, but maybe the object which calls it.
    //

    Function: function(routine)
    {
      try
      {
        return typeof routine == 'function' ? routine:
               typeof routine == 'string'   ? new Function('', routine): COM.Log('.Function(['+typeof routine+']): !allowed');
      }
      catch(e)
      {
        return COM.Log('COM.GET.Function(['+typeof routine+']); '+e);
      }
    },

    //
    //  Get whatever LOG contains. If you pass an arg that's true in boolean context,
    //  you'll get a reference to this array. Just a subject to developers.
    //

    Log: function(reference)
    {
      return reference? LOG: LOG.clone();
    }

    //
    //  Whenever there is anything not detecable failure-save or browser-independent enough, it
    //  should become a part of this subJect. But just, if more prototype tuning isn't a better
    //  solution.
    //

  }

  //
  //  Onscreens.
  //

  this.WIZARD = new function()
  {

    //
    //  Open an onscreen form. This may not really define any further layouts, but you can pass
    //  a COM.Element() compatible as 1st arg, as content. the second arg specifies the opacity
    //  of the layer in the middleground (zero is possible). if the third's boolean, a click on
    //  the layer will cause .WIZARD.Close(). Otherwise, if it's compatible to .GET.Function(),
    //  a click on the layer will cause it's execution.
    //  Call this function again to change the content if the WIZARD's still open.
    //

    this.Open = function(content, opac, click)
    {
      if(!Form)
      {
        BODY || COM.GET.Body();

        Form = COM.Element(['div',{'class':'COMElement COMWizardForm'}]);
        Cont = COM.Element(['div',{'class':'COMElement COMWizardCont'}]);

        Layer = new COM.Layer();
        Form.appendChild(Cont);
        Cont.addEvent('click', COM.Void);
      }

      if(click)
      {
        Form.addEvent('click', (typeof click == 'function')
                            || (typeof click == 'string')? COM.GET.Function(click): COM.WIZARD.Close);
      }
      else
      {
        Form.delEvent('click');
      }

      self.delEvent('resize', COM.WIZARD.Size);
      Layer.open(true, opac? opac: 50);
      COM.GET.Body().insertBefore(Form, COM.GET.Body().firstChild);

      if(content != Cont.firstChild)
      {
        while(Cont.firstChild)
        {
          Cont.removeChild(Cont.firstChild);
        }

        Cont.appendChild(COM.Element(content));
      }

      is_open = true;

      return COM.WIZARD.Size();
    }

    //
    //  Close the WIZARD. Note that the 3rd argument of .WIZARD.Open() won't take effect if you
    //  call this manually.
    //

    this.Close = function()
    {
      self.delEvent('resize', COM.WIZARD.Size);
      BODY.removeChild(Form);
      is_open = false;
      return Layer.close();
    }
    
    //
    // is wizard open?
    //
    
    this.IsOpen = function()
    {
    	return is_open;
    }

    //
    //  Usually, there's no need to call this routine. It's in window.onresize queue as soon as
    //  you've called .WIZARD.Open().
    //

    this.Size = function()
    {
      if (!(Form && Cont))
      {
    	  return false;
      }
      
      self.delEvent('resize', COM.WIZARD.Size);

      var width  = self.getWidth(),
          height = self.getHeight(),
          xpos   = self.getXPos();

      Form.style.width  = width  +'px';
      Form.style.height = height +'px';

      Cont.style.width = Cont.firstChild.getWidth() +'px';
      var            y = Cont.firstChild.getHeight(), d;

      Cont.style.paddingTop = Cont.style.paddingBottom = ((d=height+xpos-y)>10? d/3: height/5) +'px';
      Layer && Layer.size();
      return self.addEvent('resize', COM.WIZARD.Size);
    }

    //
    //  Usually, there's no need to call this routine, but sometimes you probably need hided elements.
    //

    this.Hidden = function()
    {
      if (Layer)
      {
        return Layer.hidden();
      }
      return [];
    }    

    //
    //  Privates holding references.
    //

    var Form,
        Layer,
        Cont,
        is_open = false;

    //
    //  Especially if there are many elements in the root of the DOM, there's many stuff to do.
    //  So it's recommended to use a <div> or whatelse around the documents main nodes...
    //

  }

  //
  //  Used quite often to separate the pages content from the current focus. Not be visible all
  //  the times: can also get used just to simluate "onmouseout" for more complex structs, like
  //  dropdowns, or clickouts etc...
  //

  this.Layer = function()
  {
    //
    //  To show the element, you have to define if you still want the user to be able to scroll
    //  the main page. Optional you can specify an opacity value and z-index. default is 50,90.
    //  Last but not least: here you can also define special event handling, just like .WIZARD.
    //

    this.open = function(scroll, opacity, zIndex, event)
    {
      if(proc)
      {
        return COM.Log('.Layer['+ numb +'].open: double process: '+proc);
      }

      proc = 'open';

      if(!opac)
      {
        opac = COM.Element(['div',{'class':'COMElement COMLayerOpac'}]);
        temp = COM.Element(['div',{'class':'COMElement COMLayerTemp'}]);
      }
      else
      {
        var mySelf = this;
        self.delEvent('resize', function(){mySelf.size()}, 1);
      }

      if (!Browser.IE6)
      {
	    temp.style.position = 'relative';
	    temp.style.left = '0px';
	    temp.style.top  = '0px';
      }
      opac.setStyle('opacity', opacity?  opacity:  0);
      opac.setStyle('zIndex',   zIndex?   zIndex: 90);

      if(!(temp.parentNode && temp.parentNode.nodeType == 1))
      {
        BODY || COM.GET.Body();
        BODY.insertBefore(temp, BODY.firstChild);

        while(elem = BODY.firstChild.nextSibling)
        {
          BODY.removeChild(elem);
          temp.appendChild(elem);
        }

        BODY.appendChild(opac);

        if(!hide.length)
        {
          for(var i=0; i!=3; ++i)
          {
            hide.push(COM.GET.Array(COM.GET.All((['embed', 'object', 'select'])[i], temp, -1)));

            for(var j=0, n=hide[i].length; j<n; ++j)
            {
              try
              {
                hide[i][j] = [hide[i][j], hide[i][j].getStyle('visibility')];
                hide[i][j][0].setStyle('visibility', 'hidden');
              }
              catch(e)
              {
            	  APP.ERROR.Log('COM.Layer.Open() | ' + e);
              }
            }
          }
        }
      }

      scfx = scroll;

      if(event)
      {
        exfx = (typeof event == 'function') || (typeof event == 'string')? COM.GET.Function(event): null;
        opac.addEvent('click', exfx? exfx: this.close, 1);
      }

      numb = LYR.push(this);

      return (proc = false) || this.size();
    }

    //
    //  Hide the Layer. Note that the 4th argument of .Layer.Open() will not take effect if you
    //  call this routine manually.
    //

    this.close = function()
    {
      if(proc)
      {
        return COM.Log('.Layer['+ numb +'].close: double process: '+proc);
      }

      proc = 'close';

      if (scfx)
      {
        var x = temp.getXPos(),
            y = temp.getYPos();
      }
      
      while(LYR.length > numb)
      {
        COM.Log('LYR.pop!!');
        LYR.pop().close();
      }
      LYR.pop();

      var mySelf = this;
      self.delEvent('resize', function(){mySelf.size()}, 1);

      for(var i=0, n=hide.length; i!=n; ++i)
      {
        for(var j=0, m=hide[i].length; j!=m; ++j)
        {
          try
          {
            hide[i][j][0].setStyle('visibility', hide[i][j][1]);
          }
          catch(e)
          {
        	  APP.ERROR.Log('COM.Layer.Close() | ' + e);
          }
        }
      }

      hide = [];

      while(elem = temp.firstChild)
      {
        try
        {
          temp.removeChild(elem);
          BODY.appendChild(elem);
        }
        catch(e)
        {
          COM.Log('COM.Layer.close(); '+e);
          break;
        }
      }

      try
      {
        BODY.removeChild(opac);
        BODY.removeChild(temp);
      }
      catch(e)
      {
        ;
      }

      temp.style.width  = opac.style.width  = '';
      temp.style.height = opac.style.height = '';

      temp.style.overflow = '';

      opac.delEvent('click', this.close, 1);
      if (scfx)
      {
        self.scrollTo(x,y);
      }
      return !(proc = false);
    }

    //
    //  Just like WIZARD: will get done automatically.
    //

    this.size = function()
    {
      if(proc)
      {
        return COM.Log('.Layer['+ numb +'].size: double process'+proc);
      }

      proc = 'size';

      var mySelf = this;
      self.delEvent('resize', function(){mySelf.size()}, 1);

      var w = BODY.getWidth(),
          h = BODY.getHeight();

      if(scfx)
      {
        var x = BODY.getXPos(),
            y = BODY.getYPos();

        temp.style.width  = opac.style.width  = w.toString() +'px';
        temp.style.height = opac.style.height = h.toString() +'px';

        if(temp.style.overflow != 'hidden')
        {
          temp.style.position = 'absolute';
          temp.style.overflow = 'hidden';

          temp.style.left = '0px';
          opac.style.top  = '0px';

          temp.scrollLeft = x;
          temp.scrollTop  = y;
        }
      }
      else
      {
        temp.style.position =
        opac.style.position = 'absolute';

        opac.style.left = temp.style.left = '0px';
        opac.style.top  = temp.style.top  = '0px';

        (temp.getWidth()  >= w) || temp.setStyle('width',  w = w? w +'px': '100%'); opac.setStyle('width',  temp.getWidth()  +'px');
        (temp.getHeight() >= h) || temp.setStyle('height', h = h? h +'px': '100%'); opac.setStyle('height', temp.getHeight() +'px');
      }

      self.addEvent('resize', function(){mySelf.size()}, 1);
      return !(proc = false);
    }

    //
    //  Just like WIZARD: return hidden elements.
    //

    this.hidden = function()
    {
      return hide;
    }
    
    //
    //  Internals.
    //

    var opac = null,
        temp = null,
        numb = 0,
        proc = false,
        elem = null,
        hide = [],
        exfx = null,
        scfx = null;

    //
    //  IE isn't nice, but maybe there's a more simple way to do all this resizing stuff...
    //  Actually we decided to make it instantiateable, but: stack handling for more than 2
    //  simultaneous open ones is very bad.
    //

  }

  //
  //  Constructor for elements. The most useful part here. Most behavior - what to do
  //  which kinds and count of arguments to pass etc... is not defined yet - so it is
  //  still able to become more usefull...
  //

  this.Element = function(a)
  {
    try
    {
      if((a.nodeName && a.cloneNode) || a.isString())
      {
        return COM.GET.Elem(a);
      }

      var name = '.Element('+typeof a+'); ';

      if(!a.isArray())
      {
        return COM.Log(name+'arg?')
      }

      var l, e, k, h, s, p, x, y, z, v = [], c = document;

      if(a.length == 1)
      {
        return c.createTextNode(a[0]);
      }
      else
      {
        e = c.createElement(a[0]);
        
        if(document.body)
        {
          document.body.appendChild(e);  COM.GET.Elem(e);
          document.body.removeChild(e);
        }
        else
        {
          COM.GET.Elem(e);
        }

        if(a[1])
        {
          if(typeof(a[1]) == 'object')
          {
            for(h in a[1])
            {
              if(typeof h != 'string')
              {
                continue;
              }

              switch(h.toLowerCase())
              {
                case 'disabled':

                  e.disabled = a[1][h] && (a[1][h] != 'false');
                  break;

                case 'class':

                  e.setClass(a[1][h]);
                  break;

                case 'id':

                  e.setAttribute('id', e.id = a[1][h].toString());
                  break;

                case 'style':

                  s = a[1][h].split(';');

                  for(var i=0, m=s.length; i!=m; ++i)
                  {
                    try
                    {
                      s[i] && (p = s[i].split(':'));

                      if(p[0].match('-'))
                      {
                        x = p[0].split('-');
                        z = x[0];

                        for(y=1, n=x.length; y!=n; ++y)
                        {
                          z += x[y].substr(0,1).toUpperCase() + x[y].substring(1);
                        }

                        p[0] = z;
                      }

                      e.setStyle(p[0], p[1]);
                    }
                    catch(e)
                    {
                      COM.Log(name+'invalid style: '+e);
                    }
                  }

                  break;

                default:

                  if(h.match(/^on/))
                  {
                    a[1][h] && v.push([h.replace(/^on/, ''), a[1][h]]);
                  }
                  else
                  {
                    try
                    {
                      e.setAttribute(h, a[1][h]);
                    }
                    catch(e)
                    {
                      COM.Log(name+'.setAttribute: '+e)
                    }
                  }
              }
            }
          }
          else
          {
            COM.Log(name+'invalid attibutes/argument2 @'+i);
          }
        }

        if(a[2])
        {
          if(a[2].isString())
          {
            e.appendChild(c.createTextNode(a[2]));
          }
          else
          {
            if(a[2].isArray())
            {
              for(var i=0, n=a[2].length; i!=n; ++i)
              {
                try
                {
                  e.appendChild(COM.Element(a[2][i]));
                }
                catch(err)
                {
                  COM.Log(name+'.appendChild: '+err);
                }
              }
            }
            else
            {
              COM.Log(name+'invalid childs/argument3');
            }
          }
        }

        for(var i=0, n=v.length; i!=n; ++i)
        {
          e.addEvent(v[i][0], v[i][1]);
        }
      }

      return COM.GET.Elem(e);
    }
    catch(err)
    {
      return COM.Log(name, err);
    }
  }

  //
  //  Binds JavaScript sources you need NOW.
  //

  this.Require = function(jsUrl)
  {
    var name = 'COM.Require('+jsUrl+'); ';

    if(SRC[jsUrl])
    {
      return COM.Log(name+SRC[jsUrl]);
    }

    COM.Execute((new COM.HTTP.Request('GET', jsUrl, {}, true)).start());
    return COM.Log(name+(SRC[jsUrl]='bound by require'));
  }

  //
  //  Bind JavaScript which has a callback, use it as preloader or simply bind css...
  //

  this.Include = function(url, isCss)
  {
    var name = 'COM.Include('+url+'); ';

    if(SRC[url])
    {
      return COM.Log(name+SRC[url]);
    }

    HEAD || COM.GET.Head();
// temporary Bugfix for IE: Problems with COM.Element at this point
//    HEAD.appendChild(COM.Element(isCss? ['link',   {'rel':'stylesheet','type':'text/css','href':url}]:
//                                        ['script', {'type':'text/javascript','src':url}]));
    if (isCss)
    {
      var node = document.createElement('link');
      node.href = url;
      node.rel = 'stylesheet';
      node.type = 'text/css';
    }
    else
    {
      var node = document.createElement('script');
      node.src = url;
      node.type = 'text/javascript';
  	}
    HEAD.appendChild(node);

    return true;
  }

  //
  // Execute Javascript contained into a source string.
  //

  this.Execute = function(source)
  {
    try
    {
      self.execScript(source);
    }
    catch(e)
    {
      try
      {
        var node = COM.Element(['script', {'type':'text/javascript'}]);
        node.appendChild(document.createTextNode(source));
        COM.GET.Head().appendChild(node);
      }
      catch(e)
      {
        if(typeof node.text != 'string')
        {
          return COM.Log('COM.Require([source]); '+e);
        }

        node.text = source;
      }
    }

    return true;
  }

  //
  //  Write yourself a note.
  //

  this.Log = function()
  {
    arguments[0].message || (arguments[0] = arguments[0].toString().replace(/^\./, 'COM.'));

    var text = [];

    for(var i=0, n=arguments.length; i!=n; ++i)
    {
      text.push(arguments[i] && arguments[i].message? arguments[i].message: arguments[i]);
    }

    LOG.push(text.join(': '));
    DEBUG && DEBUG(text);
    
    try
    {
    	APP.ERROR.Log(text.join(': '), 0, 0);
    }
    catch(e)
    {
    	window.setTimeout(function(){APP.ERROR.Log(text.join(': '), 0, 0);}, 100);
    }

    return 0;
  }

  //
  // That's the COM. Read so single comments to get an overview of what you need and want to do.
  //

}

//
// COM.HTTP for ajax requests.
//

COM.HTTP = new function()
{

  //
  // Often used methods post and get.
  //

  this.Post = function(url, params, synchron) { var request = new COM.HTTP.Request('POST', url, params); return self.setTimeout(' COM.HTTP.Execute('+ request.getId() +'); ', 1); }
  this.Get  = function(url, params, synchron) { var request = new COM.HTTP.Request('GET',  url, params); return self.setTimeout(' COM.HTTP.Execute('+ request.getId() +'); ', 1); }

  //
  // Request object to handle ajax calls with get or post. You can use a synchron or asynchron call. 
  //

  this.Request = function(method, url, params, synchron)
  {

    //
    // validate and prepare your arguments.
    //
	params && (params = COM.GET.Elem(params));
    if(!(params && params.isObject()))
    {
      COM.Log('params will nicht', typeof params);
      params = COM.GET.Elem({});
    }

    for(var i=0, n=EVENTS.length; i!=n; ++i)
    {
      if(params['on'+ EVENTS[i]])
      {
        params['on'+ EVENTS[i]] = COM.GET.Function(params['on'+ EVENTS[i]]);
      }
    }

    method = (typeof method == 'string') && (method.toUpperCase() == 'POST')? 'POST': 'GET';

    //
    // execute ajax request.
    //

    this.start = function()
    {
      xmlreqfx || (xmlreqfx = new COM.HTTP.Object());

      xmlreqfx.open(method, url, !synchron);

      if(method == 'POST')
      {
        xmlreqfx.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

        if(params.vars)
        {
          xmlreqfx.setRequestHeader('Content-length', params.vars.length);
        }
        else
        {
          params.vars = null;

          xmlreqfx.setRequestHeader('Content-length', '0');
          xmlreqfx.setRequestHeader('Connection', 'close');
        }
      }

      if(!synchron)
      {
        var my = this;
        xmlreqfx.onreadystatechange = function() { my.handle(); }
        xmlreqfx.send(params.vars)
        return true;
      }
      else
      {
        xmlreqfx.send(params.vars);
        return this.setResponse();
      }
    }

    //
    // callback for ajax state.
    //

    this.handle = function()
    {
      if(xmlreqfx.readyState == 4)
      {
        this.setResponse();
      }
      else
      {
        if(params['on'+ EVENTS[xmlreqfx.readyState]])
        {
          params['on'+ EVENTS[xmlreqfx.readyState]]();
        }
      }
    }

    //
    // request is finished, set response now.
    //

    this.setResponse = function()
    {
      response = params.xml? xmlreqfx.responseXML? xmlreqfx.responseXML.documentElement: null: xmlreqfx.responseText;
      response = params.json? eval('(' + response + ')'):response;
      if(params.onfinish)
      {
        params.onfinish(response);
      }

      return response;
    }

    //
    // abort request and reset stored events.
    //

    this.abort = function()
    {
      for(var i=0, n=EVENTS.length; i!=n; ++i)
      {
        (params['on'+ EVENTS[i]]) && (params['on'+ EVENTS[i]] = null);
      }
      return xmlreqfx && (xmlreqfx.abort() || 1);
    }

    //
    // get request identity.
    //

    this.getId = function() { return identity; }

    //
    // Privates holding references.
    //

    var identity = INDENT.push(this) -1,
        response = null,
        xmlreqfx = null;

    //
    // In most cases should be ok if you use COM.HTTP.Get and COM.HTTP.Post. If you really need the request object to
    // abort in some cases create an own instance of COM.HTTP.Request.
    //

  }

  //
  // Internals.
  //

  var EVENTS = COM.GET.Elem(['begin','load','loading','interactive','finish','abort']),
      INDENT = COM.GET.Elem([]);

  //
  // Execute request by index.
  //

  this.Execute = function(index) { INDENT[index].start(); }

  //
  // Gives Request object.
  //

  this.Object = function()
  {
    try
    {
      return new XMLHttpRequest();
    }
    catch(e)
    {
      try { return new ActiveXObject("Msxml2.XMLHTTP");    } catch(e) {
      try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch(e) { return COM.Log('.HTTP.Object', e); }}
    }

    return true
  }

  //
  // COM.HTTP offers all functions you need for ajax requests nd response handling. Look at the methods to find
  // out your best way.
  //

}

//
// Url hashing.
//

COM.HASH = new function()
{

  //
  // Initialize it, add hidden Iframe for IE, for other add it to url only.
  //
	
  this.Init = function(hash)
  {
    if (Browser.IE && !H)
    {
      H = COM.Element(['iframe', {'style':'display:none;','id':'COMHASHFrame'}]);
      COM.GET.Body().appendChild(H);

      var W = H.contentWindow.document;
      W.open();

      if (typeof hash != 'undefined' && hash != '')
      {
         W.location.replace(W.location+'#'+hash);
      }
      else
      {
         W.location.hash = '#'+document.location.hash.replace(/#/, '');
      }
      W.close();
    }
    return true;
  }

  //
  // Get hash from url and possible store internal.
  //
	
  this.Get = function(store)
  {
      H || this.Init();

      var hash = H ? H.contentWindow.document.location.hash.replace(/#/, '') : document.location.hash.replace(/#/, '');

      if (store || typeof store == 'undefined')
      {
         C = hash;
      }

      return hash;
  }

  //
  // Set url hash.
  //

  this.Set = function(hash)
  {
    hash && (hash = '#'+hash);
      
    C = hash; 
      
    if (H)
    {
      var W = H.contentWindow.document;
      W.open();
      W.close();
      W.location.hash = hash;
    }
    else
    {
      document.location.hash = hash;
      this.Init(hash);
    }
    
    return true;
  }

  //
  // Register function which is excecuted when hash changes. Check changes with (I)nterval.
  //

  this.Reg = function(f, r)
  {
    f && (F = COM.GET.Function(f));
    R = r;
    I || (F && (I = window.setInterval('COM.HASH.Check()', 200)));

    return true;
  }

  //
  // Check hash if changed.
  //

  this.Check = function()
  { 
	var hash;

    if (I && C != (hash = this.Get(false)))
    {
      if (hash != '')
      {
        C = '#'+hash; //document.location.hash =
        if (!Browser.IE & !Browser.Opera)
        {
          document.location.hash = C;
        }

        (typeof F == 'function') && F();
        return true;
      }
      else if (R)
      {
        window.clearInterval(I);
        document.location.href = document.location.href.substr(0, document.location.href.indexOf('#'));
        if (!Browser.IE)
        {
          document.location.reload();
        }
      }
    }

    return false;
  }
	
  //
  // private vars.
  //

  var I = null,
      C = '',
      F = null,
      R = true,
      H = null;

  //
  //
  //
  
}

//
// Sidebar on the right of the page.
//

COM.SIDEBAR = new function()
{

  //
  // Open sidebar element and adds it to DOM when not added. Main node containing page is given to calulate
  // overlapping on resize.
  //

  this.Open = function(content, max, node)
  {
    Cont || (Cont = COM.Element(['div',{'class':'COMElement COMSidebar'}]));

    if (typeof node == 'undefined')
    {
    	var n = COM.GET.Body().firstChild;
    	while(n)
    	{
    		if (n.nodeType == 1)
    		{
    			break;
    		}

    		n = n.nextSibling;
    	}
    }
    Main = node;
    
    COM.GET.Body().hasClass('COMSidebarActive') || COM.GET.Body().insertBefore(Cont, COM.GET.Body().firstChild);
    COM.GET.Body().addClass('COMSidebarActive');
    COM.GET.Body().hasClass('COMSidebarLoad') && COM.GET.Body().delClass('COMSidebarLoad');
    
    if (true || Browser.IE6)
    {
    	Cont.setStyle('position', 'absolute');
    	COM.SCROLL.Deactivate();
    }
    else
    {
    	Cont.setStyle('position', 'fixed');
    	Cont.setStyle('bottom', '0px');
    }
    
    Cont.setStyle('right', '0px');
    Cont.setStyle('top', '0px');

    if(	content &&
    	content != Cont.firstChild	)
    {
      while(Cont.firstChild)
      {
        Cont.removeChild(Cont.firstChild);
      }

      Cont.appendChild(COM.Element(content));
    }

    return (max && this.Maximize()) || this.Minimize();
  }

  //
  // Close sidebar and removes elements from DOM.
  //

  this.Close = function()
  {
	try
	{
	  Main.delLeft();

	  COM.GET.Body().delClass('COMSidebarActive');

      return COM.GET.Body().removeChild(Cont);
	}
	catch(ex)
	{
		APP.ERROR.Log('COM.SIDEBAR.Close() | ' + ex);
	}
  }

  //
  // Maximize sidebar to absolute page height not window height.
  //

  this.Maximize = function()
  {
	if (COM.GET.Body().hasClass('COMSidebarActive'))
	{
      Cont.delClass('COMSidebarMinimum');
      Cont.addClass('COMSidebarMaximum');
    
      width = Cont.getWidth();

      return this.Size();
	}
  }

  //
  // Minimize sidebar to element length.
  //

  this.Minimize = function()
  {
	if (COM.GET.Body().hasClass('COMSidebarActive'))
	{
      Cont.delClass('COMSidebarMaximum');
      Cont.addClass('COMSidebarMinimum');
    
      width = Cont.getWidth();

      return this.Size();
	}
  }

  //
  //  Usually, there's no need to call this routine. It's in window.onresize queue as soon as
  //  you've called .SIEBAR.Open().
  //

  this.Size = function()
  {
    if (!Cont)
    {
  	  return false;
    }

    if (
    		COM.GET.Body().hasClass('COMSidebarActive') && 
    		(	self.getWidth() < (Main.getWidth() + width)	)
    	)
    {
      COM.SIDEBAR.Close();
    }
    else
    {
      if (!COM.GET.Body().hasClass('COMSidebarActive'))
      {
        return COM.SIDEBAR.Open(null, Cont.hasClass('COMSidebarMaximum'), Main);
      }

      if(true || Browser.IE6)
      {
    	  (Cont.hasClass('COMSidebarMaximum') && Cont.setHeight(self.getAbsHeight())) || Cont.delHeight();    	  
      }
    
      Main.setStyle('position', 'relative');
      Main.setLeft((-1)*Cont.getWidth()/2);
    }

    return true;
  }
  
  //
  // Privates holding references.
  //

  var Cont,
      Main,
      width;

  //
  //  Especially if there are many elements in the root of the DOM, the sidebar behaves not like expected.
  //  So it's recommended to use a <div> or whatelse around the documents main nodes...
  //

}

COM.SCROLL = new function()
{
	var Me = this,
		scrollbar_active = true,
		scrollbar_init = false,
		scrollbar_enabled = false,
		
		node_body = document.body,
		
		scroll_container,
		scroll_content,
		scroll_content_overflow,
		scroll_bar,
		scroll_handle,
		scroll_handle_size,
		scroll_handle_range,
		
		timeout_id,
		cursor_offset;
	
	//
	//
	//
	
	this.Init = function()
	{
		//Do not initialize scrollbar if deactivated
		if (scrollbar_active === false)
		{
			return false;
		}
		
		//only init elements once
		if(scrollbar_init === true)
		{
			return this.SetDimensions();
		}
		
		scroll_content = $('all_trv_sidebar');
		scroll_container = scroll_content.parentNode;
		
		//append scrollbar to sidebar
		scroll_bar = COM.Element(['div',{'class':'Scrollbar'}]);
		scroll_bar.setStyle('display', 'none');
		scroll_container.appendChild(scroll_bar);
		
		//append handle to scrollbar
		scroll_handle = COM.Element(['div',{'class':'Handle gradient_bright'}]);
		scroll_bar.appendChild(scroll_handle);
		
		scrollbar_init = true;
		
		return this.SetDimensions();
	}
	
	//
	//
	//
	
	this.Deactivate = function()
	{
		scrollbar_active = false;
	}
	
	//
	//
	//
	
	this.SetDimensions = function()
	{
		if(scrollbar_init === false)
		{
			return this.Init();
		}
		
		var content_size = scroll_content.getHeight() * 100 / scroll_container.getHeight();
		
		//Hide scrollbar if content is smaller than 100% of the container size 
		if(content_size <= 100)
		{
			return this.Disable();
		}
		
		scroll_content_overflow = scroll_content.getHeight() - scroll_container.getHeight();
		if (content_size <= 100)
		{
			scroll_handle_size = 100;
		}
		else
		{
			scroll_handle_size =  100 / (content_size / 100);
			if (scroll_handle_size < 10)
			{
				scroll_handle_size = 10;
			}
		}
		
		scroll_handle.style.height = scroll_handle_size + '%';
		
		return this.Enable();
	}
	
	//
	//
	//
	
	this.Enable = function()
	{
		if(scrollbar_init === false)
		{
			return this.Init();
		}
		else if(scrollbar_enabled === true)
		{
			return scrollbar_enabled;
		}
		
		this.SetFocus(false);
		
		scroll_bar.addEvent('mouseover',  function(){	Me.SetFocus(true); Me.Appear();	});
		scroll_bar.addEvent('mouseout',  function(){	Me.SetFocus(false); Me.Appear(true); 	});
		scroll_handle.addEvent('mousedown', 	function(act){		Me.MouseDown(act);	});
		
		if (scroll_content.attachEvent)
		{
			scroll_content.attachEvent("onmousewheel", function(act){	return Me.MouseWheel(act);	});
		}
		else if (scroll_content.addEventListener)
		{
			// Firefox
			if(Browser.Gecko)
			{
				scroll_content.addEventListener('DOMMouseScroll', function(act) {	return Me.MouseWheel(act); }, false);				
			}
			// Internet Explorer, Opera, Google Chrome and Safari
			else
			{
				scroll_content.addEventListener('mousewheel', function(act) {	return Me.MouseWheel(act); }, false);				
			}
		}
		
		return scrollbar_enabled = true;
	}
	
	//
	//
	//
	
	this.Disable = function()
	{
		if(scrollbar_enabled === false)
		{
			return scrollbar_enabled;
		}
		
		this.SetFocus(true);
		
		scroll_bar.delEvent('mouseover',  function(){	Me.SetFocus(true); Me.Appear();	});
		scroll_bar.delEvent('mouseout',  function(){	Me.SetFocus(false); Me.Appear(true); 	});
		scroll_handle.delEvent('mousedown', 	function(act){		Me.MouseDown(act);	});
		
		this.Hide();
		
		return scrollbar_enabled = false;
	}
	
	//
	//
	//
	
	this.MouseWheel = function(action)
	{
		if (scrollbar_enabled === false)
		{
			return true;
		}
		
		action = window.event || action;
		
		var pos,
			direction,
			offset;
		
		direction = (action.wheelDelta) ?  action.wheelDelta*(-1) : action.detail;
		
		this.Appear(true);
		
		if(direction > 0) //scroll down
		{
			pos = scroll_handle.getTop() + 50;
		}
		else //scroll up
		{
			pos = scroll_handle.getTop() - 50;
		}
		
		scroll_handle_range = scroll_bar.getHeight() - scroll_handle.getHeight();
		offset = pos * 100 / (scroll_bar.getTop() + scroll_handle_range);
		
		this.SetScrollPosition(offset);
		
		//disable default wheel action of scrolling page
	    if (action.preventDefault)
	    {
	        action.preventDefault();
	    }
	    
	    return false;
	}
	
	//
	//
	//
	
	this.MouseDown = function(action)
	{
		var itsMe = this;
		
		document.onselectstart = new Function('return false');
		node_body.addClass('noselect');
		scroll_content.addClass('noselect');
		document.addEvent('mousemove',	function(act){		itsMe.MoveHandle(act);	});
		document.addEvent('mouseup',	function(){		itsMe.MouseUp();	});
		
		if (action.pageY)
		{
		    cursor_offset = action.pageY - scroll_handle.getTop();
		}
		else if (action.clientY)
		{
			cursor_offset = action.clientY + document.body.scrollTop + document.documentElement.scrollTop - scroll_handle.getTop();
		}
		
		this.MoveHandle(action);
		
		return false;
	}
	
	//
	//
	//
	
	this.SetFocus = function(focus)
	{
		if (focus === true)
		{
			scroll_content.delEvent('mouseover',  function(){	Me.Appear(true);	});
		}
		else
		{
			scroll_content.addEvent('mouseover',  function(){	Me.Appear(true);	});
		}
	}
	
	//
	//
	//
	
	this.MouseUp = function()
	{
		var itsMe = this;
		
		document.delEvent('mouseup', 		function(){		itsMe.MouseUp();	});
		document.delEvent('mousemove', 	function(act){	itsMe.MoveHandle(act);		});
		scroll_content.delClass('noselect');
		node_body.delClass('noselect');
		document.onselectstart = '';
	
		return false;
	}
	
	//
	//
	//
	
	this.MoveHandle = function(action)
	{
		var pos,
			offset = 0;

		if (action.pageY)
		{
		    pos = action.pageY;
		}
		else if (action.clientY)
		{
		    pos = action.clientY + document.body.scrollTop + document.documentElement.scrollTop;
		}
		
		//Set handle top position and relative offset
		pos = pos - cursor_offset;
		scroll_handle_range = scroll_bar.getHeight() - scroll_handle.getHeight();
		offset = (pos - scroll_bar.getTop()) * 100 / (scroll_bar.getTop() + scroll_handle_range);
		
		this.SetScrollPosition(offset);
	}
	
	//
	//
	//
	
	this.SetScrollPosition = function(offset)
	{
		if (offset > 100)
		{
			offset = 100;
		}
		else if(offset < 0)
		{
			offset = 0;
		}
		
		scroll_handle.style.top = Math.round(scroll_handle_range / 100 * offset) + 'px';
		scroll_content.style.marginTop = '-' + Math.round(scroll_content_overflow / 100 * offset) + 'px';		
	}
	
	//
	//
	//
	
	this.Appear = function(toggle)
	{
		toggle = (typeof toggle != 'undefined') ? toggle : false;
		(timeout_id) && (window.clearTimeout(timeout_id));
		
		scroll_bar.setStyle('opacity', 100);
		scroll_bar.appear();
		
		if (toggle == true)
		{
			timeout_id = window.setTimeout(function(){Me.Hide();}, 600);
		}
		
		return true;
	}
	
	//
	//
	//
	
	this.Hide = function()
	{
		if (typeof obj_fading != 'undefined')
		{
			obj_fading.Abort();
		}
		(timeout_id) && (window.clearTimeout(timeout_id));
		
		obj_fading = new APP.EFFECT.Fading(scroll_bar, true, {'duration':1, 'onfinish':function(){scroll_bar.disappear();}});		
		
		return false;
	}
}

//
// Instantiate a menu connected to an ul element. Define position to given left and top and define witdh of menu.
// A parent node can be given or the ul is it's parent. This special ul is extended with some functions.
//

COM.Menu = function(left, top, width, parent)
{
  var x =  left? (typeof  left == 'function'?  left: function() { return  left }): function() { if(m = COM.GET.Elem(ul.parentNode.parentNode)) return ul.setLeft(m.getWidth() - 15); },
      y =   top? (typeof   top == 'function'?   top: function() { return   top }): function() { if(m = COM.GET.Elem(ul.parentNode)) return ul.setTop(m.getTop() + 5); },
      w = width? (typeof width == 'function'? width: function() { return width }): null,
      
      m, ul = COM.Element(['ul',{'class':'COMElement COMMenuContainer'}]), j = 'var t=';  parent || (parent = ul);

  //
  // create a clickable entry.
  //

  function Entry(text, exec)
  {
    exec = exec.match(/^javascript\:/)? {'href':'javascript:COM.Void();', 'onclick':(m = exec.substring(11))}:
                                        {'href':exec,                     'onclick':function() { ul.disappear(1); }};

    return COM.Element(['li',{'style':'display:inline;', 'class':('COMElement COMMenu'+(m && m.match(/^[\/]/)? 'ListEnd': 'SubList'))}, [['a', exec, text]]]); 
  }

  //
  // Add iteration of classes with even and uneven in childNodes.
  //

  ul.parade = function()
  {
    for(var i=0, n=ul.childNodes.length; i<n; ++i)
    {
      ul.childNodes[i].firstChild.setClass('COMElement COMMenu'+(i%2? 'Even': 'UnEven'));
    }

    return true;
  }

  //
  // Get count of entries.
  //

  ul.getCount = function()
  {
    return ul.childNodes.length;
  }

  //
  // Insert new entry at the beginning.
  //

  ul.insert = function(text, exec)
  {
    var li = new Entry(text, exec);

    ul.firstChild? ul.insertBefore(li, ul.firstChild):
                   ul.appendChild(li);

    return ul.parade();
  }

  //
  // Insert new entry at the end.
  //

  ul.append = function(text, exec)
  {
    var i = ul.childNodes.length, li = new Entry(text, exec);
    li.firstChild.setClass('COMElement COMMenu'+(i%2? 'Even': 'UnEven'));
    return ul.appendChild(li);
  }

  //
  // Remove entry.
  //

  ul.remove = function(index)
  {
    return ul.removeChild(ul.childNodes[index]);
  }

  //
  // Replace entry by another one.
  //

  ul.replace = function(index, text, exec)
  {
    m = new Entry(text, exec);
    m.firstChild.setClass(ul.childNodes[index].getClass());
    m = ul.replaceChild(m, ul.childNodes[index]);
    return m;
  }

  //
  // Resize complete menu.
  //

  ul.resize = function()
  {
    ul.moveTo(x(), y());
    w && ul.setWidth(w());
    return true;
  }

  //
  // Overrides Element disappear().
  // A complete menu disappears, posible recursive, so element disappear is not enough in that case.
  //

  ul.disappear = function(recursive)
  {
    if($(ul.parentNode.firstChild).nodeName == 'A')
    {
      ul.parentNode.firstChild.delClass('COMMenuActive');
    }

    ul.setStyle('display', 'none');

    if(recursive && ul.parentNode.parentNode && $(ul.parentNode.parentNode).hasClass('COMMenuContainer'))
    {
      return ul.parentNode.parentNode.disappear();
    }

    return true;
  }

  //
  // Overrides Element appear().
  // Appear with possible layer and handle when click happens on layer.
  //

  ul.appear = function(layer, handle)
  {
    ul.parentNode && ul.parentNode.parentNode &&
    ul.parentNode.parentNode.appear &&
    ul.parentNode.parentNode.appear();

    for(var i=0, n=ul.childNodes.length; i!=n; ++i)
    {
      (ul.childNodes[i].childNodes.length > 1) &&
       ul.childNodes[i].childNodes[1].disappear();
    }

    if($(ul.previousSibling) && ul.previousSibling.nodeName == 'A')
    {
      ul.previousSibling.addClass('COMMenuActive');
    }

    if(layer)
    {
      ul.layer || (ul.layer = new COM.Layer());
      ul.layer.open(false, 0, layer > 50? layer: 85, handle? handle: function() { ul.disappear(); ul.layer.close(); });

      try { COM.GET.Body().removeChild(ul); } catch(e) {}
            COM.GET.Body().appendChild(ul);
    }

    ul.setStyle('display', 'block');
    return ul.resize();
  }

  //
  // Let parent alternate visibility of the sub menu.
  //

  ul.alternate = function(link, menu)
  {
    COM.GET.Elem(link.parentNode).appendChild(menu);

    link.delEvent('onclick');
    link.addEvent('onclick', function(e,n) { n.nextSibling.toggle(); });

    return true;
  }

  //
  // Return internal created extended ul.
  //

  return ul;

  //
  // A nice tool to generate menus with dynamic content. The main object is really simple, the different usage
  // is added to the returned ul.
  //

}

//
//  We end like we've opened: with neccessary overhead.
//

COM.Void = function() {}

//
//  Reporting that we're taking over control now,
//  then defining a shortener for COM.
//

function $()
{
  if(arguments.length == 1)
  {
    return COM.GET.Elem(arguments[0]);
  }

  for(var i=0, n=arguments.length; i<n; ++i)
  {
    arguments[i] = COM.GET.Elem(arguments[i]);
  }

  return COM.GET.Elem(arguments);
}

//
//  Our applications main class.
//  Requires COM and is also a wrapper for it - providing individual features/addons.
//  Contains also special effects and some global handling where a single class isn't
//  really neccessary.
//

var APP = new function()
{

  //
  //
  //

  this.InnerExec = function(data)
  {
    var elems = COM.GET.All('script', APP.Element('<br />'+ data));
    for(var i=0, n=elems.length;i<n;i++)
    {
		try
		{
			eval(elems[i].innerHTML);
		}
		catch(e)
		{
			COM.Log('APP.InnerExec failed while executing \''+elems[i].innerHTML+'\' '+e.message);
		}
    }

    return true;
  }


  //
  //  Nearly equiv to the former jsapi.
  //  Can dynamical reload and handle sources.
  //

  this.RUN = new function()
  {

    //
    //  Initializing, no need to call manually.
    //

    this.Start = function(f)
    {
      if (!P)
      {
        P = true;
        window.delEvent('DOMContentLoaded', function(){APP.RUN.Start();});
        this.Call("_self");
      }
    }

    //
    //  Main access: define an [o]bject/package that's required (e.g. 'trivago.form') and - maybe -
    //  some other [p]arameters as hash, e.g 'onfinish':function(){eval(anything);}.
    //

    this.Exe = function(o, p)
    {
      p || (p = {});

      if(!P)
      {
        return this.Reg("_self", function(){APP.RUN.Exe(o, p);});
      }

      p["onfinish"] && this.Reg(o, p["onfinish"]);

      if(!((F[o] === true) || J[o]))
      {
        if(o == 'google.maps3')
        {
          COM.Include("http://maps.google.com/maps/api/js?key="+p["key"]+"&sensor="+p['sensor']+"&libraries=geometry&language="+p['language']+"&region="+p['region']+"&callback="+p['onfinish']);
        }
        else if(o.substr(0, o.indexOf('.')) == 'google')
        {
          if(o == "google.jsapi")
          {
            COM.Include("http://www.google.com/jsapi?key="+p["key"]+"&callback=google_api");
          }
          else
          {
            if(F["google.jsapi"] && typeof google != "undefined")
            {
              try
              {
            	  google.load(o.substr(o.indexOf(".")+1, o.length), p["version"], {"language":"es", "callback":function(){APP.RUN.Call(o)}});
              }
              catch(e)
              {
                COM.Log('google: '+e);
              }
            }
            else
            {
              this.Exe("google.jsapi", {"key":p["key"], "onfinish":function(){APP.RUN.Exe(o, p);}});
            }
          }
        }
        else if (typeof APP.Retrieve('js_domain') != 'undefined' && typeof APP.Retrieve('release_version') != 'undefined')
        {
          COM.Include(APP.Retrieve('js_domain')+"/js_"+o.substr(o.indexOf(".")+1, o.length)+"_"+APP.Retrieve('release_version')+".js");
        }

        return true;
      }

      return this.Call(o);
    }

    //
    //  To register [f]unctions that are getting called as soon as an [o]bject's loaded successfully.
    //  They're getting called in the same order as they have been registered. "onfinish" of .Exe is
    //  simply the same...
    //

    this.Reg = function(o, f)
    {
      (typeof F[o] == 'object') || (F[o] = []);
      f && F[o].push(COM.GET.Function(f));
      return true;
    }

    //
    //  Callback for included sources and packages.
    //  Should not get called manually.
    //

    this.Call = function(o)
    {
      J[o] = 1;

      if(F[o] && (F[o] !== true))
      {
        for(var i=0, n=F[o].length; i!=n; ++i)
        {
          try
          {
            F[o][i]();
          }
          catch(e)
          {
            COM.Log('APP.RUN.Call['+i+']: '+e);
          }
        }
      }

      return F[o] = true;
    }

    //
    //  private vars
    //
    //  J: already done js
    //  F: stored functions to execute
    //  P: page loaded
    //

    var J = {}, P = false,
        F = {};

    //
    // set Events
    //

    window.addEvent('DOMContentLoaded', function(){APP.RUN.Start();});
    window.addEvent('load', function(){APP.RUN.Start();});

    //
    //  TODO:
    //  -> the package handling itself could get optimized & faster
    //  -> it isn't nesseccary to declare self.servername -
    //     the script should be able to detect the uri by it's own tag.
    //

  }

  //
  //  New version of our old speech bubble, much more comfortable: [url] of the data,
  //  reference to the [parent] element - done. the 2nd argument, [out], specifies if
  //  the bubble will stay after onmouseout event and get
  //

  this.Bubble = function(parent, out, url, param)
  {
	if('object' != typeof param)
	{
		param = {
				    'alignment' : param,
				    'addClass' : '',
				    'ID' : ''
			    };
	}
  	if('undefined' == typeof param.alignment)
  	{
  		param.alignment = 'left';
  	}
  	if('undefined' == typeof param.addClass)
  	{
  		param.addClass = '';
  	}
  	if('undefined' == typeof param.ID)
  	{
  		param.ID = '';
  	}
    if($(parent).bubble)
    {
      if(!(parent.bubble.active || parent.bubble.timeOut))
      {
        parent.bubble.active = true;
        window.setTimeout(function(){parent.bubble.appear()}, 300);
      }
      return false;
    }

    var addClass = 'SpeechBubble';
    if(('string' == typeof param.addClass) && ('' != param.addClass))
    {
    	addClass = 'SpeechBubble ' + param.addClass;
    }
    var div = null;
    if(('string' == typeof param.ID) && ('' != param.ID))
    {
    	div = COM.Element(['div', {'id': param.ID, 'class':addClass,'style':'display:none'}, [['div', {'class':'module'+(out?"":" default")}]]]);
    }
    else
    {
    	div = COM.Element(['div', {'class':addClass,'style':'display:none'}, [['div', {'class':'module'+(out?"":" default")}]]]);
    }
    COM.GET.Body().appendChild(div);

    parent.bubble = {

      'element': div,
      'request': new COM.HTTP.Request('GET', url, {
                     'onfinish': function()
                     {
                    	 parent.bubble.appear(arguments[0]);
                	     APP.InnerExec(arguments[0]);
                	     if('function' == typeof param.ajax_callback)
                	     {
                		     param.ajax_callback();
                		 };
                	 }}),
      'appear': function(content)
      {
        if(parent.bubble.timeOut)
        {
          return false;
        }

        if(content)
        {
          parent.bubble.request && (parent.bubble.request = null);
          div.lastChild.previousSibling.innerHTML = content;
        }

        if(parent.bubble.request)
        {
          if(parent.bubble.active)
          {
            parent.bubble.timeOut = window.setTimeout(function()
            {
              window.clearTimeout(parent.bubble.timeOut);
                                  parent.bubble.timeOut = null;

              parent.bubble.appear();

            }, 300);
          }

          return false;
        }

        if(Browser.IE6)
        {
          div.resizeTo(300, 1);
        }

        if(parent.bubble.active)
        {
          var absolute_top,
          	  absolute_left;

          div.appear();

          switch(param.alignment)
          {
          	case 'bottom' :
          		absolute_top = parent.getAbsTop() +  parent.getHeight();
          		absolute_left = parent.getAbsLeft();
          		break;

          	case 'left' :
          		if ((absolute_top = parent.getAbsTop() -div.getHeight() -10) < 0)
		        {
		         	absolute_top = 0;
		        }
		        if ((absolute_left = parent.getAbsLeft() -div.getWidth() -10) < 0)
		        {
		        	absolute_left = 0;
		        }
		        break;

          	case 'right' :
          		absolute_top = parent.getAbsTop();
          		absolute_left = parent.getAbsLeft() +  parent.getWidth() + 10;
          		break;
          }

          div.moveTo(absolute_left,
                     absolute_top);
        }
        if('function' == typeof param.appear)
	    {
		    param.appear();
		};

        return true;
      },
      'disappear': function()
      {
        window.clearTimeout(parent.bubble.timeOut);
        div.disappear();
        parent.bubble.active = null;

        if(out == 2)
        {
          parent.bubble.explode();
          OpenBubble = null;
        }
        if('function' == typeof param.disappear)
	    {
		    param.disappear();
		};

        return true;
      },
      'explode': function()
      {
        parent.bubble.timeOut && window.clearTimeout(parent.bubble.timeOut);
        parent.bubble.request && parent.bubble.request.abort();
        COM.GET.Body().removeChild(parent.bubble.element);
        return !(parent.bubble = null);
      },
      'active': true
    }

    if(!out)
    {
      parent.addEvent('mouseout', parent.bubble.disappear);
    }

   	if(out == 2)
   	{
   	  OpenBubble && OpenBubble.explode();
   	}
    OpenBubble = parent.bubble;

    parent.bubble.request.start();

    div.insertBefore(COM.Element(['div',{'class':'clear_both'}, ' ']), div.firstChild);

    if(out)
    {
    	div.insertBefore(COM.Element(['img', {'class':'closelink','onclick': parent.bubble.disappear,
		  'src': 'http://il1.trivago.com/images/layoutimages/dialog/x.gif',
		  'alt': 'Cerrar'
    	}]), div.firstChild);
    }

    div.appendChild(COM.Element(['div',{'class':'clear_both'}, ' ']));

    return parent.bubble;
  }

  //
  //  Holding last bubbles opened with "2" as 2nd param...
  //

  var OpenBubble = null;

  //
  //
  //

  this.Unbubble = function()
  {
  	return (OpenBubble && OpenBubble.disappear());
  }

  //
  //  Equiv to COM.WIZARD, that's able to load each step and to prepare the trivago layout.
  //  Merged with the old ScreenModule.
  //

  this.WIZ = new function()
  {
    //
    //  Initialize an onscreen form.
    //  If there's still an open one, it's [c]ontent will get replaced.
    //  NO [c]ontent means: let the big, nasty load-animation appear...
    //

    this.Open = function(c)
    {
      try
      {
        COM.WIZARD.Open(c? c: COM.Element(['div',{'style':'text-align:center;margin:50px;'},[['img',{'src':'http://il2.trivago.com/images/layoutimages/indicator_big.gif'}]]]));
        return 1 && (E={});
      }
      catch(e)
      {
        return COM.Log('APP.WIZ.Open(); '+e);
      }
    }

    //
    //  WTH could this routine do?
    //

    this.Close = function()
    {
      try
      {
      	this.Call('onclose');
        COM.WIZARD.Close();
      }
      catch(e)
      {
        return COM.Log('APP.WIZ.Close(); '+e);
      }
    }

    //
    // is wizward open?
    //
    this.IsOpen = function()
    {
    	return COM.WIZARD.IsOpen();
    }

    //
    //  Like Reg in .RUN - register [e]vent-handler,
    //  which means [f]unction routines or js-strings...
    //

    this.Reg = function(e, f)
    {
      try
      {
        E[e] || (E[e] = []);
        return E[e].push(COM.GET.Function(f));
      }
      catch(e)
      {
        return COM.Log('APP.WIZ.Reg(); '+e);
      }
    }

    //
    //  Run the queue for an [e]vent build with .Reg
    //

    this.Call = function(e)
    {
      if(typeof E[e] != 'undefined')
      {
        for (var i=0;i!=E[e].length;++i)
        {
          try
          {
            if(typeof E[e][i] == "function")
            {
              E[e][i]();
            }
          }
          catch(e)
          {
            return COM.Log('APP.WIZ.Call(); '+e);
          }
        }
      }
    }

    //
    //  Std onscreen module layout - [s]tring or html-node content (.Element),
    //  optional [l]ayout-type which has to be defined extern in css.
    //

    this.Module = function(s,l)
    {
      try
      {
        if(typeof s == 'string')
        {
          var n1 = COM.Element(['div',{'class':'message'}]);
          n1.innerHTML = s;
        }
        else if (s.isElement())
        {
          n1 = s;
        }
        else
        {
          n1 = COM.Element(s);
        }

        var n2 = COM.Element(['div',{'class':'mod_body'}, [['img',{'src':'http://il1.trivago.com/images/layoutimages/dialog/x.gif','class':'closelink','alt':'Cerrar','title':'Cerrar','onclick':'APP.WIZ.Close();'}]]]);
        n2.appendChild(n1);

        var n1 = COM.Element(['div',{'class':'module '+l}]);
        n1.appendChild(n2);

        return this.Open(n1);
      }
      catch(e)
      {
        return COM.Log('APP.WIZ.Module(); '+e);
      }
    }

    //
    //  Let the user make a coice.
    //  [p]arams: headline, message
    //

    this.Question = function(p)
    {
      try
      {
             if(p.url)         code = "url_replace('" + self.servername+p.url + "');";
        else if(p.submit_code) code = "$('"+p.submit_code+"').submit();";
        else return false;

        this.Module(COM.Element([
          'div',
          {'class':'message'},
          [
            ['h2',{},p.headline],
            ['p',{},p.msg],
            ['div',{'class':'buttons'},[
              ['a',{'class':'button button_blue','href':'javascript:'+code},
              	[['span',{'class':'content'},"Enviar"]]
              ],
              ['a',{'class':'button button_blue','href':'javascript:APP.WIZ.Close();'},
              	[['span',{'class':'content'},"Cancelar"]]
              ]
            ]]
          ]
        ]), 'question');
      }
      catch(e)
      {
        return COM.Log('APP.WIZ.Question(); '+e);
      }
    }

    //
    //  Let the user take notice of sth.
    //  [p]arams: headline, msg
    //

    this.Alert = function(p)
    {
      try
      {
        return this.Module(COM.Element([
          'div',
          {'class':'message'},
          [
            ['h2',{},p.headline],
            ['p',{},p.msg],
            ['div',{'class':'buttons'},[
             ['a',{'class':'button button_blue','href':'javascript:APP.WIZ.Close();'},
              	[['span',{'class':'content'},"Cerrar"]]
              ]
            ]]
          ]
        ]), 'alert');
      }
      catch(e)
      {
        return COM.Log(4, 'APP.WIZ.Alert(); '+e);
      }
    }

    //
    //  private vars
    //
    //  E: Events
    //

    var E = {};

    //
    //  TODO:
    //  -> simplify this whole handling - maybe export to an explicit class,
    //     but have a look on unifying the layout modules - and the native html.
    //  -> decide using [p]aram hashes or simple arguments.
    //

  }

  //
  //  Post-loading css. Simple.
  //

  this.Css = function(s)
  {
    if(!C[s])
    {
      if(C[s] === null)
      {
        return null;
      }

      //IE doen't like our prototype extensions, so I create element without COM.Element
      if (typeof APP.Retrieve('css_domain') != 'undefined' && typeof APP.Retrieve('release_version') != 'undefined')
      {
        var node = document.createElement('link');
        node.rel = 'stylesheet';
        node.type = 'text/css';
        node.media = 'screen, print';
        node.id = 'css.trivago.'+s;
        node.href = APP.Retrieve('css_domain')+'/css_'+s+'_'+APP.Retrieve('release_version')+'_b0.css';
        COM.GET.Head().appendChild(node);
      }
    }

    return C[s] = 1;
  }

  //
  //  Simple registry functionallity.
  //  Inspired by some freaks from Redmond.
  //

  this.Register = function(k,v) { return R[k] = v; }
  this.Retrieve = function(k)   { return R[k];     }

  //
  //  private vars
  //
  //  C: already done css
  //  R: apps register
  //

  var C = {},
      R = {};

  //
  // Share url and titel to facebook
  //

  this.shareFacebook = function(u, t)
  {
  	window.open('http://www.facebook.com/sharer.php?u='+encodeURIComponent(u)+'&t='+encodeURIComponent(t), '_blank');
  }

  //
  //
  //
  this.shareTwitter = function(u, t, a)
  {
	var splitHash = u.split("#", 2);
  	var splitSearch = splitHash[0].split("?", 2);
  	var joinedURL = splitSearch[0];

  	joinedURL += (splitHash[1] || splitSearch[1]) ? '?' : '';

  	if(splitSearch[1])
  	{
  		joinedURL += splitSearch[1];
  	}

  	if(splitHash[1])
  	{
  		joinedURL += '#' + splitHash[1];
  	}

  	window.open('http://twitter.com/share?url='+encodeURIComponent(joinedURL)+'&via='+encodeURIComponent(a)+'&text='+encodeURIComponent(t), '_blank');
  }
}

//
//  COM officially doesn't support innerHTML, so we're going to wrap...
//

APP.Element = function(anything)
{
  var name;
  try
  {
    name = 'APP.Element(['+ typeof anything +']); ';

    if((typeof anything == 'string') && !document.getElementById(anything))
    {
      var div = COM.Element(['div', {'class':'APPElement'}]);
      div.innerHTML = anything;
      return COM.Element(div);
    }

    return COM.Element(anything);
  }
  catch(e)
  {
    return COM.Log(name+e);
  }
}

//
//
//

//
//  wrapper for map sources.
//

function google_api()
{
	APP.RUN.Call("google.jsapi");
}

//
//  setting up our own quirky.
//  todo: look if we can do the first part via css
//

function manipulateLinks()
{
  var x = COM.GET.All('a', null, 0);

  for (var i=0; i!=x.length; ++i)
  {
    if(x[i])
    {
      x[i].onfocus = function()
      {
        this.blur();
      }
    }

    if (x[i].getAttribute('type') == 'popup')
    {
      x[i].onclick = function()
      {
        var newin = window.open(url,'trivagopop','left=50,height=500,width=800,resizable=yes,scrollbars=yes');

        if(newin.focus)
        {
          newin.focus();
        }

        return false;
      }
    }
  }
}

APP.ERROR = new function()
{
	var is_logging_enabled = false;
	//
	//
	//

	this.Enable = function()
	{
		is_logging_enabled = true;
		window.onerror = APP.ERROR.Log;
	}

	//
	//
	//

	this.Log = function(msg, url, line_no)
	{
		if (is_logging_enabled)
		{
			var err_msg = "Error: " + msg + "\n"
						+ "URL: " + url + "\n"
						+ "Line: " + line_no + "\n"
						+ "nav: " + navigator.appName + "\n"
						+ "nav-version: " + navigator.appVersion
						+ "plattform: " + navigator.platform
						+ "useragent: " + navigator.userAgent + "\n"
						+ "url: " + document.URL;

			var request = new COM.HTTP.Request('GET', '/trivago_rpc.php?action=js_error&v=v6_02_2ac&msg='+encodeURIComponent(err_msg),{
							  'onfinish':function(str){
							  }});
			request.start();
		}
	}
};

function disable_one_button(form_id)
{
	//the setTimeout is a workaround for the firefox 2.0.3
	window.setTimeout("if($('button')) $('button').disabled=true;",20);

	$( form_id ).submit();
	return true;
}
APP.CALENDER = function(O, D, N, P)
{

	//
	//
	//

	this.AdaptDate = function()
	{
		if (N > 1)
		{
			for(var i=0;i!=N;++i)
			{
				S[i+1] = new Date(S[i].getFullYear(), S[i].getMonth()+1, S[i].getDate());
			}
		}
		return true;
	}

	//
	//
	//

	this.Create = function(x, y)
	{
		if (O.isElement())
		{
			if (!C)
			{
				C = COM.Element(['div', {'class':'APPCalender', 'style':'display:none;position:absolute;top:0px;left:0px;z-index:200;'}]);
				$(document.body).appendChild(C);

				var table = '';
				if (P['position']=='bottom_centered')
				{
					table += '<div class="arrow"></div>';
				}
				
				table += '<div class="ctrl cal_arrow_left" id="'+O.id+'_cal_arrow_left"><div class="ctrl_inner_left"></div></div>';
				table += '<div class="ctrl cal_arrow_right" id="'+O.id+'_cal_arrow_right"><div class="ctrl_inner_right"></div></div>';

				for(var k=0;k!=N;++k)
				{
					table += '<div class="wrapper">';
					if(k == 0)
					{
						table += '<div class="title left cal_title_left" id="'+O.id+'_cal_title_left"></div>';
					}
					else
					{
						table += '<div class="title right cal_title_right" id="'+O.id+'_cal_title_right"></div>';
					}

					table += '<table>\n'
						   + '<thead>\n'
						   + '<tr class="monthyear" style="display:none;">\n';
					if (N == 1)
					{
						table += '<th class="ctrl">&lt;</th>\n'
							+ '<th class="title" colspan="5"></th>\n'
							+'<th class="ctrl">&gt;</th>\n';
					}
					else
					{
						switch (k)
						{
							case 0:
								table += '<th class="ctrl">&lt;</th>\n'
									+ '<th class="title" colspan="6"></th>\n';
								break;
							case (N-1):
								table += '<th class="title" colspan="6"></th>\n'
								+ '<th class="ctrl">&gt;</th>\n';
								break;
							default:
								table += '<th class="title" colspan="7"></th>\n';
								break;
						}
					}
					table += '</tr>\n'
					       + '<tr class="day">\n';
					for(var i=0;i<=6;i++)
					{
						table += '<th class="'+((i>4) ? 'weekend' : 'weekday')+'">'+_D[i]+'</th>\n';
					}
					table += '</tr>\n'
					       + '</thead>\n'
					       + '<tbody>\n';
					for(var i=0;i!=6;++i)
					{
						table += '<tr>\n';
						for(var j=0;j!=7;++j)
						{
							table += '<td></td>\n';
						}
						table += '</tr>\n';
					}
					table += '</tbody>\n'
						   + '</table>\n'
						   + '</div>';
				}
				C.innerHTML = table;

				var Me = this;
				
				var heads = COM.GET.All('thead', C);
				for(var k=0;k!=N;++k)
				{
					var cells = COM.GET.All('th', heads[k]);
					if (N == 1)
					{
						cells[0].addEvent('click', function(){Me.Move(-1);});
						cells[1].addEvent('click', function(){Me.Move( 1);});
					}
					else
					{
						switch (k)
						{
							case 0:
								cells[0].addEvent('click', function(){Me.Move(-1);});
								break;
							case (N-1):
								cells[1].addEvent('click', function(){Me.Move( 1);});
								break;
						}
					}
				}

				$(O.id+'_cal_arrow_left').addEvent('click',function(){Me.Move(-1);});
				$(O.id+'_cal_arrow_right').addEvent('click',function(){Me.Move(1);});

				(O.getStyle('position') == 'relative') || (O.getStyle('position') == 'absolute') || O.setStyle('position', 'relative');
				C.addEvent('mouseover', function(){Me.Focus(true);});
				C.addEvent('mouseout', function(){Me.Focus(false);});
			}
			(typeof x != 'undefined') && C.setLeft(x);
			(typeof y != 'undefined') && C.setTop(y);
			C.appear();
			return true;
		}
		return false;
	}

	//
	//
	//

	this.Show = function(d)
	{
		if (this.Create())
		{
			d && (S[0] = d.clone());
			S[0].setDate(1) && this.AdaptDate();

			var sla = true;
			var sra = true;
			var ts_from = 0;
			var ts_to = 0;
			
			var dh = 'dealform_hotel_from_';
			ts_from = (new Date(parseInt('20'+$(dh+'year').value),parseInt($(dh+'month').value)-1,parseInt($(dh+'day').value))).getTime(); // jvt: oh dear, this won't work after 2099....
			dh = 'dealform_hotel_to_';
			ts_to = (new Date(parseInt('20'+$(dh+'year').value),parseInt($(dh+'month').value)-1,parseInt($(dh+'day').value))).getTime();
			
			var heads = COM.GET.All('thead', C),
				bodys = COM.GET.All('tbody', C);

			for(var k=0;k!=N;++k)
			{
				// set title in thead
				var cells = COM.GET.All('th', heads[k]);
				var ih = _M[S[k].getMonth()]+' '+S[k].getFullYear();
				
				if(k == 0)
				{
					$(O.id+'_cal_title_left').innerHTML = ih;
				}
				else
				{
					$(O.id+'_cal_title_right').innerHTML = ih;
				}

				cells[0].innerHTML = ih;
				
				// set cells in tbody
				var I = new Date(S[k].getFullYear(), S[k].getMonth(), 1);
				I.setDate(I.getDate()-(I.getDay()+6)%7-1);
				var cells = COM.GET.All('td', bodys[k]);
				for(var i=0,n=cells.length;i!=n;++i)
				{
					I.setDate(I.getDate()+1);
					var ts_current = 0;
					ts_current = I.getTime();
					var c = 'outside';
					cells[i].delEvent('click');
					if (	S[k].getFullYear() == I.getFullYear() &&
							S[k].getMonth() == I.getMonth()	)
					{
						cells[i].innerHTML = String(I.getDate());
						c  = ((I.getDay()+6)%7 < 5)?'inside weekday':'inside weekend';
						c += ((ts_current >= ts_from && ts_current <= ts_to) ? ' selection' : '');
						c += (D.getFullYear() == I.getFullYear() && D.getMonth() == I.getMonth() && D.getDate() == I.getDate())?' selected':'';
						if (	(	!P['max_date'] ||
									I <= P['max_date']	) &&
								(	!P['min_date'] ||
									I >= P['min_date']	)	)
						{
							c += ' active';
							this.SetEvent(cells[i], new Date(I.getFullYear(), I.getMonth(), I.getDate()));
						}
						else
						{
							c += ' inactive';
							if(k == 0) // jvt: if there are inactive days in month, don't display corresponding arrow
							{
								sla = false;
							}
							else
							{
								sra = false;
							}
						}
					}
					else
					{
						cells[i].innerHTML = '&nbsp;';
						cells[i].setStyle('cursor', 'auto');
					}
					cells[i].setClass(c);

					if(sla)
					{
						this.setArrowDisplay('left','block','107px');
						$(O.id+'_cal_title_left').setStyle('marginLeft','18px');
					}
					else
					{
						this.setArrowDisplay('left','none','125px');
						$(O.id+'_cal_title_left').setStyle('marginLeft','0px');
					}

					if(sra)
					{
						this.setArrowDisplay('right','block','107px');
					}
					else
					{
						this.setArrowDisplay('right','none','125px');
					}
				}
			}

			return true;
		}
		return false;
	}

	this.setArrowDisplay = function(lr,display,width)
	{
		$(O.id+'_cal_arrow_'+lr).setStyle('display',display);
		$(O.id+'_cal_title_'+lr).setStyle('width',width);
	}

	//
	//
	//

	this.SetEvent = function(c, d)
	{
		var Me = this;
		c.setStyle('cursor', 'pointer');
		c.addEvent('click', function(){Me.Date(d);Me.Close('selectclose');});
	}

	//
	//
	//

	this.ShowAt = function(o, d)
	{
		(typeof P['onopen'] == 'function') && P['onopen']();
		F = false;
		var Me = this;
		$('document_main').delEvent('mouseover');
		$('document_main').delEvent('click');
		this.Create();
		this.Show(d);
		if (o.isElement())
		{
			switch (P['position'])
			{
				case 'bottom':
					this.Create(o.getAbsLeft()+o.getWidth()-C.getWidth(), o.getAbsTop()+o.getHeight());
					break;
				case 'bottom_centered':
					this.Create(o.getAbsLeft()+Math.round((o.getWidth()-C.getWidth())/2), o.getAbsTop()+o.getHeight()+3);
					break;
				case 'centered':
					if(o.className == 'calendar_to')
					{
						this.Create(o.getWidth()+10, -91);
					}
					else
					{
						this.Create(o.getWidth()+10, -58);
					}
					break;
				case 'left':
				default:
					this.Create(o.getAbsLeft()+o.getWidth()-7, o.getAbsTop());
					break;
			}
		}
		
		if (typeof P['onmouseout'] == 'function')
		{
			window.setTimeout(function(){
						$('document_main').addEvent('mouseover', function(){P['onmouseout']();});
					}, 100);
		}
		if (typeof P['onclick_blank'] == 'function')
		{
			window.setTimeout(function(){
						$('document_main').addEvent('click', function(){P['onclick_blank']();});
					}, 100);
		}
	}

	//
	//
	//
	
	this.Hide = function()
	{
		(F = true) && document.delEvent('mousedown');
		if (typeof P['onmouseout'] == 'function')
		{
			$('document_main').delEvent('mouseover');
		}
		if (typeof P['onclick_blank'] == 'function')
		{
			$('document_main').delEvent('click');
		}
		C && C.disappear();
	}

	//
	//
	//
	
	this.Close = function(t)
	{
		this.Hide();
		(t == 'none') || ((typeof P['on'+t] == 'function') && P['on'+t](D));
	}

	//
	//
	//

	this.Focus = function(b)
	{
		return (F = b);
	} 

	//
	//
	//
	
	this.CloseEvent = function(t)
	{
		F || this.Close(t);
	}

	//
	//
	//

	this.Move = function(i)
	{
		S[0].setDate(1);

		var old_month = S[0].getMonth();
		var old_year = S[0].getFullYear();
		if(i<0 && old_month<=0)
		{
			// jvt: switch to December of previous year
			S[0].setFullYear(S[0].getFullYear() - 1);
			S[0].setMonth(11);
		}
		else if (i>0 && old_month>=11)
		{
			// jvt: switch to January of next year
			S[0].setFullYear(S[0].getFullYear() + 1);
			S[0].setMonth(0);
		}
		else
		{
			S[0].setMonth(S[0].getMonth()+i);
		}

		if (	(	P['max_date'] &&
					(	S[0].getFullYear() > P['max_date'].getFullYear()	||
						(	S[0].getFullYear() == P['max_date'].getFullYear()	&&
							S[0].getMonth() > P['max_date'].getMonth()	)	)	) ||
				(	P['min_date'] &&
					(	S[0].getFullYear() < P['min_date'].getFullYear()	||
						(	S[0].getFullYear() == P['min_date'].getFullYear()	&&
							S[0].getMonth() < P['min_date'].getMonth()	)	)	)	)
		{ // jvt: invalid value, reset to old values
			S[0].setMonth(old_month);
			S[0].setFullYear(old_year);
		}
		this.AdaptDate();
		this.Show();
	}

	//
	//
	//

	this.MoveDate = function(d)
	{
		P['min_date'] && (d < P['min_date']) && (d = P['min_date']) && this.Date(d);
		P['max_date'] && (d > P['max_date']) && (d = P['max_date']) && this.Date(d);
		var f;
		(typeof P['onselect'] == 'function') && (f = P['onselect']) && (P['onselect'] = null);
		if(this.Date(d))
		{
			var now = new Date();
			var dh = 'dealform_hotel_from_';
			var from = new Date(parseInt('20'+$(dh+'year').value),parseInt($(dh+'month').value)-1,parseInt($(dh+'day').value)); // jvt: oh dear, this won't work after 2099....
			dh = 'dealform_hotel_to_';
			var to = new Date(parseInt('20'+$(dh+'year').value),parseInt($(dh+'month').value)-1,parseInt($(dh+'day').value));
			//if(d.getTime() - now.getTime() <= 21 * 24 * 60 * 60 * 1000) // 3 weeks (21 days)
			if(now.getMonth() == (from.getMonth() - 1) && now.getMonth() == (to.getMonth() - 1))
				d = now; // jvt: calendar should display current month if complete selection is in next month
		        (S[0] = new Date(d.getFullYear(),d.getMonth(),1)) && this.AdaptDate();
		}
		(typeof f == 'function') && (P['onselect'] = f);
	}

	//
	//
	//

	this.Date = function(d)
	{
		try
		{
		
			if ((!P['min_date'] || d >= P['min_date']) && (!P['max_date'] || d <= P['max_date']))
			{
				(typeof P['onselect'] == 'function') && P['onselect'](d);
				return (D = d);
			}
		}
		catch(e) { }
		
		return false;
	}

	//
	// private vars
	//

	var C, // calender element
	    S = [], // shown dates
	    F = false; // aktiver Focus
	    _M = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio',
	    	  'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'],
	    _D = ['Lu', 'Ma', 'Mi', 'Ju',
	    	  'Vi', 'SÃ¡', 'Do'];

	//
	// init vars
	//

	D || (D = new Date());
	P || (P = {});
	N || (N = 1);
	S[0] = D.clone();
	this.AdaptDate();

};APP.DEALFORM = function(format, id, pos, min, max, steps, type, disp_weekday, use_event_hover, year_short)
{
	// load dom-nodes for performance-optimization
	var node_calendar_position_from = $(id+'_from_calendar_position'),
		node_calendar_position_to = $(id+'_to_calendar_position'),
		node_date_from = $(id+'_from_date'),
		node_date_to = $(id+'_to_date'),
		timeout_id1,
		timeout_id2;
		
	//
	//
	//

	this.Hide = function()
	{
		C && C['from'].Close(node_calendar_position_from);
		C && C['to'].Close(node_calendar_position_to);
	}
	
	//
	//
	//

	this.Handler = function(m, t, d)
	{
		try
		{
			var node = (t == 'from') ? node_date_from : node_date_to;
			var node_position = (t == 'from') ? node_calendar_position_from : node_calendar_position_to;
			switch(m)
			{
				case 'copen':
					(d = APP.PRICE.DEALS.CreateDate(format, node.value)) || (d = APP.PRICE.DEALS.CreateDate(format, node.defaultValue));
					d && C && C[t].MoveDate(d);
					break;
				case 'csclose':
				case 'cselect':
					this.SelectCalender(t, d);
					break;
				case 'cclose':
					this.CheckDateRange(t);
					break;
				case 'eclick':
					node.setAttribute('focus', 'true');
					C && C[(t == 'from'?'to':'from')].Close(node_position);
					C && C[t].ShowAt(node_position);
					timeout_id1 = false;
					break;
				case 'onmouseouver':
					var Me = this;
					(timeout_id1) && window.clearTimeout(timeout_id1);
					(timeout_id2) && window.clearTimeout(timeout_id2);
					C && C[(t == 'from'?'to':'from')].Close(node_position);

					timeout_id1=window.setTimeout(function(){
															Me.Handler('eclick', t, null);
														}, 200);
					break;
				case 'onmouseout':
					var Me = this;
					(timeout_id2) && window.clearTimeout(timeout_id2);
					(timeout_id1) && window.clearTimeout(timeout_id1);
					timeout_id2=window.setTimeout(function(){
																node.setAttribute('focus', 'false');
																C && C[t].CloseEvent('none');
															}, 150);
					break;
				case 'eblur':
					node.setAttribute('focus', 'false');
					C && C[t].CloseEvent('none');
					this.CheckDateRange(t);
					break;
			}
		}
		catch(e) {}
	}
	
	//
	//
	//

	this.SetDateField = function(t, d)
	{
		var _D = ['Do', 'Lu', 'Ma', 'Mi', 'Ju',
	    		  'Vi', 'SÃ¡'];

	    var dayString = '';
	    if (disp_weekday)
	    {
	    	dayString = _D[d.getDay()]+', ';
	    }

		var year = String(d.getFullYear());
		if (year_short && !Browser.IE6 && !Browser.IE7)
		{
			year = String(year[2])+String(year[3]);
		}
		$(id+'_'+t+'_year').value  = year;
		$(id+'_'+t+'_month').value = d.getMonth()+1;
		$(id+'_'+t+'_day').value   = d.getDate();
		switch(format)
		{
			case 'us':
				$(id+'_'+t+'_date').value  = dayString+String(d.getMonth()+1).lpad(2, '0')+'/'+String(d.getDate()).lpad(2, '0')+'/'+year;
				break;
			case 'uk':
				$(id+'_'+t+'_date').value  = dayString+String(d.getDate()).lpad(2, '0')+'/'+String(d.getMonth()+1).lpad(2, '0')+'/'+year;
				break;
			case 'eu':
			default:
				$(id+'_'+t+'_date').value  = dayString+String(d.getDate()).lpad(2, '0')+'.'+String(d.getMonth()+1).lpad(2, '0')+'.'+year;
				break;
		}
	}

	//
	//
	//

	this.SelectCalender = function(t, d)
	{
		this.SetDateField(t, d);
		this.CheckDateRange(t);
	}
	
	//
	//
	//

	this.CheckDateRange = function(t, init)
	{
		(typeof init == 'undefined') && (init = false);
		
		var from_date, to_date;
		(from_date = APP.PRICE.DEALS.CreateDate(format, node_date_from.value)) || (from_date = APP.PRICE.DEALS.CreateDate(format, node_date_from.defaultValue));
		(to_date = APP.PRICE.DEALS.CreateDate(format, node_date_to.value)) || (to_date = APP.PRICE.DEALS.CreateDate(format, node_date_to.defaultValue));
	
		if (to_date && from_date)
		{
			if (	type=='hotel' ||
					type=='fly'	)
			{
				var date_range_diff = (type=='hotel') ? 1 : 0;
				if (to_date <= from_date)
				{
					switch(t)
					{
						case 'to':
							from_date.setDate(1);
							from_date.setFullYear(to_date.getFullYear());
							from_date.setMonth(to_date.getMonth());
							from_date.setDate(to_date.getDate()-date_range_diff);
							break;
						case 'from':
							to_date.setDate(1);
							to_date.setFullYear(from_date.getFullYear());
							to_date.setMonth(from_date.getMonth());
							to_date.setDate(from_date.getDate()+date_range_diff);
							break;
					}
				}
				else if (	init == false &&
							t == 'from' &&
							(to_date-from_date)/(1000*60*60*24) > 21	)
				{
					to_date.setDate(1);
					to_date.setFullYear(from_date.getFullYear());
					to_date.setMonth(from_date.getMonth());
					to_date.setDate(from_date.getDate()+date_range_diff);
				}
			}
		
			this.SetDateField('to', to_date);
			this.SetDateField('from', from_date);
	
			C && C['from'].MoveDate(from_date);
			C && C['to'].MoveDate(to_date);
		}
	}

	//
	//
	//
	
	var Me = this;

	if (pos !== null)
	{
		var C = {
			'from':	new APP.CALENDER($(id+'_from_calendar'), null, steps, {
						'min_date':min,
						'max_date':max,
						'position':pos,
						'onopen':function(){Me.Handler('copen', 'from', null);},
						'onselectclose':function(d){Me.Handler('csclose', 'from', d);},
						'onclose':function(d){Me.Handler('cclose', 'from', d);},
						'onselect':function(d){Me.Handler('cselect', 'from', d); },
						'onmouseout':function(d){Me.Handler('onmouseout', 'from', d);},
						'onclick_blank':function(d){Me.Handler('eblur', 'from', d);}
					}),
			'to':	new APP.CALENDER($(id+'_to_calendar'), null, steps, {
						'min_date':min,
						'max_date':max,
						'position':pos,
						'onopen':function(){Me.Handler('copen', 'to', null);},
						'onselectclose':function(d){Me.Handler('csclose', 'to', d);},
						'onclose':function(d){Me.Handler('cclose', 'to', d);},
						'onselect':function(d){Me.Handler('cselect', 'to', d);},
						'onmouseout':function(d){Me.Handler('onmouseout', 'to', d);},
						'onclick_blank':function(d){Me.Handler('eblur', 'to', d);}
					})
		};
		
		use_event_hover = typeof use_event_hover == 'undefined' ? false : use_event_hover;

		node_calendar_position_from.show();
		node_calendar_position_from.setStyle('cursor', 'pointer');
		node_date_from.addEvent('click', function(){Me.Handler('eclick', 'from', null);});
		node_calendar_position_from.addEvent('click', function(){Me.Handler('eclick', 'from', null);});
		if (use_event_hover)
		{
			$(node_date_from.parentNode).addEvent('mouseover', function(){Me.Handler('onmouseouver','from', null);});
			$(node_date_from.parentNode).addEvent('mouseout',  function(){Me.Handler('onmouseout', 'from', null);});
		}
		node_date_from.addEvent('focus', function(e){Me.Handler('eclick', 'from', null);});
		node_date_from.addEvent('blur', function(e){Me.Handler('eblur', 'from', null);});
	
		node_calendar_position_to.show();
		node_calendar_position_to.setStyle('cursor', 'pointer');
		
		node_date_to.addEvent('click', function(){Me.Handler('eclick', 'to', null);});
		if (use_event_hover)
		{
			$(node_date_to.parentNode).addEvent('mouseover', function(){Me.Handler('onmouseouver','to', null);});
			$(node_date_to.parentNode).addEvent('mouseout',  function(){Me.Handler('onmouseout', 'to', null);});
		}
		node_calendar_position_to.addEvent('click', function(){Me.Handler('eclick', 'to', null);});
		node_date_to.addEvent('focus', function(){Me.Handler('eclick', 'to', null);});
		node_date_to.addEvent('blur', function(){Me.Handler('eblur', 'to', null);});
	}

	this.CheckDateRange('from', true);

};APP.SNAPSHOT = new function()
{

	//
	//
	//

	this.Get = function(k)
	{
		if (typeof k == 'undefined')
		{
			var S = {},
				i;
			for(i in P)
			{
				S[i] = P[i];
			}
			for(i in J)
			{
				S[i] = J[i];
			}
			return S;
		}
		else
		{
			if (typeof J[k] != 'undefined')
			{
				return J[k];
			}
			else if (typeof P[k] != 'undefined')
			{
				return P[k];
			}
			else
			{
				return null;
			}
		}
	}

	//
	//
	//

	this.Response = function(params, is_protocol)
	{
		var o = [],
			i;

		if (is_protocol)
		{
			for(i in params)
			{
				o[ key_map[i] ] = params[i];
			}
		}
		else
		{
			o  = params;
		}

		return ((J = {}) && (P = o));
	}

	//
	// 
	//

	this.Request = function(k, v)
	{
		return (J[k] = v);
	}

	//
	// 
	//

	this.GetQuery = function(complete, without_request_ident, encode_uri)
	{
		var retval = !complete ? "&path=" + encodeURI(this.Get('path')) : '',
			hash   = complete  ? this.Get() : J,
			field;
			
		if (typeof encode_uri == 'undefined')
		{
			encode_uri = true;
		}

		for (param in hash)
		{
			if (param=='category')
			{
				retval += ((retval=='') ? '' : '&') + "category_range="+hash[param];
			}
			else if (param=='overall_liking' && {'object':1}[typeof hash[param]])
			{
				retval += ((retval=='') ? '' : '&') + "overall_liking="+hash[param].join(',');
			}
			else if (param=='fields')
			{
				for (field in hash[param])
				{
					if (!{'function':1,'undefined':1,'object':1}[typeof hash[param][field]])
					{
						retval += ((retval=='') ? '' : '&') + "f_" + field + "=";
						retval += encode_uri ? encodeURI(hash[param][field]) : hash[param][field];
					}
				}
			}
			else if (
						!{'function':1,'undefined':1,'object':1}[typeof hash[param]] && 
						(hash[param]!=null)
					)
			{
				retval += ((retval=='') ? '' : '&') + param + "=";
				if ((typeof without_request_ident=='undefined') || (without_request_ident===true && param!='request_ident'))
				{
					retval += encode_uri ? encodeURI(hash[param]) : hash[param];
				}
			}
		}

		return retval;
	}

	//
	// 
	//

	this.SetMap = function(map)
	{
		key_map = map;
	}

	//
	// private vars
	//

	var P = {},
		J = {},
		key_map = null;

};APP.HASH = new function()
{

	//
	//
	//

	this.Get = function(id)
	{
			this.Objects();
			if (typeof O[id] != 'undefined')
			{
				return this.Unconvert(O[id]);
			}
		return '';
	}

	//
	//
	//

	this.Set = function(id, hash, straight)
	{
			this.Objects();
			(typeof straight == 'undefined') && (straight = false);
			(typeof id != 'undefined' && typeof hash != 'undefined') && (O[id] = this.Convert(hash));
			var hash = '',
				h;
			for(h in O)
			{
				if (typeof O[h] == 'string' && O[h] != '')
				{
					hash && (hash += ',');
					hash += h+':"'+encodeURI(O[h])+'"';
				}
			}
			(hash || straight) && COM.HASH.Set(hash);
		return true;
	}

	//
	//
	//

	this.Unset = function(id)
	{
		return this.Set(id, '', true);
	}

	//
	//
	//

	this.Reg = function(id, f, r)
	{
		f && (F[id] = COM.GET.Function(f));
		((typeof r == 'undefined' || r) && (r = true)) || (r = false);
		COM.HASH.Reg(function(){APP.HASH.Check();}, r);
		return true;
	}

	//
	//
	//

	this.Convert = function(any)
	{
		var s = '';
		if (typeof any == 'string')
		{
			s = any;
		}
		else
		{
			for(h in any)
			{
				if (typeof any[h] != 'function' && typeof any[h] != 'object')
				{
					s && (s += '&');
					s += h+'='+encodeURI(any[h]);
				}
			}
		}
		return s;
	}

	//
	//
	//

	this.Unconvert = function(any)
	{
		var o = {};
		if (typeof any == 'string')
		{
			var a = any.split('&');
			var p;
			for(var i=0;i!=a.length;++i)
			{
				(p = a[i].split('=', 2)) && (o[p[0]] = decodeURI(p[1]));
			}
		}
		else
		{
			o = any.clone();
		}
		return o;
	}

	//
	//
	//
	
	this.Objects = function()
	{
		try
		{
			eval('O = COM.GET.Elem({'+decodeURI(COM.HASH.Get().replace(/#/, ''))+'})');
			return true;
		}
		catch(e)
		{
			O = COM.GET.Elem({});
			return false;
		}
	}

	//
	//
	//

	this.Check = function()
	{ 
	  	var Old = O.clone();
		this.Objects();
		for(h in Old)
		{
			(typeof Old[h] != 'function' && Old[h] != O[h]) && (typeof F[h] == 'function') && F[h]();
		}
		return true;
	}

	//
	// private vars
	//

	var F = {},
		O = {};

};
function AjaxForm_Engine()
{
	this.current_url = false;
};

AjaxForm_Engine.prototype = {

	get_form_id:function(obj)
	{
		var node = obj;
		while(node.nodeName != "FORM")
			node = node.parentNode;
				return node.getAttribute((typeof node.getAttribute("name") == "string") ? "name" : "id");
	},

	get_formvars:function(obj, button)
	{
		var elems;
		var postvars = "";
		if (elems = document.forms[this.get_form_id(obj)].elements)
		{
			for(var i=0;i<elems.length;i++)
			{
				var do_add = false;
				var add_value = null;
				switch(elems[i].type)
				{
					case "checkbox":
					case "radio":
						var do_add = elems[i].checked;
						var add_value = elems[i].value;
						break;
					case "submit":
					case "button":
						if (elems[i].name == button || button == "")
						{
							var do_add = true;
							var add_value = (elems[i].value == '')?'on':elems[i].value;
						}
						break;
					default:
						var do_add = true;
						var add_value = elems[i].value;
				}
				if (do_add && add_value && elems[i].name)
				{
					if (postvars != "")
					{
						postvars += "&";
					}
					postvars += escape(elems[i].name)+"="+encodeURIComponent(add_value);
				}
			}
		}
		return postvars;
	},

	reset_formvars:function(obj)
	{
		document.forms[this.get_form_id(obj)].reset();
	},

	run:function(obj, params, synchron)
	{
		if (synchron == null)
		{
			synchron=false;
		}
		var form_id = this.get_form_id(obj);
		if (document.forms[form_id])
		{
			if (document.forms[form_id].getAttribute("enctype") == "multipart/form-data")
			{
				if (!$("submit_"+form_id).isElement())
				{
					if(typeof this.int_iframe_counter == "undefined")
					{
						this.int_iframe_counter = 0;
					}
					else
					{
						this.int_iframe_counter++;
					}

					var emode     = document.createElement("input");
					var iframe    = document.createElement("iframe");
					var iframe_id = "submit_"+form_id + "_" + this.int_iframe_counter;

					emode.setAttribute("type", "hidden");
					emode.setAttribute("name", "iframe_mode");
					emode.setAttribute("value", "1");
					iframe.setAttribute("id",   iframe_id);
					iframe.setAttribute("name", iframe_id);
					iframe.style.display="none";
					var parentNode = $( form_id ).parentNode;
					$( form_id ).setAttribute("target", iframe_id);
					$( form_id ).appendChild(emode);
					parentNode.appendChild(iframe);

					/**
					* VERY IMPORTANT:
					* The following Code is a BUGFIX for the INTERNET EXPLORER !!
					* This browser has problems with dynamic generated iframes and changing
					* the target - attrib.
					* !! NORMAL IT NOT WORKS !!
					*/
					if(self.frames[ iframe_id ].name != iframe_id)
					{
						self.frames[ iframe_id ].name = iframe_id;
					}
					window.setTimeout("AjaxForm.iframe_handler('" + iframe_id + "', " + params["onfinish"] + ");", 250);
				}

				if (this.current_url != $(form_id).getAttribute("action"))
				{
					this.current_url = $(form_id).getAttribute("action");
					return true;
				}
			}
			else
			{
				if (this.current_url != document.forms[form_id].getAttribute("action"))
				{
					this.current_url = document.forms[form_id].getAttribute("action");
					var form_method = document.forms[form_id].getAttribute("method");
					var onfinish = function(r){AjaxForm.current_url = false;params["onfinish"](r);};
					switch (form_method)
					{
						case "get":
							COM.HTTP.Get(document.forms[form_id].getAttribute("action")+"?"+this.get_formvars(obj, params["button"]), { "onfinish":onfinish }, synchron );
							break;
						case "post":
						default:
						    COM.HTTP.Post(document.forms[form_id].getAttribute("action"), { "vars":this.get_formvars(obj, params["button"]), "onfinish":onfinish }, synchron );
					}
				}
			}
		}
		if (params["reset"])
		{
			this.reset_formvars(obj);
		}
		return false;
	},

	iframe_handler:function(iframe_id, onfinish)
	{
		var iframe = eval("" + iframe_id + "");
		var ibody  = iframe.document.body;

		if( ibody != null &&
			ibody.innerHTML.length > 0)
		{
			this.current_url = false;
			if (onfinish)
			{
				onfinish(ibody.innerHTML);
			}

		}
		else
		{
			window.setTimeout("AjaxForm.iframe_handler('" + iframe_id + "', " + onfinish + ");", 250);
		}
	}

}

var AjaxForm = new AjaxForm_Engine();
//
// Handles onscreen overlays with different request methods
// content is loaded with ajax
//
// @author crankers
// @since 21.07.2008
//
APP.SCREEN = new function()
{

    //
    //  private vars
    //
    //  U - (string|boolean) current url
    //  B - (string) pressed button
    //
    var U = false,
    	B;

	//
	// stored pressed button to decide which action should be done
	// in more complex forms. Use of function is public.
	//
	// @author crankers
	// @since 21.07.2008
	//
	// @param (string) b, button name pressed
	//
	// @return (boolean)
	//
	this.Button = function(b)
	{
		return (B = b);
	};

	//
	// Hash get, execute get method with base64 url. Use of function is public.
	//
	// @author crankers
	// @since 21.07.2008
	//
	// @param (string) url, base64 url to call 
	//
	// @return (void)
	//
	this.HGet = function(url)
	{
		this.Get(APP.LB.base64_decode(url), false);
	};

	//
	// Execute get method to given url,
	// possible to initialize hashing in url to go forward and backward.
	// Use of function is public.
	//
	// @author crankers
	// @since 21.07.2008
	//
	// @param (string) url, url to call
	// @param (boolean) use_hash
	//
	// @return (void)
	//
	this.Get = function(url, use_hash)
	{
		(typeof use_hash == 'undefined') && (use_hash = true);

		if (!this.IsActive(url))
		{
			APP.Unbubble();
			APP.WIZ.Open();
			use_hash && this.InitialHash(url);
			COM.HTTP.Get(url, { 'onfinish':function(r) {
				($('dealform_big').isElement()) && APP.PRICE.DEALS.Clear(); // jvt: pause destinationstring rotation if dealform present
				use_hash && APP.HASH.Reg('screenmodule', function(){} );
				APP.SCREEN.Response('load', r);
				use_hash && APP.HASH.Reg('screenmodule', function(){APP.SCREEN.InitHash();} );
			}});
		}
	};

	//
	// Reload already opened overlay with get method to get new content
	// possible to initialize (hash)ing. Use of function is public.
	//
	// @author crankers
	// @since 21.07.2008
	//
	// @param (string) url, url to call
	// @param (boolean) hash
	//
	// @return (void)
	//
	this.Reload = function(url, hash)
	{
		if (!this.IsActive(url))
		{
			(typeof hash == 'undefined') && (hash == false);
			COM.HTTP.Get(url, { 'onfinish':function(r) {
				hash && APP.HASH.Reg('screenmodule', function(){} );
				APP.SCREEN.Response('reload', r);
				hash && APP.HASH.Reg('screenmodule', function(){APP.SCREEN.InitHash();} );
			}});
		}
	};

	//
	// Opens a screen with post method.
	// Given form (o)bject is parsed into string from AjaxForm and send there.
	// Use of function is public.
	//
	// @author crankers
	// @since 21.07.2008
	//
	// @param (object) o, form object
	//
	// @return (boolean)
	//
	this.Post = function(o)
	{
		APP.Unbubble();
		APP.WIZ.Open();
		AjaxForm.run(	o, {
						'button':B,
						'reset':true, 
						'onfinish':function(r) {
							APP.SCREEN.Response('reload', r);
						}
					});
		return false;
	};

	//
	// Submits an opened screen form (o)bject with AjaxForm
	// This method is used in onsubmit event of form, when not a screen form is opened
	// return true, that form executuin continues.
	// Use of function is public.
	//
	// @author crankers
	// @since 21.07.2008
	//
	// @param (object) o, form object
	//
	// @return (boolean)
	//
	this.Submit = function(o)
	{
		if(!this.IsScreen(o))
		{
			return true;
		}

		return AjaxForm.run(	o, {
								'button':B,
								'onfinish':function(r) {
									APP.SCREEN.Response('reload', r);
								}
							});
	};

	//
	// Handles ajax responses, insert response html and executes contained javascript.
	// Use of function is private.
	//
	// @author crankers
	// @since 21.07.2008
	//
	// @param (string) t, type
	// @param (string) r, response text
	//
	// @return (boolean)
	//
	this.Response = function(t, r)
	{
		U = false;
		switch (t)
		{
			case 'reload':
			case 'load':
			default:
				APP.WIZ.Module(r, 'screenmodule');
		}
		APP.WIZ.Reg('onclose', function() {
			try
			{
				APP.HASH.Get('screenmodule') && APP.HASH.Unset('screenmodule');
			}
			catch (ex)
			{}
		});
		APP.InnerExec(r);
		return true;
	};

	//
	// Prooves if given url is currently active to avoid multiple requests.
	// Use of function is private.
	//
	// @author crankers
	// @since 21.07.2008
	//
	// @param (string) url
	//
	// @return (boolean)
	//
	this.IsActive = function(url)
	{
		if(U == url)
		{
			return true;
		}
		U = url;
		return false;
	};

	//
	// Prooves if given (n)ode is an onscreen child node.
	// Use of function is public.
	//
	// @author crankers
	// @since 21.07.2008
	//
	// @param (string) url
	//
	// @return (boolean)
	//
	this.IsScreen = function(n)
	{
		while((n = n.parentNode))
		{
			if(n.getAttribute)
			{
				if(n.className.match(/COMWizardCont$/))
				{
					return true;
				}
			}
		}
		return false;
	};

	//
	// Executes hash and loads content to given hash.
	// Use of function is public.
	//
	// @author crankers
	// @since 21.07.2008
	//
	// @param (string) url
	//
	// @return (boolean)
	//
	this.InitHash = function()
	{
		U = null;
		var h = APP.HASH.Get('screenmodule');
		if (h && h['base'])
		{
			var u = (h['base'].substr(0, 1) == '/'?'':'/')+h['base']+'?';
			for(var k in h)
			{
				(typeof h[k] == 'string') && (k != 'base') && (u += '&'+k+'='+h[k]);
			}
			APP.HASH.Reg('screenmodule', function(){});
			this.Reload(u, true);
		}
	};

	//
	// Registers the screenmodule hash to APP.HASH.
	// Use of function is public.
	//
	// @author crankers
	// @since 21.07.2008
	//
	// @param (string) url
	//
	// @return (boolean)
	//
	this.InitialHash = function(url)
	{
		var b = url.split('?', 2);
		var h = { 'base':(b[0].substr(0, 1) == '/')?b[0]:'/'+b[0] };
		var q = b[1].split('&');
		for(var i=0,n=q.length;i!=n;++i)
		{
			var qe = q[i].split('=', 2);
			qe[0] && (h[qe[0]] = qe[1]);
		}
		APP.HASH.Reg('screenmodule', function(){} );
		APP.HASH.Set('screenmodule', h);
	};

};//
// base part for navigation map APP.NAVMAP in package map
//
// @author crankers
// @since 02.08.2011
//
APP.NAV = new function()
{
	
	//
	// Route given event to APP.NAVMAP when loaded.
	// Use of function is public.
	//
	// @author crankers
	// @since 02.08.2011
	//
	// @return (boolean)
	//
	this.Event = function(e, id)
	{
		(typeof APP.NAVMAP == 'undefined') || APP.NAVMAP.Event(e, id);
		return true;
	};
	
};APP.PRICE = new function()
{	
	//
	// this function is quickier than eval (multiplicator: 3.5)
	//

	this.EvalCode = function(code)
	{
		if(code)
		{
			var doc  = document;
			var node = doc.createElement('script');
			doc.getElementsByTagName('head')[0].appendChild(node);
			node.text = code;
		}
	}
};

APP.PRICE.DEALS = new function()
{
	//
	// private vars
	//

	var Form   = null,
		Node   = null, 
		Mod    = null,
		IsOpen = false,
		ssg    = '',
		FormName = null,
		onClose = null,
		loading_try = 0;


	//
	//
	//

	this.CreateDate = function(f, s)
	{
		var ctest = s.split(', ');
		if(ctest.length > 1)
		{
			s = ctest[1];
		}
		
		try
		{
			var i = [];
			(s.indexOf('.') == -1) || (i = s.split('.'));
			(i.length) || (s.indexOf('/') == -1) || (i = s.split('/'));
			(i.length) || (s.indexOf('-') == -1) || (i = s.split('-'));
			(i.length) || (s.indexOf(' ') == -1) || (i = s.split(' '));
			if (	i.length == 3 &&
					(i[0] = parseInt(i[0], 10)) &&
					(i[1] = parseInt(i[1], 10)) &&
					(i[2] = parseInt(i[2], 10))	)
			{
				var d, m, y;
				(String(i[2]).length == 4) && (i[2] > 0) && (y = i[2]) && (i = [i[0], i[1]]);
				(y == null) && (String(i[0]).length == 4) && (i[0] > 0) && (y = i[0]) && (i = [i[1], i[2]]);
				(y == null) && (String(i[2]).length <= 2) && (i[2] > 31) && (y = i[2]) && (i = [i[0], i[1]]);
				(y == null) && (String(i[0]).length <= 2) && (i[0] > 31) && (y = i[0]) && (i = [i[1], i[2]]);
				(y == null) && (i[2] > 0) && (i[2] < 100) && (y = i[2]) && (i = [i[0], i[1]]);
				(y == null) || ((String(y).length <= 2) && (y < 50) && (y = 2000+y));
				(y == null) || ((String(y).length <= 2) && (y > 50) && (y = 1900+y));
				if (y != null)
				{
					(String(i[0]).length <= 2) && (i[0] > 12) && (d = i[0]);
					(d != null) && (i[1] > 0) && (i[1] <= 12)&& (m = i[1]-1);
					(d == null) && (String(i[1]).length <= 2) && (i[1] > 12) && (d = i[1]);
					(m == null) && d && (i[0] > 0) && (i[0] <= 12)&& (m = i[0]-1);
					(d == null) && (f == 'us') && (i[1] > 0) && (d = i[1]);
					(m == null) && (f == 'us') && (i[0] > 0) && (m = i[0]-1);
					(d == null) && (i[0] > 0) && (d = i[0]);
					(m == null) && (i[1] > 0) && (m = i[1]-1);
					if (d != null && m != null)
					{
						return new Date(y, m, d);
					}
				}
			}
			return false;
		}
		catch(e)
		{
			return false;
		}
	} 
	
	//
	//
	//
	
	this.SetOnloadEvent = function(e)
	{
		 if (!e)
		 {
		 	e = window.event;
		 }
		 if (e.keyCode!=13)
		 {
		 	APP.PRICE.DEALS.Clear();
		 }
	}

	//
	//
	//

	this.SetViewType = function(value)
	{
		$('dealform_view_type').value = value;
	}

	//
	//
	//

	this.SetDealformReferer = function(value)
	{
		$('dealform_referer').value = value;
	}

	//
	//
	//

	this.SetGeocode = function(geo_longitude, geo_latitude)
	{
		var form = document.forms['dealform_hotel'];

		form['geo_longitude'].value     = geo_longitude;
		form['geo_latitude'].value      = geo_latitude;
		form['order_by'].value          = 'distance';
		form['geo_distance_item'].value = '';
	}
	
	//
	//
	//
	
	this.SwitchItemPage = function(path_id, item_id, type)
	{
		var pagetype = 'hotels',
			action   = '/region.php';

		if(!node_deals)
		{
			this.Init();
		}

		// set values
		switch((type+''))
		{
			case '2':
				node_deals['geo_distance_item'].value 	= item_id;
				node_deals['geo_use_distance'].value 	= 1;
				node_deals['geo_distance_limit'].value 	= 20000;
				node_deals['order_by'].value           	= 'distance';
				break;
			case '3':
			default:
				if(item_id > 0)
				{
					action = '/item.php';
					pagetype = 'deals';
					node_deals['item'].value = item_id;
				}
				break;
		}
		
		node_deals['pagetype'].value = pagetype;
		node_deals.action = action;
		node_deals['path'].value = path_id;
	}
	
	//
	//
	//
	
	this.HideError = function()
	{
		if(typeof node_dealform_error != 'undefined')
		{
			node_dealform_error.disappear();
		}
	}
	
	//
	// display error
	//
	
	this.DisplayError = function(str)
	{
		node_dealform_error.appear();
		node_unknown_path.appear();
		node_unknown_path.innerHTML = "<p>" + str + "</p>";
		$('js_dealform_submit_button').setClass("button button_red");
	}
	
	//
	//
	//
	
	this.OnSubmit = function()
	{
		try
		{
			this.Init();

			if(APP.Retrieve('c49') != 1) // jvt: deactivate this for ctest, otherwise tabbing "breaks"
				$('js_dealform_submit_button').focus();

			var highlight_path_tmp 		= APP.PRICE.DEALS.SSG.GetHighlightValue();
			
			if (highlight_path_tmp > 0)
			{
				var highlight_itemid_tmp 	= APP.PRICE.DEALS.SSG.GetHighlightItemId();
				var highlight_itemtype_tmp 	= APP.PRICE.DEALS.SSG.GetHighlightItemType();
				
			 	this.SwitchItemPage(highlight_path_tmp,highlight_itemid_tmp,highlight_itemtype_tmp);
			 	
			 	highlight_itemid_tmp 	= 0;
				highlight_itemtype_tmp 	= 0;	
			}

			highlight_path_tmp 		= 0;

		 	node_unknown_path.disappear();
		 	node_dealform_error.disappear();

			//check from- and to-date
			var actual_date = new Date(); //reset actual time. we need only the date
			actual_date.setSeconds(0);
			actual_date.setHours(0);
			actual_date.setMilliseconds(0);
			actual_date.setMinutes(0);

			var to_date, from_date;
			
			to_date = this.CreateDate('uk', $('dealform_hotel_to_date').value);
			from_date = this.CreateDate('uk', $('dealform_hotel_from_date').value);

			if(!to_date || !from_date || to_date <= from_date)
			{
				this.DisplayError("La fecha de la vuelta es anterior a la salida");
				return false;
			}
			else if((actual_date > from_date) || (actual_date > to_date))
			{
				this.DisplayError("La fecha que nos indicas ya ha pasado");
				return false;
			}
			else if(node_deals['query_path_name'].value == '')
			{
				this.DisplayError("Introduce una ciudad o regiÃ³n");
				return false;
			}

			APP.PRICE.DEALS.SSG.ClearResultList();

			// deactivitate example rotation
			APP.HOME_ROTATION.Stop();

			if((node_deals['path'].value=="") && (node_destinationstring_select.innerHTML != ""))
			{
				this.SetPreviewLinks($('select_unknown_path').value);
			}
	
			if((node_deals['path'].value=="") || (node_deals['path'].value=="0"))
			{
				APP.PRICE.DEALS.SSG.StartRequest('/trivago_rpc.php?action=get_dealform_unkown_path');
				return false;
			}
		
			if(!APP.PRICE.DEALS.SSG.GetChangeFocus())
			{
				window.location.href = $("dealform_hotel").action+'?'+AjaxForm.get_formvars($("dealform_hotel"), false);
			}
			else
			{
				APP.PRICE.DEALS.SSG.ClearChangeFocus();
				$('js_dealform_submit_button').delClass('waiting');
			}
		}
		catch(e)
		{
			loading_try = parseInt(loading_try);
			if (++loading_try <= 20)
			{
				window.setTimeout(function(){
						APP.PRICE.DEALS.OnSubmit();
					}, 100);
			}
		}
		return false;
	}
	
	//
	//
	//
	
	this.Init = function()
	{	
		node_deals = $('dealform_hotel');
		
		node_unknown_path             = $('unknown_path');
		node_destinationstring_select = $('destinationstring_select');
		node_dealform_error           = $('dealform_error');

		// javascript is enabled
		$('dealform_hotel_javascript').value = 1;
	}
	
	//
	//
	//
	

	this.SetPreviewLinks = function(path_and_item)
	{
		var tmp = path_and_item.split('|');
		if (typeof tmp[1]=='undefined')
		{
			tmp[1] = '';
		}
		this.SwitchItemPage(tmp[0], tmp[1]);
	}
	
	//
	//
	//

	this.SetSelectField = function(node_selectfield)
	{
		this.SetPreviewLinks(node_selectfield.value);
		
		for (var i=0, n=node_selectfield.length; i<n; i++)
		{
			if (node_selectfield.options[i].selected)
			{
				$('destinationstring').value = node_selectfield.options[i].text;
				break;
			}
		}
		
		node_selectfield.disappear();
	}

	//
	//
	//

	this.Clear = function()
	{
		APP.PRICE.DEALS.Init();
		
		if (APP.HOME_ROTATION.IsEnabled())
		{
			node_deals['query_path_name'].value='';
		}
		APP.HOME_ROTATION.Stop();

		$('destinationstring').delClass('lighttext');
		node_deals.action='/region.php';
		node_destinationstring_select.innerHTML='';
		node_unknown_path.innerHTML='';
		node_dealform_error.disappear();
	
		this.SwitchItemPage('', '');

		node_deals['geo_distance_item'].value  = '';
		node_deals['order_by'].value           = '';
		node_deals['geo_use_distance'].value   = '';
		node_deals['geo_distance_limit'].value = '';

		return true;
	}
	
	//
	//
	//
	
	this.SearchFieldOnKeyPress = function(e)
	{
		 if (!e)
		 {
		 	e = window.event;
		 }
		 if (e.keyCode!=13)
		 {
		 	APP.PRICE.DEALS.Clear();
		 }
	}

	//
	//
	//
	this.handleRoomTypeKeyEvent = function(e)
	{
		if(!e)
			e = window.event;

		var one = $('js_room_type_open_1').hasClass('selected');
		if(e.keyCode > 20)
			one = !one; // flip value for arrow keys

		var text = (one ? $('js_room_type_open_1').innerHTML : $('js_room_type_open_7').innerHTML);
		var val = (one ? 1 : 7);
		switch(e.keyCode)
		{
			case 38: // up
			case 40: // down
				APP.PRICE.DEALS.SelectRoomType(text,val);
				break;
			case 13: // enter
			case 9: // tab
				document.onkeyup = document.onkeypress = document.onkeydown = function(){}; // reset
				APP.PRICE.DEALS.ClickRoomType(text,val);
				$('js_dealform_submit_button').focus(); // focus submit button
				break;
		}

		return false; // and block event
	}
	
	//
	//
	//
	
	this.RoomTypeOpen = function()
	{
		(timeout_id2) && window.clearTimeout(timeout_id2);
		var timeout = 200;
		timeout_id1 = window.setTimeout(function(){
													APP.PRICE.DEALS.SSG.Blur();
													APP.PRICE.DEALS.SSG.ClearResultList();
													$('js_room_type_open').appear();
													if(APP.Retrieve('c49') == 1)
													{
														document.onkeyup = APP.PRICE.DEALS.handleRoomTypeKeyEvent;
														document.onkeypress = function(e){return false;};
														document.onkeydown = function(e){return false;};
													}
												}, timeout);
	}
	
	//
	//
	//
	
	this.RoomTypeClose = function()
	{
		(timeout_id1) && window.clearTimeout(timeout_id1);
		timeout_id2 = window.setTimeout(function(){
													$('js_room_type_open').disappear();
												}, 200);
	}
	
	//
	//
	//

	this.SelectRoomType = function(text, val)
	{
		$('js_dealform_room_type').innerHTML=text;
		$('js_room_type').value=val;
		
		switch(val)
		{
			case 1 : 
				$('js_room_type_open_1').setClass('selected');
				$('js_room_type_open_7').setClass('');
				break;
				
			case 7 :
				$('js_room_type_open_7').setClass('selected');
				$('js_room_type_open_1').setClass('');
				break;
		}
	}

	//
	//
	//

	this.ClickRoomType = function(text, val)
	{
		APP.PRICE.DEALS.SelectRoomType(text,val);

		(timeout_id1) && window.clearTimeout(timeout_id1);
		(timeout_id2) && window.clearTimeout(timeout_id2);
		$('js_room_type_open').disappear();
		$('js_dealform_submit_button').focus(); // focus submit button
	}
	
	//
	//
	//
	
	var node_unknown_path,
		node_destinationstring_select,
		node_dealform_error,
		node_deals,
		timeout_id1,
		timeout_id2;
};
//
// example searchstring - rotation
//
	
APP.ROTATION = function()
{
	//
	//
	//

	this.SetExampleStrings = function(arr)
	{
		rotation_strings = arr;
	}
		
	//
	//
	//

	this.Start = function(node_id)
	{
		this.SetRotationStatus(true);
		node = $(node_id);
		if ((node) && (node.isElement()))
		{
			node.setClass('text destination lighttext');
			this.setRandSearchstring(node.type == 'text');
		}
		display_string = '';
	}
		
	//
	//
	//

	this.Stop = function()
	{
		this.SetRotationStatus(false);
		
		if((!status) && (node))
		{
			node.setClass('text destination');
		}
	}
		
	//
	//
	//

	this.getRandSearchstring = function()
	{
		if(rotation_strings.length > 0)
		{
			var index = rand(0, rotation_strings.length-1);
			
			//is it the same string?
			if(display_string == rotation_strings[index])
			{
				index = ((index>0) ? --index : ++index);
			}

			return rotation_strings[index];
		}

		return '';

	}
		
	//
	//
	//

	this.setRandSearchstring = function(text_node)
	{
		try
		{
			if((this.GetRotationStatus()) && (rotation_strings))
			{
				if(text_node)
				{
					display_string = node.value = this.getRandSearchstring();
				}
				else
				{
					display_string = node.innerHTML = this.getRandSearchstring();
				}
				
				if (node.createTextRange)
				{
            		var part = node.createTextRange();
            		part.moveStart("textedit", 0);
            		part.moveEnd("textedit", -1);
            		//part.select();
        		}
        		else if (node.setSelectionRange)
        		{
            		node.setSelectionRange(0, 0);
            	}
				
				var me = this;
				window.setTimeout(function(){me.setRandSearchstring(text_node);}, (ttl*1000));
			}
		}
		catch(e)
		{
			COM.Log('APP.ROTATION.setRandSearchstring() - exception with node.type');
		}
	}
		
	//
	//
	//

	this.GetRotationStatus = function()
	{
		return status;
	}
	
	//
	//
	//

	this.SetRotationStatus = function(val)
	{
		status = val;
	}
		
	//
	//
	//

	this.IsInit = function()
	{
		return (typeof status == 'undefined') ? false : true;
	}
	
	//
	//
	//

	this.SetDelay = function(delay)
	{
		ttl = delay;
	}
		
	//
	// private vars
	//

	var rotation_strings,
		status,
		node = false,
		ttl = 3,
		display_string; //delay in seconds 
}

APP.CLICKOUT = new function()
{
	
	//
	//
	//
	
	this.HOpen = function(url, partner)
	{
		return this.Open(APP.LB.base64_decode(url), partner);
	}

	//
	//
	//

	this.Open = function(url, partner)
	{
		var newwindow = false;
		try
		{
			var height, 
				width, 
				left = 50, 
				top = 50;
			if (screen.height<=600 || screen.width<=800)
			{
				width = small_width;
				height = small_height;
			}
			else
			{
				width = big_width;
				height = big_height;
			}
			
			// data popup-size
			for (var i=0,n=pspecs.length; i<n; i++)
			{
				if (pspecs[i].partner==partner)
				{
					width = pspecs[i].width;
					height = pspecs[i].height;
					break;
				}
			}
			
			newwindow=window.open(url, 'trivagopop', 'resizable=yes,scrollbars=yes,menubar=yes,location=yes,toolbar=yes,width='+width+',height='+height+',innerWidth='+width+',innerHeight='+height+',titlebar=yes,left='+left+',top='+top);

			if (newwindow && window.focus)
			{
				newwindow.focus()
			}
		}
		catch(error) { }
	
		if (!newwindow)
		{
			window.location.href = url;
		}

		try
		{
			var temp = url.split("?");
			var params = temp[1].split("&");
			var item = false;
			
			for (var i=0; i < params.length; i++)
			{
				if (params[i].indexOf("item") != -1)
				{
					var parts = params[i].split("=");
					item = parts[1];
					break;
				}
			}
			
			if (item)
			{
				var timestamp = new Date().getTime();
				var transid = item+timestamp;

				basket = {
						products : [{
									identifier: item
								   }],
						transaction: transid
				};
				sociomantic.enable();
			}
		}
		catch(e) { }

		return false;
	}
	
	//
	//
	//
	
	var pspecs = [{"width":"1130","height":"700","scroll_offset":null,"partner":"2"},{"width":"1020","height":"700","scroll_offset":null,"partner":"3"},{"width":"1000","height":"700","scroll_offset":null,"partner":"5"},{"width":"1000","height":"700","scroll_offset":null,"partner":"8"},{"width":"1000","height":"700","scroll_offset":null,"partner":"9"},{"width":"910","height":"700","scroll_offset":null,"partner":"12"},{"width":"880","height":"700","scroll_offset":null,"partner":"13"},{"width":"1000","height":"700","scroll_offset":null,"partner":"14"},{"width":"980","height":"700","scroll_offset":null,"partner":"16"},{"width":"1120","height":"700","scroll_offset":null,"partner":"26"},{"width":"990","height":"700","scroll_offset":null,"partner":"28"},{"width":"900","height":"700","scroll_offset":null,"partner":"32"},{"width":"1010","height":"700","scroll_offset":null,"partner":"33"},{"width":"1030","height":"700","scroll_offset":null,"partner":"46"},{"width":"1040","height":"700","scroll_offset":null,"partner":"47"},{"width":"950","height":"700","scroll_offset":null,"partner":"51"},{"width":"950","height":"700","scroll_offset":null,"partner":"52"},{"width":"1040","height":"700","scroll_offset":null,"partner":"54"},{"width":"900","height":"700","scroll_offset":null,"partner":"55"},{"width":"1040","height":"700","scroll_offset":null,"partner":"59"},{"width":"1000","height":"700","scroll_offset":null,"partner":"60"},{"width":"900","height":"700","scroll_offset":null,"partner":"65"},{"width":"1000","height":"700","scroll_offset":null,"partner":"66"},{"width":"1025","height":"700","scroll_offset":null,"partner":"67"},{"width":"900","height":"700","scroll_offset":null,"partner":"69"},{"width":"1020","height":"700","scroll_offset":null,"partner":"71"},{"width":"950","height":"700","scroll_offset":null,"partner":"74"},{"width":"1000","height":"700","scroll_offset":null,"partner":"80"},{"width":"1070","height":"700","scroll_offset":null,"partner":"82"},{"width":"960","height":"700","scroll_offset":null,"partner":"85"},{"width":"960","height":"700","scroll_offset":null,"partner":"87"},{"width":"1030","height":"700","scroll_offset":null,"partner":"89"},{"width":"900","height":"700","scroll_offset":null,"partner":"93"},{"width":"1100","height":"700","scroll_offset":null,"partner":"105"},{"width":"900","height":"700","scroll_offset":null,"partner":"111"},{"width":"900","height":"700","scroll_offset":null,"partner":"113"},{"width":"900","height":"700","scroll_offset":null,"partner":"117"},{"width":"900","height":"700","scroll_offset":null,"partner":"193"},{"width":"1025","height":"700","scroll_offset":null,"partner":"195"},{"width":"1010","height":"700","scroll_offset":null,"partner":"201"},{"width":"900","height":"700","scroll_offset":null,"partner":"209"},{"width":"990","height":"700","scroll_offset":null,"partner":"217"},{"width":"900","height":"700","scroll_offset":null,"partner":"225"},{"width":"1020","height":"700","scroll_offset":null,"partner":"227"},{"width":"900","height":"700","scroll_offset":null,"partner":"229"},{"width":"1010","height":"700","scroll_offset":null,"partner":"267"},{"width":"1020","height":"700","scroll_offset":null,"partner":"279"},{"width":"940","height":"700","scroll_offset":null,"partner":"293"},{"width":"900","height":"700","scroll_offset":null,"partner":"295"},{"width":"980","height":"700","scroll_offset":null,"partner":"303"},{"width":"970","height":"700","scroll_offset":null,"partner":"309"},{"width":"1000","height":"700","scroll_offset":null,"partner":"323"},{"width":"1000","height":"700","scroll_offset":null,"partner":"331"},{"width":"1020","height":"880","scroll_offset":null,"partner":"335"}],
	
		small_width = 740,
		small_height = 580,
		
		big_width = 900,
		big_height = 700;
}

/**
* historic function - wrapper
*/
function popupPartner(url, partner) { APP.CLICKOUT.Open(url, partner); }
function pop(url){ APP.CLICKOUT.Open(url, -1); }

//
//
//

APP.SSG = function(subname, object_name)
{

	//
	//
	//

	this.Start = function()
	{
		//init vars
		_node_query          = $(subname+'string');
		_node_query_shadow   = $(subname+'string_shadow');
		_node_resultlist     = $(subname+'string_sug');
		_node_typelog     	 = $('dealform_typelog');
		_node_path           = $('destination_path');
		_node_item           = $('destination_item');
		_node_geoitem        = $('geo_distance_item');

		_highlight_value     = '';
		_highlight_itemid    = '';
		_highlight_itemtype  = '';
		_highlight_string    = '';
		_result_inner		 = '';
		_tp                  = 0;
		_countRows           = 0;
		_focus_changes       = false;
		
		var Me = this;
		this.SetSelectedIndex(0);
		_node_query.addEvent('keydown', function(eve, tar){Me.KeyPressDown(eve);});
		this.ClearResultList();
		_node_query_shadow.style.display = "block";
		_node_query.style.backgroundColor = "transparent";
	}
	
	//
	// return the key-code related by the browser
	//
		
	this.Getkeycode = function(e)
	{
		var doc = document;
		if(doc.layers)	
		{
			return e.which;
		}
		else if(doc.all)
		{
			return event.keyCode;
		}
		else if(doc.getElementById)
		{
			return e.keyCode;
		}
		else
		{
			return 0;
		}
	}

	//
	//
	//

	this.GetChangeFocus = function()
	{
		return _focus_changes;
	}

	//
	//
	//

	this.ClearChangeFocus = function()
	{
		_focus_changes = false;
	}
		
	//
	// related by the key, we must execute different code (handling for: escape, up/down array, return and different)
	//
		
	this.KeyPressDown = function(e)
	{
		var key_code = this.Getkeycode(e);
			
		switch (key_code)
		{
			case 27: // escape
				_highlight_string = '';
				if(_node_resultlist)
					_node_resultlist.style.display = 'none';
				_node_query_shadow.value = '';
				this.DisplayHideLists('');
				this.AbortConnection();
				break;
			
			case 38: // up arrow
			case 40: // down arrow
				this.HandleMove((key_code == 38 ? 'up' : 'down'));
				break;

			case  9: // tab
			case 13: // return
				if(_highlight_string)
				{
					_node_query.value = _highlight_string.replace(/\'/, "'");
			    	_node_path.value  = _highlight_value;
					_node_item.value  = _highlight_itemid;
				}
				_node_typelog.value = '1'+_node_typelog.value;
				
				this.ResetTimer();
				this.AbortConnection();
				this.ClearResultList();
				this.DisplayHideLists('');
				break;
					
			default:
				_highlight_string = '';
				_highlight_value  = '';
				_highlight_itemid  = '';
				_highlight_itemtype  = '';
				
				this.ClearChangeFocus();
				this.StartTimer();
				break;
		}
	}

	//
	//
	//	

	this.AbortConnection = function()
	{
		if(_request)
		{
			_request.abort();
		}
	}

	//
	//
	//	
	
	this.HandleMove = function(direction)
	{
		if ((_countRows > 0) && (!_node_resultlist.style.display=='inline'))
		{
			_node_resultlist.style.display='inline';
			return;
		}
		
		if(_countRows > 1) 
		{
			_focus_changes = true;
		}
		
		var selected_index = this.GetSelectedIndex();
	
		if((direction == 'down') && (this.GetSelectedIndex() != _countRows - 1))
		{
			this.SetSelectedIndex( ++selected_index );
		}
		else if ((direction == 'up') && (this.GetSelectedIndex() != 0))
		{
			this.SetSelectedIndex( --selected_index );
		}
				
		this.HighlightRow(true);
	}

	//
	//
	//

	this.HighlightRow = function(mousemove)
	{
	    var li = COM.GET.All('li', _node_resultlist),
	    	node;
	
	    for (var i=0, n=li.length; i<n; i++)
	    {
	        if (i == this.GetSelectedIndex())
	        {
	        	node = li[i];
	        	node.className    = 'highlight';
	            _highlight_value  = node.getAttribute('value');
	            _highlight_itemid = node.getAttribute('itemid');
	            _highlight_itemtype = node.getAttribute('type');
	            _highlight_string = node.getAttribute('name');
	            if(mousemove == true)
	            {
					_node_query.value 			= _highlight_string.replace(/\'/, "'");
			    	_node_path.value  			= _highlight_value;
					_node_item.value  			= _highlight_itemid;
					_node_query_shadow.value 	= '';         
	            }
	        }
	        else
	        {
	        	li[i].className = (i%2==0) ? 'blue' : '';
	        }
	    }
	}

	//
	//
	//

	this.GetQuery = function()
	{
		if (_node_query.value.length == 0)
		{
			this.ClearResultList();
			return '';
		}

		return (_node_resultlist.currentQuery = _node_query.value);
	}

	//
	//
	//

	this.MouseClick = function(query, path_id, item_id, type)
	{
		_node_path.value  = path_id;
		_node_item.value  = item_id;
		_node_query.value = query.replace(/\'/, "'");
		_node_typelog.value = '0'+_node_typelog.value;
		
		APP.PRICE.DEALS.SwitchItemPage(path_id, item_id, type);
		
		this.ClearResultList();
		this.DisplayHideLists('');
	}
	
	//
	//
	//
	
	this.Close = function()
	{
		if((_node_typelog.value.substring(0,1)!='0')
			&& _node_typelog.value.substring(0,1)!='1'
			&& _node_typelog.value.substring(0,1)!='3'
			)
		{
			_node_typelog.value = '2'+_node_typelog.value;
		}
	
		this.ClearResultList();
		this.DisplayHideLists('');
	}

	//
	//
	//

	this.MouseOut = function()
	{
		this.SetSelectedIndex(-1);
		this.HighlightRow(false);
	}

	//
	//
	//

	this.MouseOver = function(i)
	{
		if (!_disable_hover_event)
		{
			this.SetSelectedIndex(i);
			this.HighlightRow(false);
		}
	}
	
	//
	//
	//
	
	this.Blur = function()
	{
		if(_highlight_string)
		{
			_node_query.value = _highlight_string.replace(/\'/, "'");
		   	_node_path.value  = _highlight_value;
			_node_item.value  = _highlight_itemid;
		}
	}

	//
	//
	//
		
	this.ClearResultList = function()
	{
		if (_node_resultlist)
		{
			_node_resultlist.style.display='none';
			_node_resultlist.innerHTML = '';
		}
		_node_query_shadow.value = '';
		_countRows = 0;
		this.SetSelectedIndex(0);
	}

	//
	//
	//

	this.AppendRow = function(query, c, sel, splitline, showtype, name, type, item_id)
	{
		if (!_node_resultlist) 
		{
			return;
		}
			
		this.SetSelectedIndex(0);
		
		var css_class = (sel==0 ? 'highlight' : ((sel%2==0) ? "blue" : ""));
		var css_class2 = "";
		
		if (splitline==1)
		{
			css_class2 = "splitline";
		}
		
		type_title = "";
		
		switch(showtype)
		{
			case 1:
				type_title = '<span class="ssgregion">ciudades/regiones<i class="sprite_icon">&nbsp;</i></span>';
				break;
			case 2:
				type_title = '<span class="ssgattraction">cerca de<i class="sprite_icon">&nbsp;</i></span>';
				break;
			case 3:
				type_title = '<span class="ssghotel">Hoteles<i class="sprite_icon">&nbsp;</i></span>';
				break;
		}
		
		if(showtype==5)
		{
			var didyoumean_title = 'NingÃºn resultado para \"$usersearchstring\"';
			didyoumean_title = didyoumean_title.split('$usersearchstring').join(_node_query.value);
			_result_inner += '<li class=""><a class="didyoumean">'+didyoumean_title+'</a></li>';
			
			_node_typelog.value = '3'+_node_typelog.value;		
		}
		else
		{
			_result_inner += '<li class="' + css_class + '" value="' + c + '" itemid="' + item_id + '" name="' + name + '" type="' + type + '" '
			 		+ ' onmouseover="'+object_name+'.MouseOver(' + _countRows + ');"'
			 		+ ' onmouseout="'+object_name+'.MouseOut();"'
			 		+ ' onclick="'+object_name+'.MouseClick(\'' + name.replace(/'/, "\\\'") + '\', \'' + c +'\',\'' + item_id +'\',\'' + type +'\');"><a class="' + css_class2 + '">'+ type_title + query + '</a></li>';		
		}
		
		++_countRows;
	}

	//
	//
	//
	
	this.AppendCloseRow = function()
	{
		_result_inner += '<li><a onclick="'+object_name+'.Close();" class="splitline ssgclose"><span class="ssgcloseimg sprite_icon">&nbsp;</span>Cerrar</a></li>';
		this.SetHoverEvent(true);
		_node_resultlist.innerHTML = _result_inner;
		window.setTimeout(function(){APP.PRICE.DEALS.SSG.SetHoverEvent(false);}, 100);
		_result_inner = '';
	}
	
	//
	//
	//
	
	this.SetHoverEvent = function(stat)
	{
		_disable_hover_event = stat;
	}

	//
	//
	//
	
	this.HoverSsgCloseMsgHook = function()
	{
		if(!this.SsgCloseMsg)
		{
			this.SsgCloseMsg = COM.GET.Elem('ssg_close_msg');
		}
	}
	
	//
	//
	//
	
	this.HoverSsgCloseMsgIn = function()
	{
		this.HoverSsgCloseMsgHook();
		this.SsgCloseMsg.show();
	}
	
	//
	//
	//
	
	this.HoverSsgCloseMsgOut = function()
	{
		this.HoverSsgCloseMsgHook();
		this.SsgCloseMsg.hide();
	}
	
	//
	//
	//

	this.StartRequest = function(base_rpc_url)
	{
		var q,
			enable_error_message = (typeof base_rpc_url != 'undefined');
		
		if((q = this.GetQuery()) != '')
		{
			_node_typelog.value = q;
			
			if (typeof base_rpc_url == 'undefined')
			{
				base_rpc_url = '/trivago_rpc.php?action=ssg_sphinx';
			}
		
			if(_node_query.value.toLowerCase() != _node_query_shadow.value.toLowerCase().substring(0,_node_query.value.length)
				&& _node_query.value.length > 1)
			{
				_node_query_shadow.value = '';
			}
			this.AbortConnection();
			_request = new COM.HTTP.Request('GET', base_rpc_url+'&v=v6_02_2ac&path=' + APP.Retrieve('CURRENTPATH') + '&q=' + encodeURIComponent( q ),{
						  'onfinish':function(str){
						  	if (str && str!='[]')
						  	{
						  		APP.PRICE.EvalCode(object_name+".GetResponse(" + str + ");");
						  		if (enable_error_message && eval(str).length==1)
							  	{
							  		APP.PRICE.DEALS.OnSubmit();
							  	}
						  	}
						  	else if (enable_error_message)
						  	{
						  		$('dealform_error').appear();
						  		$('unknown_path').appear();
						  		$('unknown_path').innerHTML = ("No pudimos encontrar ningÃºn resultado para \"$string\".<br />Por favor revisa que tus datos de bÃºsqueda sean correctos.").split('$string').join(q);
						  		$('destinationstring').focus();
						  	}
						  }});
			_request.start();
		}
		else
		{
			this.ClearResultList();
			this.DisplayHideLists('');
		}
	}

	//
	//
	//

	this.GetResponse = function(_data)
	{
		if (this.GetQuery() == '')
		{
			this.DisplayHideLists('');
			return;
		}

		this.DisplayHideLists('none');	
		this.ClearResultList();
	
		if((_data) && (_data.length > 0))
		{
			// display dropdown-list
			if(_node_resultlist)
				_node_resultlist.style.display='block';
	
			first_name_clear   = _data[0][0].replace(/{/g,"").replace(/}/g,"");
	
			// fill the dropdown-list
			if((_data.length > 1) || (_node_query.value.length !=_data[0][0].length))
			{
				var _type = 0;
				var _splitline = 0;
				var _showtype = 0;
				
				for (var i = 0; i < _data.length; i++)
				{
					if(_type > 0 && _type != _data[i][4])
					{
						_splitline = 1;
						_showtype = _data[i][4];
					} 
					else
					{
						_splitline = 0;
						_showtype = 0;
					}
					
					if (i==0)
					{
						_showtype = _data[i][4];
					}
					
					name_clear   = _data[i][0].replace(/{/g,"").replace(/}/g,"");
					
					name		 = _data[i][0].replace(/{/g,"<kbd>").replace(/}/g,"</kbd>");
					name		+= "<i>, "+ _data[i][3].replace(/{/g,"<kbd>").replace(/}/g,"</kbd>") + " </i>";
					
					this.AppendRow(name, _data[i][1], i, _splitline, _showtype, name_clear, _data[i][4], _data[i][2]);
					_type = _data[i][4];
				}
				
				this.AppendCloseRow();
				
				if(_node_query.value.toLowerCase() == first_name_clear.toLowerCase().substring(0,_node_query.value.length)
					&& _node_query.value.length > 1 && _node_query.value.length < 25)
				{
				 	_node_query_shadow.value = _node_query.value + first_name_clear.toLowerCase().substring(_node_query.value.length);
				}
				else
				{
					_node_query_shadow.value = '';
				}
				
				_highlight_string 		= first_name_clear;
				_highlight_value  		= _data[0][1];
				_highlight_itemtype  	= _data[0][4];
				_highlight_itemid  		= _data[0][2];
			}
			else
			{
				// automatically selection
				_node_resultlist.value = _data[0][1];
	
				name_clear   = _data[0][0].replace(/{/g,"").replace(/}/g,"");
	
				if(_node_query.value.length == _data[0][0].length)
				{
					_node_query.value              = name_clear;
					_node_path.value               = _data[0][1];
					_node_resultlist.style.display = 'none';
				}
				else
				{
					this.HighlightRow(false);
				}
											
				_highlight_string 		= name_clear;
				_highlight_value  		= _data[0][1];
				_highlight_itemtype  	= _data[0][4];
				_highlight_itemid  		= _data[0][2];
				
				this.ClearResultList();
				this.DisplayHideLists('');
			}
		}
		else
		{
			this.DisplayHideLists(''); //empty list
		}
	}

	//
	//
	//

    this.StartTimer = function()
	{
		var Me = this;
		if (_tp > 0) 
		{
			this.ResetTimer();
		}
		_tp = window.setTimeout(function(){Me.StartRequest();}, 100);
	}

	//
	//
	//

	this.ResetTimer = function()
	{
		if (_tp > 0)
		{
			window.clearTimeout(_tp);
		}
		_tp = 0;
	}

	//
	//
	//

	this.SetSelectedIndex = function(val)
	{
		_selectedIndex = val;
	}

	//
	//
	//

	this.GetSelectedIndex = function()
	{
		return _selectedIndex;
	}
	
	//
	//
	//
	
	this.DisplayHideLists = function(val)
	{
		try
		{
			APP.PRICE.DEALS.HideError();
		}
		catch(e){}	
	}
	
	//
	//
	//
	
	this.GetHighlightValue = function()
	{
		return _highlight_value;
	}
	
	this.GetHighlightItemId = function()
	{
		return _highlight_itemid;
	}
	
	this.GetHighlightItemType = function()
	{
		return _highlight_itemtype;
	}
		
	//
	// private vars
	//
		
	var _highlight_string,
		_tp,
		_node_query,
		_node_query_shadow,
		_node_resultlist,
		_node_path,
		_node_item,
		_node_geoitem,
		_countRows,
		_selectedIndex,
		_focus_changes,
		_highlight_value,
		_highlight_itemid,
		_highlight_itemtype,
		_result_inner,
		_disable_hover_event = false,
		_request;
}

APP.PRICE.DEALS.SSG = new APP.SSG('destination', 'APP.PRICE.DEALS.SSG');
function mouse_pos(e)
{
	if(!e)
	{
		e = window.event;
	}
	var body = (window.document.compatMode
					&& (window.document.compatMode == "CSS1Compat")) ?
				window.document.documentElement : window.document.body;
	var retval =
	{ // position in the document
		top: (e.pageY ? e.pageY : e.clientY + body.scrollTop - body.clientTop),
		left: (e.pageX ? e.pageX : e.clientX + body.scrollLeft  - body.clientLeft)
	};
	return retval;
}

function mouse_pos_rel(elem, e)
{
	var pos = mouse_pos(e);
	var retval =
	{ // position relative to elem
		top: (pos.top - elem.getTop()),
		left: (pos.left - elem.getLeft())
	};
	return retval;
}

//
//
//

APP.TopListFeature = new function()
{
	var _request,
		_timeout_id,
		displayed_list      = 0,
		maxScrollStep       = 12,
		maxScrollAngle      = 1,
		containerOffsetTop  = 0,
		scrollIntervallTime = 1,
		step    = 0,
		htop    = null,
		hbottom = null,
		toplist_elem = null;

	this.moveUp   = null;
	this.moveDown = null;

	//
	//
	//

	this.Init = function(node_id)
	{
		var nodes = $(node_id).getElementsByTagName('em'),
			id;

		for(var i=0, n=nodes.length; i < n; i++)
		{
			id = $(nodes[i]).getAttribute('id');
			if(id && id.substring(0, 5) == 'path_')
			{
				nodes[i].addEvent(
					         'click',
							 "APP.TopListFeature.Set('"+id+"'); return false;");
				var links = nodes[i].getElementsByTagName('a');
				if(links.length == 1)
				{
					links[0].href = 'javascript:void(0); return false;';
				}

				if(i < 10)
				{
    			    var path = id.split('_');
    				nodes[i].addEvent(
    								  'mouseover',
    								  'APP.HOME_ROTATION.LoadPath('
    								      + path[1]
    								      + ", {'delay': 100});");
    			}
			}
		}
	}

	//
	//
	//

	this.Set = function(node)
	{
	    var path = $(node).getAttribute('id').split('_');
		APP.PRICE.DEALS.SwitchItemPage(path[1], 0);
		$('destinationstring').value = $(node).getAttribute('name');
		$(node).href = "#";
		APP.PRICE.DEALS.OnSubmit();
		return false;
	}

	//
	//
	//

	this.addScrolling = function()
	{
		if(Browser.Gecko)
		{
			maxScrollStep = 40;
		}
		var topelements = $("scroll_canvas").getElementsByTagName('em');
		if(10 < topelements.length)
		{
			htop = $('hotspot_top');
			hbottom = $('hotspot_bottom');
			maxScrollAngle = Math.round(
				(topelements.length - 10) *
				(-1 * topelements[0].offsetHeight));
			toplist_elem = topelements[0];
			if(!(toplist_elem.style.marginTop))
			{
				toplist_elem.style.marginTop = "0px";
			}
			this.addScrollEvents();
			var tf = $('all_toplistfeature');
			containerOffsetTop = tf.offsetTop;
			tf.onmouseover = function()
				{
					htop.show();
					hbottom.show();
				};
			tf.onmouseout = function()
				{
					htop.hide();
					hbottom.hide();
				}
		}
	}

	//
	//
	//

	this.addScrollEvents = function()
	{
		htop.onmouseover = function()
		{
			this.moveUp =
				window.setInterval(function()
				{
					var oldVal = parseInt(toplist_elem.style.marginTop);
					if(oldVal < 0)
					{
						var newVal = oldVal - step;
						if(-1 > newVal)
						{
							toplist_elem.style.marginTop = newVal + 'px';
							hbottom.appear();
						}
						else
						{
							toplist_elem.style.marginTop = '0px';
							htop.disappear();
						}
					}
				}, scrollIntervallTime);
		}
		htop.onmouseout = function()
		{
			APP.TopListFeature.snapScrolling();
			window.clearInterval(this.moveUp);
		}
		htop.onmousemove = function(evt)
		{
			var pos = mouse_pos_rel(htop, evt);
			step = -1 * (1 - Math.sqrt((pos.top - containerOffsetTop) / htop.offsetHeight)) * maxScrollStep;
	    }
		htop.onmousedown = function()
		{
			window.clearInterval(this.moveUp);
			htop.disappear();
			window.setTimeout(function()
			{
				htop.appear();
			}, 3300);
		}
		hbottom.onmouseover = function()
		{
			this.moveDown =
				window.setInterval(function()
				{
					var oldVal = parseInt(toplist_elem.style.marginTop);
					if(oldVal > maxScrollAngle)
					{
						var newVal = oldVal - step;
						if(newVal > maxScrollAngle)
						{
								toplist_elem.style.marginTop = newVal + 'px';
								htop.appear();
						}
						else
						{
							toplist_elem.style.marginTop = maxScrollAngle + 'px';
							hbottom.disappear();
						}
					}
				}, scrollIntervallTime);
		}
		hbottom.onmouseout = function()
		{
			APP.TopListFeature.snapScrolling();
			window.clearInterval(this.moveDown);
		}
		hbottom.onmousedown = function()
		{
			window.clearInterval(this.moveDown);
			hbottom.disappear();
			window.setTimeout(function()
			{
				hbottom.appear();
			}, 3300);

		}
		hbottom.onmousemove = function(evt)
		{
			var pos = mouse_pos_rel(hbottom, evt);
			step = (1 - Math.sqrt((hbottom.offsetHeight + containerOffsetTop - pos.top) / hbottom.offsetHeight)) * maxScrollStep;
		}
	}

	this.snapScrollTo = function(iElemMaxScrollAngle)
	{	
		if('number' != typeof iElemMaxScrollAngle)
		{
			return;
		}
		// set minimal speed, if initial value too low
		if(0 < step)
		{ // scrolling down
			if(3 > step)
			{
				step = 3;
			}
		}
		else
		{ // scrolling up
			if(-3 < step)
			{
				step = -3;
			}
		}
		
		var iNewVal = parseInt(toplist_elem.style.marginTop) - step;		
		var bScrollingNeeded = false;
		if(0 < step)
		{ // scrolling down
			bScrollingNeeded = (iElemMaxScrollAngle < Math.ceil(iNewVal));
		}
		else
		{ // scrolling up
			bScrollingNeeded = (iElemMaxScrollAngle > Math.floor(iNewVal));
		}
		
		if(bScrollingNeeded)
		{
			toplist_elem.style.marginTop = iNewVal + 'px';
			window.setTimeout(function()
				{
					APP.TopListFeature.snapScrollTo(iElemMaxScrollAngle);
				}, scrollIntervallTime);
		}
		else
		{
			toplist_elem.style.marginTop = iElemMaxScrollAngle + 'px';
			if(-1 < iElemMaxScrollAngle)
			{
				htop.disappear();
			}
			else if(maxScrollAngle >= iElemMaxScrollAngle)
			{
				hbottom.disappear();
			}
		}
	}
	
	this.snapScrolling = function()
	{
		if(0 < step)
		{ // scrolling down
			this.snapScrollTo(
							  Math.floor(
							      parseInt(toplist_elem.style.marginTop)
							      / toplist_elem.offsetHeight)
							  * toplist_elem.offsetHeight);
		}
		else
		{ // scrolling up
			this.snapScrollTo(
							  Math.ceil(
				                  parseInt(toplist_elem.style.marginTop)
				                  / toplist_elem.offsetHeight)
				              * toplist_elem.offsetHeight);
		}
	}

}
APP.LB = new function()
{
	//
	//
	//
	
	this.Set = function(atag, url, new_window)
	{
		var uri;
		
		// backward compatible behavior
		if((arguments.length < 3) || (!((typeof new_window) == 'boolean')))
		{
			new_window = (atag.getAttribute('target') == '_blank');
		}
		
		if(!(uri = this.base64_decode(url)))
		{
			//error situation go to the homepage
			uri = '/';
		}

		if(new_window)
		{
			window.open(uri);
		}
		else
		{
			window.location.href = uri;
		}
	},
	
	//
	//
	//
	
	this.base64_decode = function(string)
	{
		var retval = '';

		if (string)
		{
			var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
			var code1, code2, code3;
			var h1, h2, h3, h4; 
			var bits;
			var i = 0; 
			var arr_i = 0, 
				arr   = [];

			string += '';
		 
			do
			{
				h1 = b64.indexOf(string.charAt(i++));
				h2 = b64.indexOf(string.charAt(i++));
				h3 = b64.indexOf(string.charAt(i++));
				h4 = b64.indexOf(string.charAt(i++));
		 
				bits = h1<<18 | h2<<12 | h3<<6 | h4;
				code1 = bits>>16 & 0xff;
				code2 = bits>>8  & 0xff;
				code3 = bits     & 0xff;
		 
				if (h3 == 64)
				{
					arr[arr_i++] = String.fromCharCode(code1);
		        }
		        else if (h4 == 64)
		        {
					arr[arr_i++] = String.fromCharCode(code1, code2);
		        }
		        else
		        {
					arr[arr_i++] = String.fromCharCode(code1, code2, code3);
				}
		    }
		    while (i < string.length);
		 
		    retval = arr.join('');
	    }
	
	    return retval;
	}
}

//
//
//

APP.SIMILAR_ITEMS = new function()
{
	//
	//
	//

	this.Left = function(node_id, count_items)
	{
		var pos = $(node_id).style.left.split('px').join('');
		var width = $($(node_id).getElementsByTagName('div')[0]).getWidth() + 10;
		if ((count_items-3)*width > pos*-1)
		{
			$('js_similar_item_right').className = 'button button_right_active';
			$('js_similar_item_left').className = 'button button_left_active';
			$(node_id).style.left = (pos - width)+'px';
			pos = (pos - width);
		}
		if ((count_items-3)*width <= pos*-1)
		{
			$('js_similar_item_right').setClass('button button_right_inactive');
		}
	}
	//
	//
	//

	this.Right = function(node_id)
	{
		var pos = $(node_id).style.left.split('px').join('');
		var width = $($(node_id).getElementsByTagName('div')[0]).getWidth() + 10;
		if (pos < 0)
		{
			$('js_similar_item_left').className = 'button button_left_active';
			$('js_similar_item_right').className = 'button button_right_active';
			$(node_id).style.left = (pos - (-1*width))+'px';
			pos = (pos - (-1*width));
		}
		if (pos >= 0)
		{
			$('js_similar_item_left').className = 'button button_left_inactive';
		}
	}
}

APP.FORWARD = new function()
{
	var timer_seconds = 3,
		page_start_time = '',
		timer_id = false,
		tracking_codes,
		node_forward_link,
		node_headline1,
		node_timer_seconds,
		node_tracking_codes,
		node_website_performance,
		
		clickout_partner,
		
		performance_log,
		
		start_time;

	//
	//
	//
	
	this.Init = function(tracking_urls, partner, ppage_start_time)
	{
		tracking_codes = tracking_urls;
		clickout_partner = partner;
		node_forward_link = $('js_forward_link');
		node_headline1 = $('js_headline1');
		node_timer_seconds = $('js_timer_seconds');
		node_tracking_codes = $('js_tracking_codes');
		node_website_performance = $('js_website_performance');
		page_start_time = ppage_start_time;
	}

	//
	//
	//

	this.Start = function(service_id, item, type, rate_key, partner, item2partner, arrival, departure, room_type, soap_client_id, redirect_url)
	{
		start_time = new Date();
		COM.HTTP.Get('/trivago_rpc.php?action=booking_url&service_id=' + service_id + "&item=" + item + "&type=" + type 
										+ "&rate_key=" + rate_key + "&partner=" + partner + "&item2partner=" + item2partner
		 								+ "&arrival=" + arrival + "&departure=" + departure + "&room_type=" + room_type + "&soap_client_id=" + soap_client_id, {
					 "onfinish":function(json_code){
					 	if (json_code)
					 	{
					 		APP.PRICE.EvalCode("APP.FORWARD.UpdateDesign(" + json_code + ");");
						}
						else
						{
							// error situation
							window.location.href=redirect_url;
						}
					 }});
	}
	
	//
	//
	//
	
	this.UpdateDesign = function(json_code)
	{
		var time_diff = timer_seconds - Math.round((new Date().getTime() - start_time.getTime())/1000);
		timer_seconds = node_timer_seconds.innerHTML = (time_diff<=1 ? 1 : time_diff);
		node_forward_link.href = json_code.url;
		node_forward_link.appear();
		
		this.CallTrackings(json_code.url);
		this.Redirect();
	}
	
	//
	//
	//

	this.Redirect = function()
	{
		performance_log = new Date();
		
		window.addEvent('unload', function(){APP.FORWARD.Unload();});

		window.location.href = node_forward_link.href;
	}
	
	//
	//
	//
	
	this.Unload = function()
	{
		try
		{
			if (page_start_time)
			{
				var url = '/trivago_rpc.php?action=website_performance&page_start_time='+page_start_time+'&partner='+clickout_partner+'&speed='+Math.round((new Date().getTime() - performance_log.getTime()));
				node_website_performance.innerHTML = "<img src=\""+url+"\" width=\"1\" height=\"1\" />";
			}
		}
		catch(e){}
	}
	
	//
	//
	//
	
	this.CallTrackings = function(url)
	{
		var html_trackings = '';

		if (tracking_codes)
		{
			for (var i=0, n=tracking_codes.length; i<n; i++)
			{
				html_trackings += "<img src=\""+tracking_codes[i].split('<url>').join(encodeURIComponent(url))+"\" width=\"1\" height=\"1\" />";
			}
		
			node_tracking_codes.innerHTML = html_trackings;
		}
	}
};
/**
 * $Id: $
 *
 * This is a class that provides global helper methods 
 *
 * @class HELPER
 * @author tschulte
 * @since 12.04.2011
 */
APP.HELPER = new function()
{

	/**
	 * Toggle content of a container and switch text for more/less Button
	 *
	 * @param tid	The ID of the target button that will be toggled
	 * @param sid	The ID of the source button that will optionally be toggled with tid.
	 * @param bstyle The element style of the button, block|inline default block
	 */
	this.toggleMoreLess = function(tid, sid, bstyle)
	{
		var node = $(tid);
		var elem_style = 'block';
		if (	typeof(bstyle) != 'undefined' &&
				bstyle == 'inline'	)
		{
			elem_style = 'inline';
		}
	
		if (	node.style.display == 'none'	)
		{
			node.style.display = elem_style;
			if (sid)
			{
				$(sid).disappear();	
			}			
		}
		else
		{
			node.disappear();
			if (sid)
			{
				$(sid).style.display = elem_style;
			}
		}
		
		if (typeof($(tid+'_b').id) != 'undefined')
		{
			$(tid+'_b').toggle();
		}
		   
		return false;
	},
	
	/**
	 * Format given number to locale specific numbers format
	 *
	 * @param d number
	 * @param a accuracy (digits)
	 */
	 this.numberFormat = function(d, a)
	 {
		d = parseFloat(d);
		a = (a && a > 0) ? a : 0;
		
		if(isNaN(d))
		{
			d = 0;
		}
		
		var dp = APP.Retrieve('decimal_point');
		var ts = APP.Retrieve('thousands_sep');
		var b = String(Math.floor(d));
		var n = b.length, s = '', p = '';
		
		for(i=0; i < n; ++i)
		{
			s += b.charAt(i);
			s += ((n-1-i)%3 == 0 && (n-1) != i) ? ts : '';
		}
		
		if (	a != 0 &&
				String(d).indexOf('.') != -1 && 
				String(d).substr(String(d).indexOf('.')+1).length != 0	)
		{
			p += dp;
			p += String(d).substr(String(d).indexOf('.')+1, a);		
		}

		return s + p;
	 }
};//
// Templating for Javascript
//
// Templates must be first registered with method Register
// then they can be executed on a node with direct inserting HTML
// or return generated string
//
// @author crankers
// @since 28.05.2011
//
APP.TPL = new function()
{

	//
	// internal registered templates
	//
	// @author crankers
	// @since 28.05.2011
	//
	// @var (object)
	//
	var T = {};

	//
	// register a template string with id
	// with id template can be applied
	// placeholder vars should be inserted with #varname#
	//
	// @author crankers
	// @since 28.05.2011
	//
	// @param (string) id - id of template to access
	// @param (string) t - template string
	//
	// @return (boolean)
	//
	this.Register = function(id, t)
	{
		return (T[id] = t);
	};

	//
	// applies a template by id access to arguments a
	// format of element from a must be:
	//  [<id>, <var_object>] - <id> is name of template, <var_object> object with names and values
	//  <var_object> e.g. { 'var':'value_to_be_printed' }
	//
	// @author crankers
	// @since 28.05.2011
	//
	// @param (string) id - id of template to access
	// @param (object) a - argument vars to be replaced
	//
	// @return (string)
	//
	this.Apply = function(id, a)
	{
		if (typeof T[id] == 'undefined')
		{
			return '';
		}

		s = T[id];
		for(var p in a)
		{
			s = s.replace(new RegExp('#'+p+'#', 'g'), a[p]);
		}

		return s.replace(/#\w+#/g, '');
	};

	//
	// applies list of templates and replace into given dom element
	// format of element from a must be:
	//  [<id>, <var_object>] - <id> is name of template, <var_object> object with names and values
	//  <var_object> e.g. { 'var':'value_to_be_printed' }
	//
	// @author crankers
	// @since 28.05.2011
	//
	// @param (object dom) - dom element to insert
	// @param (array) a - array of templates with elements like [<id>, <var_object>]
	//
	// @return (boolean)
	//
	this.Insert = function(d, a)
	{
		if (d)
		{
			h = '';
			for(var i=0,n=a.length;i!=n;++i)
			{
				h += this.Apply(a[i][0], a[i][1]);
			}

			d.innerHTML = h;
			return true;
		}

		return false;
	};

};//
// collapses given elements and can open them again,
// initial state is given by settings
//
// @author crankers
// @since 09.08.2011
//
APP.COLLAPSE = new function()
{
	
    //
    //  private vars
    //
    //  S - (object) Settings for given ids
    //
    var S = {};
	
	//
	// Add a new collapse entry and inits it, when not already added.
	// Use of function is public.
	//
	// @author crankers
	// @since 09.08.2011
	//
	// @return (boolean)
	//
	this.Add = function(id, s)
	{
		if (	(	typeof S[id] == 'undefined' ||
					S[id] === null	) &&
				$(id).isElement()	)
		{
			S[id] = {};
			
			S[id]['state'] = 'open';
			S[id]['parent'] = $(id).parentNode;
			
			(typeof s['close'] == 'undefined') || (S[id]['close'] = s['close']);
			(typeof s['open'] == 'undefined') || (S[id]['open'] = s['open']);
			(typeof s['state'] == 'undefined') || (S[id]['state'] = s['state']);
			(typeof s['elem'] == 'undefined') || (S[id]['elem'] = s['elem']);
			(typeof s['parent'] == 'undefined') || (S[id]['parent'] = s['parent']);
			(typeof s['onopen'] == 'undefined') || (S[id]['onopen'] = s['onopen']);
			(typeof s['onclose'] == 'undefined') || (S[id]['onclose'] = s['onclose']);

			$(id).insertBefore(
				COM.Element(['a', {'href':'javascript:void(0);', 'onclick':'APP.COLLAPSE.Toggle(\''+id+'\');'}, [S[id][S[id]['state']]]]),
				$(id).firstChild
			);
			S[id]['node'] = $(id).firstChild;

			S[id]['childs'] = [];
			(typeof S[id]['elem'] == 'string') && (S[id]['elem'] = [S[id]['elem']]);
			
			for(var i=0,n=S[id]['elem'].length;i<n;++i)
			{
				c = COM.GET.All(S[id]['elem'][i], S[id]['parent']);
				for(var j=0,m=c.length;j<m;++j)
				{
					if (c[j].hasClass(id+'_collapse'))
					{
						S[id]['childs'].push(c[j]);
					}
				}
			}
			
			this.Switch(id, S[id]['state']);

			return true;
		}

		return false;
	};

	//
	// Delete a collapse entry.
	// Use of function is public.
	//
	// @author crankers
	// @since 14.10.2011
	//
	// @return (boolean)
	//
	this.Del = function(id)
	{
		if (typeof S[id] != 'undefined')
		{
			S[id] = null;
		}
	};

	//
	// Switch element visibility to given id and to given (v)isibility.
	// Use of function is private.
	//
	// @author crankers
	// @since 09.08.2011
	//
	// @return (boolean)
	//
	this.Switch = function(id, v)
	{
		if (typeof S[id] == 'undefined')
		{
			return false;
		}

		switch(v)
		{
			case 'open':
				S[id]['node'].replaceChild(COM.Element(S[id]['open']), S[id]['node'].firstChild);

				for(var i=0,n=S[id]['childs'].length;i<n;++i)
				{
					S[id]['childs'][i].appear();
				}
				
				return (S[id]['state'] = 'open');

			case 'close':
				S[id]['node'].replaceChild(COM.Element(S[id]['close']), S[id]['node'].firstChild);

				for(var i=0,n=S[id]['childs'].length;i<n;++i)
				{
					S[id]['childs'][i].disappear();
				}

				return (S[id]['state'] = 'close');
		}
		
		return false;
	};

	//
	// Toggle element (v)isibility to given id.
	// Use of function is public.
	//
	// @author crankers
	// @since 09.08.2011
	//
	// @return (boolean)
	//
	this.Toggle = function(id)
	{
		if (typeof S[id] == 'undefined')
		{
			return false;
		}

		switch(S[id]['state'])
		{
			case 'open':
				this.Switch(id, 'close');
				(typeof S[id]['onclose'] == 'function') && S[id]['onclose']();
				return true;

			case 'close':
				this.Switch(id, 'open');
				(typeof S[id]['onopen'] == 'function') && S[id]['onopen']();
				return true;
		}

		return false;
	};

};APP.BOOKMARK = new function()
{

    //
    //
    //

	this.Exec = function(favorites)
	{
		var node;
		 
		node = $('social_network_button_print');		
		node.appear();
		node.addEvent('click', function(){window.print();})
		
		node = $('social_network_button_email');
		node.appear();
		node.addEvent('click', function(){window.mailTo('', document.title, document.location.href);})
		
		node = $('social_network_button_favorites');
		node.appear();
		node.addEvent('click', function(){window.addBookmark(document.location.href, document.title, favorites);})
	}
}


APP.EFFECT = new function()
{
	/**
	* SlideUp one Element
	* 
	* @param node is the dom-element for sliding
	* @param params is a object with the following options:
	* - scaleX : horizontal scale (true | false)
	* - scaleY : vertical skalieren (true | false)
	* - duration : Time between steps in seconds
	* - steps : render-steps (integer)
	* - onfinish : execute function with the onfinish-event
	* - onbegin : execute function before we start the sliding
	* - onchange : execute function with every sliding-call
	* - target_size : target slide-size in px. 0px for very small
	*/
	this.SlideUp = function(node, params)
	{
		return new APP.EFFECT.Slide(node, 1, params);
	}
	
	/**
	* SlideDown one Element
	* 
	* @param node is the dom-element for sliding
	* @param params is a object with the following options:
	* - scaleX : horizontal scale (true | false)
	* - scaleY : vertical skalieren (true | false)
	* - duration : Time between steps in seconds
	* - steps : render-steps (integer)
	* - onfinish : execute function with the onfinish-event
	* - onbegin : execute function before we start the sliding
	* - onchange : execute function with every sliding-call
	* - target_size : target slide-size in px
	*/
	this.SlideDown = function(node, params)
	{
		return new APP.EFFECT.Slide(node, 0, params);
	}
	var timeout_id;
	/**
	*
	*/
	this.Slide = function(node, alignment, options)
	{
		var pos,
			one_step_y,
			one_step_x,

			startSizes,
			is_finish;
		var Me = this;
		
		this.Init = function()
		{
			// set automatic the missing options
			(!options.steps) && (options.steps=5);
			(!options.duration) && (options.duration=0.05);

			// init vars
			this.startSizes = {'height':$(node).getHeight(), 'width':$(node).getWidth()};
			if (alignment)
			{
				this.one_step_y = Math.round(this.startSizes.height/options.steps);
				this.one_step_x = Math.round(this.startSizes.width/options.steps);
			}
			else
			{
				this.one_step_y = Math.round(options.target_size/options.steps);
				this.one_step_x = Math.round(options.target_size/options.steps);
			}
			this.pos = 1;
			node.setStyle('overflow', 'hidden');

			// init events
			for (var event in {'begin':1,'finish':1,'change':1})
			{
				(options['on'+event]) && (options['on'+event] = COM.GET.Function(options['on'+event]));
			}
			
			//execute onbegin-event
			(options['onbegin']) && (options['onbegin']());
		}
		
		//
		//
		//

		this.Exec = function()
		{
			if (alignment == 1) // slide-up
			{		
				var new_y = this.startSizes.height - this.one_step_y*this.pos;
				var new_x = this.startSizes.width - this.one_step_x*this.pos;
				is_finish = new_y<=options.target_size || new_x<=options.target_size;
			}
			else // slide-down
			{
				var new_y = this.startSizes.height + this.one_step_y*this.pos;
				var new_x = this.startSizes.width + this.one_step_x*this.pos;
				is_finish = new_y>=options.target_size;
			}
			(is_finish) && (new_x = new_y = options.target_size);
			(options.scaleY) && (node.setStyle('height', parseInt(new_y) +'px'));
			(options.scaleX) && (node.setStyle('width', parseInt(new_x) +'px'));
			
			this.pos++;

			(options['onchange']) && (options['onchange'](this.pos));

			//execute events
			if (!is_finish)
			{
				if (!is_finish)
				{
					timeout_id = window.setTimeout(function(){Me.Exec();}, options.duration * 1000);
				}
			}
			if (options['onfinish'] && is_finish)
			{
				sliding_nodes[node] = false;
				options['onfinish']();
			}
		}
		
		//
		//
		//

		this.Abort = function()
		{
			(timeout_id) && (window.clearTimeout(timeout_id));
			is_finish = true;
			sliding_nodes[node] = false;
		}

		//
		//
		//

		try
		{
			if (!sliding_nodes[node])
			{
				sliding_nodes[node] = node;
				this.Abort();
				this.Init();
				this.Exec();
			}
		}
		catch(e){}
	}

	//
	//
	//

	var sliding_nodes=[];
	
	
	//
	//
	//
	var timeout_id_fading = false;
	this.Fading = function(node, alignment, options)
	{
		var is_finish = false,
			Me = this;
		
		//
		//
		//
		
		this.Init = function()
		{
			// set automatic the missing options
			(!options.steps) && (options.steps=15);
			(!options.duration) && (options.duration=3);
			if(typeof options.target_opacity == 'undefined')
			{
				options.target_opacity = (alignment) ? 0 : 100;
			}

			// init events
			for (var event in {'begin':1,'finish':1,'change':1})
			{
				(options['on'+event]) && (options['on'+event] = COM.GET.Function(options['on'+event]));
			}
			
			//execute onbegin-event
			(options['onbegin']) && (options['onbegin']());
		}

		//
		//
		//

		this.Exec = function()
		{
			if (alignment==true)
			{
				var opacity = node.getStyle('opacity')-10;
				if (opacity >= options.target_opacity && opacity>=0)
				{
					node.setStyle('opacity', opacity);
				}
				else
				{
					is_finish = true;
				}
			}
			else
			{
				var opacity = node.getStyle('opacity')+10;
				if (opacity <= options.target_opacity && opacity<=100)
				{
					node.setStyle('opacity', opacity);
				}
				else
				{
					is_finish = true;
				}
			}

			//execute events
			if (!is_finish)
			{
				(options['onchange']) && (options['onchange']());
				if (!is_finish)
				{
					timeout_id_fading = window.setTimeout(function(){Me.Exec();}, options.duration*10);
				}
			}
			if (options['onfinish'] && is_finish)
			{
				options['onfinish']();
			}
		}
		
		//
		//
		//

		this.Abort = function()
		{
			(timeout_id_fading) && (window.clearTimeout(timeout_id_fading));
			is_finish = true;
		}
		
		//
		//
		//

		try
		{
			this.Init();
			this.Exec();
		}
		catch(e){}
	}
};
APP.LABELS = new function() 
{
	//
	//
	//
	
	this.fix = function(doc)
	{
		if (
				navigator.userAgent.match(/iPhone/i) || 
		  		navigator.userAgent.match(/iPod/i) || 
		  		navigator.userAgent.match(/iPad/i)
		  	)
		{
			var labels = doc.getElementsByTagName('label');
	
			for (var i=0; labels[i]; i++)
			{
				if (labels[i].getAttribute('for'))
				{
					labels[i].onclick = APP.LABELS.labelClick;
				}
			}
		}
	}

	//
	//
	//

	this.labelClick = function()
	{
		var el = document.getElementById(this.getAttribute('for'));
		if (['radio', 'checkbox'].indexOf(el.getAttribute('type')) != -1)
		{
			el.setAttribute('selected', !el.getAttribute('selected'));
		}
		else
		{
			el.focus();
		}
	}
};
//
// Main Sidebar Templates
//
// @author crankers
// @since 14.10.2011
//
var tpl = '';

tpl  = '<div id="all_trv_sidebar" style="display:none;">';
tpl += '	<span id="js_trv_sidebar" class="open_close subheadline"></span>';
tpl += '	<div id="js_sidebar_content" class="js_trv_sidebar_collapse content"></div>';
tpl += '</div>';

APP.TPL.Register('app.sidebar.main', tpl);

tpl  = '<img class="beta" src="http://il2.trivago.com/images/layoutimages/new_design_3/beta_graphik.png"/>';
APP.TPL.Register('app.sidebar.beta', tpl);

//
// Bookmark List Templates
//
// @author crankers
// @since 14.10.2011
//
tpl  = '<h3 id="js_sidebar_bookmark"></h3>';
APP.TPL.Register('app.sidebar.bookmark.headline', tpl);

tpl  = '<div class="js_sidebar_bookmark_collapse placeholder">';
tpl += '	<div>';
tpl += '		No has guardado ningÃºn hotel.';
tpl += '	</div>';
tpl += '</div>';
APP.TPL.Register('app.sidebar.bookmark.placeholder', tpl);

tpl  = '<div class="js_sidebar_bookmark_collapse placeholder">';
tpl += '	<div>';
tpl += '		No has guardado ningÃºn hotel.<h4>CÃ³mo guardar y comparar hoteles:</h4><h5><span>1.</span>Haz clic en el botÃ³n de \'+\' que estÃ¡ antes del nombre de cada hotel.</h5><img src=\"http://il1.trivago.com/images/layoutimages/new_design_3/add_to-_liste_graphik.png\"/>';
tpl += '	</div>';
tpl += '</div>';
APP.TPL.Register('app.sidebar.bookmark.placeholder_list', tpl);

tpl  = '<div class="js_sidebar_bookmark_collapse placeholder">';
tpl += '	<div>';
tpl += '		No has guardado ningÃºn hotel.<h4>CÃ³mo guardar y comparar hoteles:</h4>Haz clic en el botÃ³n \'+\' situado debajo del icono de opiniones del hotel.<img src=\"http://il1.trivago.com/images/layoutimages/new_design_3/add_to-_liste_item_mx.png\"/>';
tpl += '	</div>';
tpl += '</div>';
APP.TPL.Register('app.sidebar.bookmark.placeholder_item', tpl);

tpl  = '<div class="js_sidebar_bookmark_collapse">#content#</div>';
tpl += '<div id="js_sidebar_bookmark_more" class="more_less js_sidebar_bookmark_collapse"></div>';
APP.TPL.Register('app.sidebar.bookmark.collapse', tpl);

tpl  = '<a href="#link#" class="bookmark gradient_very_bright #class#">';
tpl += '	<div class="icon" onclick="APP.SIDEBAR.DelBookmark(\'#id#\'); return false;" title="Borrar hotel de \'Hoteles favoritos\'"></div>';
tpl += '	<div class="image sprite_icon"><img src="#img#"/></div>';
tpl += '	<div class="details">';
tpl += '		<div class="item_name" title="#title#">#title#</div>';
tpl += '		<div class="item_group">#category#</div>';
tpl += '		#rating#/100';
tpl += '	</div>';
tpl += '	<div class="price">';
tpl += '		<span class="max_price">#max_price#</span><br/>';
tpl += '		<span class="min_price">#min_price#</span>';
tpl += '	</div>';
tpl += '</a>';
APP.TPL.Register('app.sidebar.bookmark.entry', tpl);

tpl  = '<em onclick="#link#" id="js_sidebar_bookmark_compare" class="js_sidebar_bookmark_collapse button_big gradient_bright_hover" target="_blank">';
tpl += '	<span>Comparar hoteles</span>';
//tpl += '	Comparar los primeros 5 hoteles';
tpl += '</em>';
APP.TPL.Register('app.sidebar.bookmark.compare', tpl);

//
// History List Templates
//
// @author crankers
// @since 14.10.2011
//
tpl  = '<h3 id="js_sidebar_history"></h3>';
APP.TPL.Register('app.sidebar.history.headline', tpl);

tpl  = '<div class="js_sidebar_history_collapse">#content#</div>';
tpl += '<div id="js_sidebar_history_more" class="more_less js_sidebar_history_collapse"></div>';
APP.TPL.Register('app.sidebar.history.collapse', tpl);

tpl  = '<a href="#link#" class="history history_search gradient_very_bright #class#" target="_blank">';
tpl += '	<div class="image sprite_icon"><img src="http://il1.trivago.com/images/layoutimages/new_design_3/default_placehoder_search.jpg"/></div>';
tpl += '	<div class="details">';
tpl += '		<div class="item_name">';
tpl += '			#path#';
tpl += '		</div>';
tpl += '		#from# - #to#, #room#';
tpl += '	</div>';
tpl += '	<div class="price">#price#</div>';
tpl += '</a>';
APP.TPL.Register('app.sidebar.history.search', tpl);

tpl  = '<a href="#link#" class="history gradient_very_bright #class#" target="_blank">';
tpl += '	<div class="icon #icon_class#" onclick="#icon_onclick# return false;" title="#icon_title#"></div>';
tpl += '	<div class="image sprite_icon"><img src="#img#"/></div>';
tpl += '	<div class="details">';
tpl += '		<div class="item_name" title="#title#">#title#</div>';
tpl += '		<div class="item_group">#category#</div>';
tpl += '		#rating#/100';
tpl += '	</div>';
tpl += '	<div class="price">';
tpl += '		<span class="max_price">#max_price#</span><br/>';
tpl += '		<span class="min_price">#min_price#</span>';
tpl += '	</div>';
tpl += '</a>';
APP.TPL.Register('app.sidebar.history.item', tpl);

//
// Deals List Templates
//
// @author crankers
// @since 14.10.2011
//
tpl  = '<h3 id="js_sidebar_deals"></h3>';
APP.TPL.Register('app.sidebar.deals.headline', tpl);

tpl  = '<div class="js_sidebar_deals_collapse">#content#</div>';
tpl += '<div id="js_sidebar_deals_more" class="more_less js_sidebar_deals_collapse"></div>';
APP.TPL.Register('app.sidebar.deals.collapse', tpl);

tpl  = '<a href="#link#" class="item gradient_very_bright #class#" title="#info#" target="_blank">';
tpl += '	<div class="icon #icon_class#" onclick="#icon_onclick# return false;" title="#icon_title#"></div>';
tpl += '	<div class="image sprite_icon"><img src="#img#"/></div>';
tpl += '	<div class="details">';
tpl += '		<div class="item_name" title="#title#">#title#</div>';
tpl += '		<div class="item_group">#category#</div>';
tpl += '		<div class="date_from">#date_from#</div>';
tpl += '		#rating#/100';
tpl += '	</div>';
tpl += '	<div class="price">';
tpl += '		<span class="max_price">#max_price#</span><br/>';
tpl += '		<span class="min_price">#min_price#</span>';
tpl += '	</div>';
tpl += '</a>';
APP.TPL.Register('app.sidebar.deals.entry', tpl);

//
// Bookmark Buttons Templates
//
// @author crankers
// @since 14.10.2011
//
tpl  = '<em onclick="APP.SIDEBAR.AddBookmark(\'#id#\');" title="Guardar hotel"><span class="bookmark_add"></span><span class="bookmark_text">Guardar hotel</span></em>';
APP.TPL.Register('app.sidebar.bookmark.button.add', tpl);

tpl  = '<div><span class="bookmark_wait"></span><span class="bookmark_text">El hotel estÃ¡ siendo guardado</span></div>';
APP.TPL.Register('app.sidebar.bookmark.button.wait', tpl);

tpl  = '<em onclick="APP.SIDEBAR.DelBookmark(\'#id#\');" title="Hotel guardado"><span class="bookmark_del"></span><span class="bookmark_text">Hotel guardado</span></em>';
APP.TPL.Register('app.sidebar.bookmark.button.delete', tpl);
//
// Equiv to COM.SIDEBAR, Handles a sidebar and idebar content on the right.
//
// @author crankers
// @since 06.09.2011
//
APP.SIDEBAR = new function()
{

	//
	// private vars
	//
	//  S - settings object given by init
	//  B - internal bookmark list
	//  W - current waiting bookmark requests
	//  R - possible stored response for sidebar
	//  N - main content node
	//  I - array of items to add bookmark to
	//
	var S = { 'collapse':{}, 'limit':{} },
		B = null,
		W = [],
	    R,
	    N = null,
	    I = [];

	//
	// Init sidebar, add initial HTML.
	// Use of function is public.
	//
	// @author crankers
	// @since 14.10.2011
	//
	// @param (string) c, content to insert into sidebar
	//
	// @return (void)
	//
	this.Init = function(s)
	{
		S['main'] = s['m'];
		S['page'] = s['p'];
		S['bookmark'] = s['b'];
		S['limit']['bookmark'] = s['lb'];
		S['limit']['history'] = s['lh'];
		S['limit']['deals'] = s['ld'];
		S['collapse']['url'] = s['c'];
		S['collapse']['main'] = s['cm'];
		S['collapse']['placeholder'] = s['cp'];
		S['collapse']['bookmark'] = s['cb'];
		S['collapse']['bookmark_ext'] = s['cbe'];
		S['collapse']['history'] = s['ch'];
		S['collapse']['history_ext'] = s['che'];
		S['collapse']['deals'] = s['cd'];
		S['collapse']['deals_ext'] = s['cde'];
		
		COM.HTTP.Get(	S['main'], {'json':true,
									'onfinish':function(r){
										if (r)
										{
											APP.SIDEBAR.Open(r);
										}
										else
										{
											APP.SIDEBAR.Close();
										}
									}});
	}

	//
	// Open minimized sidebar element with COM.SIDEBAR.Open.
	// Use of function is public.
	//
	// @author crankers
	// @since 14.10.2011
	//
	// @param (string) o, object to render
	//
	// @return (void)
	//
	this.Open = function(r)
	{
		if (N === null)
		{
			var n = COM.Element(['div',{}]);
			n.innerHTML = APP.TPL.Apply('app.sidebar.main');
			COM.SIDEBAR.Open(n.firstChild, false, $('document_main'));
			
			if(COM.GET.Body().hasClass('COMSidebarActive'))
			{
				var node_sidebar_content = $('js_sidebar_content');
				if (node_sidebar_content.isElement())
				{
					N = node_sidebar_content;
				
					APP.COLLAPSE.Add('js_trv_sidebar',{
						'open':S['collapse']['main']['open'],
						'close':S['collapse']['main']['close'],
						'state':( S['collapse']['main']['state'] == 'o'?'open':'close' ),
						'elem':S['collapse']['main']['elem'],
						'onopen':function(){ APP.SIDEBAR.Maximize();COM.HTTP.Get(S['collapse']['url']+'&id=s&s=o', {}); },
						'onclose':function(){ APP.SIDEBAR.Minimize();COM.HTTP.Get(S['collapse']['url']+'&id=s&s=c', {}); }
					});
				}			
			}
			
			window.addEvent('resize', function(){APP.SIDEBAR.Size();});
		}
		
		if (COM.GET.Body().hasClass('COMSidebarActive'))
		{
			(S['collapse']['main']['state'] == 'o') && APP.SIDEBAR.Maximize();
			this.Render(r);
			$('all_trv_sidebar').appear();
			
			R = null;
			
			COM.SCROLL.SetDimensions();
		}
		else
		{
			R = r;
		}
	};

	//
	// Close sidebar and removes elements from DOM.
	// Use of function is public.
	//
	// @author crankers
	// @since 06.09.2011
	//
	// @return (void)
	//
	this.Close = function()
	{
		COM.SIDEBAR.Close();
	};

	//
	// Maximize sidebar with COM.SIDEBAR.Maximize.
	// Use of function is public.
	//
	// @author crankers
	// @since 07.09.2011
	//
	// @return (void)
	//
	this.Maximize = function()
	{
		COM.SIDEBAR.Maximize();
		COM.SCROLL.Enable();
	};

	//
	// Minimize sidebar with COM.SIDEBAR.Minimize.
	// Use of function is public.
	//
	// @author crankers
	// @since 07.09.2011
	//
	// @return (void)
	//
	this.Minimize = function()
	{
		COM.SCROLL.Disable();
		COM.SIDEBAR.Minimize();
	};

	//
	// When size of sidebar is open now, add sidebar content when stored into class.
	// Use of function is public.
	//
	// @author crankers
	// @since 08.09.2011
	//
	// @return (void)
	//
	this.Size = function()
	{
		if(COM.SIDEBAR.Size() == false)
		{
			return false;
		}
		
		if (COM.GET.Body().hasClass('COMSidebarActive'))
		{
			if(R)
			{
				this.Open(R);
			}
			else
			{
				COM.SCROLL.SetDimensions();
			}
		}
	};

	//
	// Render Sidebar content into DOM.
	// Use of function is private.
	//
	// @author crankers
	// @since 14.10.2011
	//
	// @return (void)
	//
	this.Render = function(r)
	{
		var tpl = [], c = { 'b':'bookmark', 'h':'history', 'd':'deals' };
		
		if (r['s'])
		{
			S['collapse']['placeholder'] = r['s']['p'];
			S['collapse']['bookmark']['state'] = r['s']['b'];
			S['collapse']['bookmark_ext']['state'] = r['s']['be'];
			S['collapse']['history']['state'] = r['s']['h'];
			S['collapse']['history_ext']['state'] = r['s']['he'];
			S['collapse']['deals']['state'] = r['s']['d'];
			S['collapse']['deals_ext']['state'] = r['s']['de'];
		}

		tpl.push( ['app.sidebar.beta', {}] );
		tpl = this.GenerateBookmarks(r['b'], tpl);
		tpl = this.GenerateHistory(r['h'], tpl);
		tpl = this.GenerateDeals(r['d'], tpl);
		APP.TPL.Insert(N, tpl);

		this.AddCollapse(r['b'].length, 'b', 'bookmark');
		this.AddCollapse(r['h'].length, 'h', 'history');
		this.AddCollapse(r['d'].length, 'd', 'deals');
	};

	//
	// Generate Bookmarks templates to insert.
	// Use of function is private.
	//
	// @author crankers
	// @since 14.10.2011
	//
	// @return (void)
	//
	this.GenerateBookmarks = function(r, tpl)
	{
		W = [];B = [];
	
		if (typeof r != 'undefined')
		{
			tpl.push( ['app.sidebar.bookmark.headline', {}] );
		
			if (r.length)
			{
				var stpl = '';
				for(var i=0,n=r.length;i!=n;++i)
				{
					B.push(r[i]['id']);
					
					var o = {
								'id':r[i]['id'],
								'link':r[i]['link'],
								'img':r[i]['img'],
								'category':r[i]['category'],
								'rating':r[i]['rating'],
								'title':r[i]['name'],
								'max_price':r[i]['max_price'],
								'min_price':r[i]['min_price']
							};
				
					if (i > S['limit']['bookmark'])
					{
						o['class'] = 'js_sidebar_bookmark_more_collapse';
						stpl += APP.TPL.Apply('app.sidebar.bookmark.entry', o);
					}
					else
					{
						o['class'] = 'js_sidebar_bookmark_collapse';
						tpl.push(['app.sidebar.bookmark.entry', o]);
					}
				}
				
				if (stpl)
				{
					tpl.push(['app.sidebar.bookmark.collapse', { 'content':stpl }]);
				}
				
				if(r.length > 1)
				{
					tpl.push(['app.sidebar.bookmark.compare', {'link':"APP.CLICKOUT.Open('/user.php?pagetype=item_comparison&popup=1', 0);"}] );
				}
			}
			else
			{
				if(S['collapse']['placeholder'] == 'o')
				{
					if(S['page'] == 'item')
					{
						tpl.push( ['app.sidebar.bookmark.placeholder_item', {}] );
					}
					else
					{
						tpl.push( ['app.sidebar.bookmark.placeholder_list', {}] );
					}				
				}
				else
				{
					tpl.push( ['app.sidebar.bookmark.placeholder', {}] );
				}
			}
		}
		
		return tpl;	
	};

	//
	// Generate History templates to insert.
	// Use of function is private.
	//
	// @author crankers
	// @since 14.10.2011
	//
	// @return (void)
	//
	this.GenerateHistory = function(r, tpl)
	{
		if (	typeof r != 'undefined' &&
				r.length	)
		{
			tpl.push( ['app.sidebar.history.headline', {}] );

			var stpl = '';
			for(var i=0,n=r.length;i!=n;++i)
			{
				switch(r[i]['type'])
				{
					case 'search':
						var t = 'app.sidebar.history.search';
						var o = {
									'link':r[i]['link'],
									'path':r[i]['path'],
									'from':r[i]['from'],
									'to':r[i]['to'],
									'room':r[i]['room']
								};
						break;

					case 'item':
					default:
						var t = 'app.sidebar.history.item';
						var o = {
									'id':r[i]['id'],
									'icon_class':r[i]['icon_class'],
									'icon_onclick':r[i]['icon_onclick'],
									'icon_title':r[i]['icon_title'],
									'link':r[i]['link'],
									'img':r[i]['img'],
									'rating':r[i]['rating'],
									'category':r[i]['category'],
									'title':r[i]['name'],
									'max_price':r[i]['max_price'],
									'min_price':r[i]['min_price']
								};
						break;
				}
			
				if (i > S['limit']['history'])
				{
					o['class'] = 'js_sidebar_history_more_collapse';
					stpl += APP.TPL.Apply(t, o);
				}
				else
				{
					o['class'] = 'js_sidebar_history_collapse';
					tpl.push([t, o]);
				}
			}
			
			if (stpl)
			{
				tpl.push(['app.sidebar.history.collapse', { 'content':stpl }]);
			}
		}
		
		return tpl;	
	};

	//
	// Generate Deals templates to insert.
	// Use of function is private.
	//
	// @author crankers
	// @since 14.10.2011
	//
	// @return (void)
	//
	this.GenerateDeals = function(r, tpl)
	{
		if (	typeof r != 'undefined' &&
				r.length	)
		{
			tpl.push( ['app.sidebar.deals.headline', {}] );

			var stpl = '';
			for(var i=0,n=r.length;i!=n;++i)
			{
				var o = {
							'id':r[i]['id'],
							'icon_class':r[i]['icon_class'],
							'icon_onclick':r[i]['icon_onclick'],
							'icon_title':r[i]['icon_title'],
							'link':r[i]['link'],
							'info':r[i]['info'],
							'img':r[i]['img'],
							'title':r[i]['title'],
							'date_from':r[i]['date_from'],
							'max_price':r[i]['max_price'],
							'min_price':r[i]['min_price'],
							'rating':r[i]['rating'],
							'category':r[i]['category']
						};
			
				if (i > S['limit']['deals'])
				{
					o['class'] = 'js_sidebar_deals_more_collapse';
					stpl += APP.TPL.Apply('app.sidebar.deals.entry', o);
				}
				else
				{
					o['class'] = 'js_sidebar_deals_collapse';
					tpl.push(['app.sidebar.deals.entry', o]);
				}
			}
			
			if (stpl)
			{
				tpl.push(['app.sidebar.deals.collapse', { 'content':stpl }]);
			}
		}
		
		return tpl;	
	};

	//
	// Add Collapser for (t)ype and (n)amed elements.
	// Use of function is private.
	//
	// @author crankers
	// @since 14.10.2011
	//
	// @return (void)
	//
	this.AddCollapse = function(c, t, n)
	{
		if (	typeof S['collapse'][n] != 'undefined' &&
				c	)
		{
			APP.COLLAPSE.Add('js_sidebar_'+n,{
				'open':S['collapse'][n]['open'],
				'close':S['collapse'][n]['close'],
				'state':( S['collapse'][n]['state'] == 'o'?'open':'close' ),
				'elem':S['collapse'][n]['elem'],
				'onopen':function(){ COM.HTTP.Get(S['collapse']['url']+'&id='+t+'&s=o', {});COM.SCROLL.SetDimensions(); },
				'onclose':function(){ COM.HTTP.Get(S['collapse']['url']+'&id='+t+'&s=c', {});COM.SCROLL.SetDimensions(); }
			});
			
			if (	typeof S['collapse'][n+'_ext'] != 'undefined' &&
					c > S['limit'][n]	)
			{
				APP.COLLAPSE.Add('js_sidebar_'+n+'_more',{
					'open':S['collapse'][n+'_ext']['open'],
					'close':S['collapse'][n+'_ext']['close'],
					'state':( S['collapse'][n+'_ext']['state'] == 'o'?'open':'close' ),
					'elem':S['collapse'][n+'_ext']['elem'],
					'onopen':function(){ COM.HTTP.Get(S['collapse']['url']+'&id='+t+'e&s=o', {});COM.SCROLL.SetDimensions(); },
					'onclose':function(){ COM.HTTP.Get(S['collapse']['url']+'&id='+t+'e&s=c', {});COM.SCROLL.SetDimensions(); }
				});
			}
		}
	};

	//
	// Delete Collapser for given (t)ype.
	// Use of function is private.
	//
	// @author crankers
	// @since 14.10.2011
	//
	// @return (void)
	//
	this.DelCollapse = function(t)
	{
		APP.COLLAPSE.Del('js_sidebar_'+t);
		APP.COLLAPSE.Del('js_sidebar_'+t+'_more');
	};

	//
	// Prooves if given id is stored in bookmark list and render button to
	// element id pattern 'js_personal_bookmark_<e>'.
	// Use of function is public.
	//
	// @author crankers
	// @since 14.10.2011
	//
	// @return (boolean|null)
	//
	this.ShowBookmark = function(e)
	{
		var node_personal_bookmark = $('js_personal_bookmark_'+e);
		// we have no element or no bookmarks loaded
		if (	!node_personal_bookmark.isElement() ||
				B === null	)
		{
			return null;
		}

		// request is running
		if (W.hasValue(e))
		{
			APP.TPL.Insert(node_personal_bookmark, [['app.sidebar.bookmark.button.wait', { 'id':e }]]);
			return true;
		}

		// bookmark is set
		if (B.hasValue(e))
		{
			APP.TPL.Insert(node_personal_bookmark, [['app.sidebar.bookmark.button.delete', { 'id':e }]]);
			return true;
		}
		
		// no bookmark for item
		APP.TPL.Insert(node_personal_bookmark, [['app.sidebar.bookmark.button.add', { 'id':e }]]);
		return false;
	};

	//
	// Adds a bookmark to bookmark list for given (e)lement.
	// Use of function is public.
	//
	// @author crankers
	// @since 14.10.2011
	//
	// @return (boolean)
	//
	this.AddBookmark = function(e)
	{
		if (B.hasValue(e) === false)
		{
			return this.RequestBookmark(e, 'add');
		}

		return false;
	};

	//
	// Deletes a bookmark from bookmark list for given (e)lement.
	// Use of function is public.
	//
	// @author crankers
	// @since 14.10.2011
	//
	// @return (boolean)
	//
	this.DelBookmark = function(e)
	{
		if (B.hasValue(e) === true)
		{
			return this.RequestBookmark(e, 'delete');
		}

		return false;
	};

	//
	// Request a bookmark from bookmark list for given (e)lement.
	// Use of function is private.
	//
	// @author crankers
	// @since 14.10.2011
	//
	// @return (boolean)
	//
	this.RequestBookmark = function(e, t)
	{
		W.push(e);
		this.ShowBookmark(e);

		COM.HTTP.Get(S['bookmark']+'&s='+t+'&item='+e, {	'json':true,
															'onfinish':function(r){
																APP.SIDEBAR.DelCollapse('bookmark');
																APP.SIDEBAR.DelCollapse('history');
																APP.SIDEBAR.DelCollapse('deals');

																$('js_sidebar_content').innerHTML = '';
																
																APP.SIDEBAR.Render(r);
																COM.SCROLL.SetDimensions();
																APP.SIDEBAR.ShowBookmark(e);
															}
		});

		return true;
	};
	
	
	//
	// Display bookmark button
	// Use of function is public.
	//
	// @author tschulte
	// @since 25.01.2012
	//
	this.DisplayBookmark = function(e)
	{
		// bookmark is not set
		if (	B === null	||
				B.hasValue(e) === false	)
		{
			return APP.TPL.Apply('app.sidebar.bookmark.button.delete', { 'id':e });
		}
		else
		{
			return APP.TPL.Apply('app.sidebar.bookmark.button.add', { 'id':e });
		}
	};		
};APP.HOME_ROTATION = new function()
{
	var data = [],
		used_index = 0,
		timeout_id_start,
		timeout_id_fade,
		for_example = '',
		status_enabled = true,
		http_obj,
		arrow_list = [],
		bNoCtest = false;

	//
	//
	//

	this.Init = function(node_id, path_list, init_index, example_string)
	{
		data = path_list;
		for_example = example_string;
		used_index = init_index;
	}

	//
	//
	//

	this.initNoCtest = function(node_id)
	{
		bNoCtest = true;
		var nodes = $(node_id).getElementsByTagName('div'),
			id;
		for(var i=0, n=nodes.length; i<n; i++)
		{
			id = $(nodes[i]).getAttribute('id');
			if (id && id.split('js_all_toplistfeature_arrow_').length==2)
			{
				arrow_list.push($(nodes[i]));
			}
		}
	}

	//
	//
	//

	this.IsEnabled = function()
	{
		return status_enabled;
	}

	//
	//
	//


	//
	//
	//

	this.Start = function()
	{
		if(status_enabled)
		{
			if(!data[++used_index])
			{
				used_index = 0;
			}
			this.LoadPath(data[used_index].id, {'delay':10000, 'onfinish':function(){if(APP.HOME_ROTATION.IsEnabled()){APP.HOME_ROTATION.Start();}}});
		}
	}

	//
	//
	//

	this.LoadPath = function(path, params)
	{
		(http_obj) && http_obj.abort();
		http_obj = new COM.HTTP.Request('GET', '/trivago_rpc.php?action=home_top_items&path=' + path, {
										'onfinish':function(html) {
											if (html)
											{
												APP.HOME_ROTATION.Response(path, html, params);
											}
										}});

		timeout_id_start = window.setTimeout(function(){APP.HOME_ROTATION.StartRpcCall();}, params['delay']);
	}

	//
	//
	//

	this.StartRpcCall = function()
	{
		http_obj.start();
	}

	//
	//
	//

	this.Response = function(path, html, params)
	{
		if($('destinationstring').value == '')
		{
			$('destinationstring_shadow').value = for_example + ' ' + data[used_index].name;
		}
		$('destination_path').value = path;
		params['onfinish'] && params['onfinish']();
		$('hotellistitems').innerHTML = html;
		if(bNoCtest)
		{
			for (var i=0, n=arrow_list.length; i<n; i++)
			{
				arrow_list[i].disappear();
			}
			$('js_all_toplistfeature_arrow_'+path).appear();
		}
	}

	//
	//
	//

	this.FadeOut = function(node, opacity, param)
	{
		if (opacity>0)
		{
			if (!Browser.IE6 && !Browser.IE7)
			{
				$('destinationstring').setOpacity((opacity -= 10));
				node.setOpacity(opacity);
			}
			timeout_id_fade = window.setTimeout(function()	{
																APP.HOME_ROTATION.FadeOut(node, opacity, param);
															}, 50);
		}
		else
		{

			(param.onfinish) && param.onfinish();
			this.FadeIn($('hotellistitems'), 0);
		}
	}


	//
	//
	//

	this.FadeIn = function(node, opacity)
	{
		if (opacity<100)
		{
			if (!Browser.IE6 && !Browser.IE7)
			{
				$('destinationstring').setOpacity((opacity += 10));
				node.setOpacity(opacity);
			}

			timeout_id_fade = window.setTimeout(function()	{
																APP.HOME_ROTATION.FadeIn(node, opacity);
															}, 50);
		}
	}

	//
	//
	//

	this.Stop = function()
	{
		status_enabled = false;
		(timeout_id_start) && window.clearTimeout(timeout_id_start);
		(timeout_id_fade)  && window.clearTimeout(timeout_id_fade);
		(http_obj) && http_obj.abort();

		if (!Browser.IE6 && !Browser.IE7 && $('hotellistitems').isElement())
		{
			$('destinationstring').setOpacity(100);
			$('hotellistitems').setOpacity(100);
		}
	}

	//
	//
	//

	this.Break = function()
	{
		(timeout_id_start) && window.clearTimeout(timeout_id_start);
		(timeout_id_fade)  && window.clearTimeout(timeout_id_fade);
		(http_obj) && http_obj.abort();

		if (!Browser.IE6 && !Browser.IE7 && $('hotellistitems').isElement())
		{
			$('destinationstring').setOpacity(100);
			$('hotellistitems').setOpacity(100);
		}
	}
};
/**
 * $Id: $
 *
 * This is a class that provides the top-deals handling 
 *
 * @class TOP_DEALS
 * @author cschmidt
 * @since 10.10.2011
 */
APP.TOP_DEALS = new function()
{
	var node_forward_deal,
		node_button_backward,
		node_button_forward,
		ignore_item,
		path_id, 
		
		is_init = false,
		opacity = 0,
		active_item = 1;
		count_of_items = 1,
		
		intervall_id = false,
		
		is_sliding = false,
		is_loaded = false;
	
	//
	//
	//
	
	this.Init = function(count, pignore_item, ppath_id)
	{
		if (!node_forward_deal)
		{
			node_forward_deal = $('js_home_top_deal');
			node_button_backward = $('js_last_item');
			node_button_forward = $('js_next_item');
			ignore_item = pignore_item;
			is_init = true;
			count_of_items = count;
			path_id = ppath_id;
			
			window.setTimeout(function(){
											COM.HTTP.Get('/trivago_rpc.php?action=top_deals&item=' + ignore_item + '&path=' + path_id, {
														'json':true,
														 'onfinish':function(items){
															if (items && items.length>0)
															{
																APP.TOP_DEALS.load(items);
																window.setTimeout(function(){
																								APP.TOP_DEALS.StartAutoFading();
																							}, 2500);
															}
															else
															{	
																$('js_next_item').disappear();
																$('js_last_item').disappear();
															}
														 }});
						 				}, 2500);
		}
	}
	
	//
	//
	//
	
	this.StartAutoFading = function()
	{
		intervall_id = window.setInterval(function(){APP.TOP_DEALS.SliderForward(true);}, 5000);
	}
	
	//
	//
	//
	
	this.load = function(items)
	{
		var retval = '';
		
		for (var i=0, n=items.length; i<n; i++)
		{
			retval += '<div id="js_top_deal'+(i+2)+'" class="round_borders single_home_top_deal" style="background-image:url('+items[i].image+');">'
					+ '	<em class="teaser" onclick="window.location.href=\''+items[i].link+'\';">'
					+ '		<span class="city">'+items[i].city+'</span><br />'
					+ '		<span class="type">'+items[i].type+'</span><br />'
					+ '		<span class="hotel">'+items[i].name+'</span>'
					+ '	</em>'
					+ '	<div class="price_max" onclick="APP.PRICE.REGION.DESIGN.HClickoutLink(\''+items[i].link_max+'\',0,0,'+items[i].partner_id_min+');">'+items[i].partner_max+'<span>'+items[i].price_max+'</span></div>'
					+ '	<div class="price_min" onclick="APP.PRICE.REGION.DESIGN.HClickoutLink(\''+items[i].link_min+'\',0,0,'+items[i].partner_id_max+');">'+items[i].partner_min+'<span>'+items[i].price_min+'</span></div>'
					+ '</div>';
		}
		node_forward_deal.innerHTML += retval;
		
		is_loaded = true;
		is_sliding = false;
	}
	
	//
	//
	//

	this.SliderForward = function(auto_fade, intern_loop)
	{
		auto_fade = typeof auto_fade == 'undefined' ? false : auto_fade;
		// is init
		if (!is_init)
		{
			window.setTimeout(function(){APP.TOP_DEALS.SliderForward(auto_fade, intern_loop);}, 500);
			return;
		}
		// block double sliding
		else if (is_sliding && typeof intern_loop=='undefined')
		{
			return;
		}
		// clear-interval
		else if (!auto_fade && typeof intern_loop=='undefined')
		{
			(intervall_id) && window.clearInterval(intervall_id);
		}		
		
		is_sliding = true;

		if (!is_loaded)
		{
			window.setTimeout(function(){APP.TOP_DEALS.SliderForward(auto_fade, intern_loop);}, 500);
		}
		else
		{
			node_button_backward.appear();
			
			if (typeof intern_loop=='undefined')
			{
				opacity = 100;
			}

			var next_item_exists = $('js_top_deal'+(active_item+1)).isElement();
			var node_active = $('js_top_deal'+active_item);
			var node_next = $('js_top_deal'+(next_item_exists?active_item+1:1));
			
			node_active.setOpacity((opacity -= 10));
			node_active.style.zIndex = 10;
			node_next.style.zIndex = 9;
			node_next.appear();

			if (opacity>0)
			{
				window.setTimeout(function(){APP.TOP_DEALS.SliderForward(auto_fade, true);}, 50);
			}
			else
			{
				node_active.style.zIndex = 0;
				node_next.style.zIndex = 10;
				node_active.disappear();
				node_active.setOpacity(100);
				active_item = next_item_exists ? active_item+1 : 1; 
				is_sliding = false;
			}
		}
	}
	
	//
	//
	//
	
	this.SliderBackward = function(intern_loop)
	{
		// is init
		if (!is_init)
		{
			window.setTimeout(function(){APP.TOP_DEALS.SliderBackward(intern_loop);}, 500);
			return;
		}
		// block double sliding
		else if (is_sliding && typeof intern_loop=='undefined')
		{
			return;
		}
		// clear-interval
		else if (typeof intern_loop=='undefined')
		{
			(intervall_id) && window.clearInterval(intervall_id);
		}

		is_sliding = true;

		if (!is_loaded)
		{
			window.setTimeout(function(){APP.TOP_DEALS.SliderBackward(intern_loop);}, 500);
		}
		else
		{
			if (typeof intern_loop=='undefined')
			{
				opacity = 100;
			}
	
			var last_item_exists = $('js_top_deal'+(active_item-1)).isElement();
			var node_active = $('js_top_deal'+active_item);
			var node_last = $('js_top_deal'+(last_item_exists?active_item-1:count_of_items));
			node_active.setOpacity((opacity -= 10));
			node_active.style.zIndex = 10;
			node_last.style.zIndex = 9;
			node_last.appear();
	
			if (opacity>0)
			{
				window.setTimeout(function(){APP.TOP_DEALS.SliderBackward(true);}, 50);
			}
			else
			{
				node_active.style.zIndex = 0;
				node_last.style.zIndex = 10;
				node_active.disappear();
				node_active.setOpacity(100);
				active_item = last_item_exists ? active_item-1 : count_of_items; 
				is_sliding = false;
			}
		}
	}
}
//
//  show or hide all critical elements.
//  todo: create more flexible functionallity
//

function DisplayHideLists(StyleType, id){

  if(!id)
    id = document;
  else
    id = $( id );

  setHideLists(id, "select", StyleType);
  if(Browser.IE) {
    setHideLists(id, "embed",  StyleType);
    setHideLists(id, "object", StyleType);
  }
}

function setHideLists(id, tagName, StyleType) {
  var a = id.getElementsByTagName(tagName);
  for(var i=0; i<a.length; i++){
    a[i].style.display = StyleType;
  }
}

function CheckLen(Target,Tlength) {
    Tlength = Tlength || 250;
  var StrLen = Target.value.length;
  if (StrLen == 1 && Target.value.substring(0,1) == " ") {
    Target.value = "";
    StrLen = 0;
  }
  if (StrLen > Tlength) {
    Target.value = Target.value.substring(0,Tlength);
    CharsLeft = 0;
  }
  else CharsLeft = Tlength - StrLen;

  $('counter_'+Target.getAttribute('name')).value = CharsLeft;
}

function radioValue(rObj) {
  for (var i=0; i<rObj.length; i++){
    if (rObj[i].checked){
      return rObj[i].value;
    }
  }
  return false;
}

function showHelpBox(code, r){
  r = (r)? '&r='+r : '';
  COM.HTTP.Get("/trivago_rpc.php?help=true&action=dialog_box&code=" + code+r,{"onfinish":function(r){APP.WIZ.Module(r, "question");}});
}

function CheckLoginForm()
{
  var node_js_login_usrname = $("js_login_usrname");
  var node_js_login_pass    = $("js_login_pass");
  if ((node_js_login_usrname) && (node_js_login_usrname.value != ''))
    node_js_login_usrname.className='text usrname2';

  if((node_js_login_pass) && (node_js_login_pass.value!=''))
    node_js_login_pass.className='text pwd2';

}
function showQuickPollResult(quickpoll_id, selection)
{
    // load the data-string from the server
    COM.HTTP.Get(self.servername + '/trivago_rpc.php?&action=getquickpollresult&quickpoll=' + quickpoll_id + '&selection=' + selection, {"onfinish":function(str){$('quickpoll_form').innerHTML = str;}});
}

window.addEvent("load", "if(self.PageType=='static') manipulateLinks();");

function changeDestination(id)
{
  var objekt = $('destination');
  if(objekt.options[ objekt.selectedIndex ].getAttribute('mylink')) {
    var sub_url = $("searchstring") ? "&q=" + encodeURIComponent($("searchstring").value) : "";
    window.location.href=(objekt.options[ objekt.selectedIndex ].getAttribute('mylink') + sub_url);
  }
}

function displayInputButton(object_id)
{
  var node_object_id = $(object_id).parentNode;
  node_object_id.className += " button_waiting";
}

function displayLinkButton(object_id)
{
  var node_object_id = $(object_id).parentNode;
  node_object_id.className += " button_waiting";
}

function url_replace(url)
{
  window.location.href = url;
  return false;
}

function getElD(i,o)
{
	var node;

	try
	{
		if (i && o && (node = i.getElementsByTagName(o)) && (node[0]) && (node[0].lastChild))
		{
			return node[0].lastChild.data;
		}
	}
	catch (er) { }

	return "";
}

function rand(min, max)
{
  return Math.round( Math.random()*max + min);
}


APP.RUN.Call("trivago.base");
APP.PRICE.REGION = new function()
{
    //
    //  private vars
    //

	var requestIdent         = 0,
		finish_timeout_event = false,
		
		timeout_complete     = 32000,
		execution_time       =     0,

		http_obj,
		service_response,

		//all ajax - states
		ajax_state_error      =  -1,
		ajax_state_incomplete =  0,
		ajax_state_complete   =  1,

		service = { 'run':0, 'status':ajax_state_incomplete, 'resultcount':0  },
		
		
		disable_start,

		max_service_runs = 40; // max repeat-loopings
	
	//
	//
	//

	this.Init = function(request_ident, currency_before_price)
	{
		APP.SNAPSHOT.Request('request_ident', (requestIdent = request_ident));
		APP.PRICE.STRINGS.Init({"max":"max.","details":"Datos","opinions":"Opiniones","map":"Mapa","hotels":"Hoteles","more":"m\u00e1s","less":"reducir","count_image":"Fotos","more_prices":"M\u00e1s precios","deals_forward":"Ver oferta","seo_item_group_in_item":"$item_group $item_name","deals_forward3":"Ver oferta &raquo;","sort_by":"Ordenar por:","sort_by_desc":"descendente","sort_by_asc":"ascendente","sort_relevance":"popularidad","sort_overall_liking":"valoraci\u00f3n","sort_price":"precio","sort_distance_city_center":"distancia al centro de la ciudad","sort_distance_item":"distancia a $name","sort_distance_address":"distancia a $name","certificates":"Ranking","best_price":"Mejor precio","room_details":"Comparar ofertas de habitaci\u00f3n","available_offers":"Disponible en $count webs","disable_filter":"Desactivar filtro","available_offer":"Disponible en $count portal","deals_partner":"Web","partner_no_answer":"No hay ofertas","partner_loading":"cargando","partners_deals_from":"Hoteles desde","deals_proof":"Buscar precios","not_rated_yet":"sin opiniones","all_notices":"Mostrar todos","stars":"Estrellas","save_long":"Ahorro $price","city_center":"Centro de ciudad","all_prices_from_sites_x":"<span>Ver todos los precios<\/span><br\/>de <span>$count<\/span> websites","all_prices_from_site_x":"<span>Ver todos los precios<\/span><br\/>de <span>$count<\/span> web","paging_backward":"<","paging_forward":">","no_geocode_exist":"Localizaci\u00f3n exacta desconocida","no_info_exists":"Descripciones no disponibles","short_room_type_1":"Habitaci\u00f3n Individual","short_room_type_7":"Habitaci\u00f3n doble","night":"noche","searchstring":"T\u00e9rmino de b\u00fasqueda","hotel_booked_out_name":"El hotel ya no est\u00e1 disponible en $name","no_geocode_exists_region":"Localizaci\u00f3n no disponible en la regi\u00f3n","hotelwebsite":"web del hotel","price_filter_search_string":"Buscar t\u00e9rmino $value","price_filter_include_all":"S\u00f3lo hoteles con disponibilidad","price_filter_category":"S\u00f3lo hoteles de $value estrellas","price_filter_distance_limit":"Distancia m\u00e1x $value","price_filter_distance_address_limit":"m\u00e1x. a $value de $location","price_filter_overall_liking":"Valoraci\u00f3n de trivago $value","price_filter_price_max":"Precio m\u00e1x. $value","price_filter_partner1":"Partner: $value","price_filter_partner2":"Partner","distance_unit_single":"km","distance_unit_plural":"km","filter_group_14":"Tipo de hotel","filter_group_8":"Ideal para","filter_group_2":"Instalaciones del hotel","filter_group_6":"Instalaciones deportivas","filter_group_3":"Equipamiento de la habitaci\u00f3n","filter_group_9":"Tipo de alojamiento","filter_group_1":"Cadenas de hoteles","list_title_images0":"no hay fotos disponibles","list_title_images1":"ver fotos de $name","list_title_ratings0":"no hay opiniones disponibles","list_title_ratings1":"ver opiniones sobre $name","list_title_distance0":"localizaci\u00f3n desconocida","list_title_distance1":"ver localizaci\u00f3n de $name","list_title_info0":"no hay descripci\u00f3n disponible","list_title_info1":"ver descripci\u00f3n de $name","list_title_all_rates":"ver todas las ofertas disponibles","hoteltest_rate":"hoteltest_rate","value_label_1_39":"Bastion","value_label_1_43":"Best Western","value_label_1_62":"City Partner Hotels","value_label_1_66":"Comfort","value_label_1_87":"Dorint","value_label_1_101":"Familotel","value_label_1_113":"Four Seasons","value_label_1_116":"Golden Tulip","value_label_1_127":"Hilton","value_label_1_128":"Hipotels","value_label_1_129":"Holiday Inn","value_label_1_135":"Hyatt","value_label_1_136":"Iberostar","value_label_1_137":"Ibis","value_label_1_143":"InterConti","value_label_1_155":"Kempinski","value_label_1_161":"Le Meridien","value_label_1_166":"LTI International","value_label_1_170":"Marriott","value_label_1_172":"Maritim","value_label_1_175":"Melia","value_label_1_176":"Mercure","value_label_1_185":"M\u00f6venpick","value_label_1_189":"NH","value_label_1_190":"Novotel","value_label_1_210":"Quality","value_label_1_212":"Radisson","value_label_1_214":"Ramada","value_label_1_224":"Ritz Carlton","value_label_1_225":"RIU","value_label_1_226":"Robinson Club","value_label_1_240":"Sheraton","value_label_1_246":"Sofitel","value_label_1_247":"Sol Meli\u00e1","value_label_1_254":"Steigenberger","value_label_1_261":"Swiss\u00f4tel","value_label_1_270":"Tryp","value_label_1_275":"Westin","value_label_1_281":"Magic Life","value_label_1_282":"Iberotel","value_label_1_287":"Hapimag","value_label_1_296":"Occidental","value_label_1_323":"Paradores","value_label_1_333":"Delta","value_label_1_348":"Clarion","value_label_1_349":"mD-Hotel","partner_1":"hotel.info","partner_2":"Booking.com","partner_3":"Venere.com","partner_4":"HotelClub","partner_5":"Expedia","partner_6":"giata","partner_7":"skoosh","partner_8":"ebookers","partner_9":"Hotelopia","partner_10":"DHR.com","partner_11":"alpharooms","partner_12":"Hotels.com","partner_13":"InterConti","partner_14":"Accor","partner_15":"HRS","partner_16":"Best Western","partner_17":"Golden Tulip","partner_18":"Choice Hotels","partner_19":"Marriott","partner_20":"One Travel","partner_21":"eDreams","partner_22":"AsiaRooms","partner_23":"iff","partner_24":"HotelPronto","partner_25":"RatesToGo","partner_26":"Hilton","partner_27":"Quality Inn","partner_28":"LateRooms","partner_29":"AffiliateFuture","partner_30":"Reserve A Hotel Online","partner_31":"Quick Rooms","partner_32":"tiscover","partner_33":"octopustravel","partner_34":"HotelsChart","partner_35":"PlaniGo","partner_36":"ehotel","partner_37":"hotel.info","partner_38":"Ab in den Urlaub","partner_40":"opodo","partner_41":"weg.de","partner_42":"Asiativ","partner_43":"travel scout 24","partner_46":"FastBooking","partner_47":"EasyClickTravel","partner_48":"beauty24","partner_49":"escapio","partner_50":"Atrapalo","partner_51":"lastminute","partner_52":"lastminute.de","partner_53":"lastminute.de","partner_54":"priceline.com","partner_55":"hotelbook","partner_56":"opodo","partner_57":"Holidaycheck","partner_58":"tripadvisor","partner_59":"agoda","partner_60":"EasyToBook","partner_61":"hostelsclub","partner_62":"Epoque Hotels","partner_63":"Superbreak","partner_64":"hoteladvisor","partner_65":"onhotels","partner_66":"hotels.nl","partner_67":"Hotusa","partner_68":"Voyages SNCF","partner_69":"barceloviajes","partner_70":"Certified Business Hotels","partner_71":"Splendia","partner_72":"Rural Gest","partner_73":"Crowne Plaza","partner_74":"lastminute.com","partner_75":"Candlewood","partner_76":"Hostelworld","partner_77":"Holiday Inn Express","partner_79":"Indigo","partner_80":"Precio del hotel","partner_81":"Holiday Inn","partner_82":"otel.com","partner_83":"StayBridge","partner_84":"1800-Hotels","partner_85":"Initalia","partner_86":"TUI","partner_87":"infohostal","partner_89":"Budgetplaces","partner_91":"Hotels4u","partner_93":"Hotel-Website","partner_95":"Booking.com","partner_97":"Hotel-Website","partner_99":"Precio del hotel","partner_101":"Tui","partner_103":"Opodo","partner_105":"Logitravel","partner_107":"LTUR","partner_109":"reserveTravel","partner_111":"travelclick","partner_113":"Feratel","partner_115":"FirstAustrianHotels","partner_117":"WORLDHOTELS","partner_119":"Hotelscombined","partner_121":"Agoda.com","partner_123":"BookDirectRooms.com","partner_125":"Booking.com","partner_127":"CarlsonHotels.com","partner_129":"ChoiceHotels.com","partner_131":"EasyClickTravel","partner_133":"ebookers.com","partner_135":"Expedia","partner_137":"FastBooking.com","partner_139":"DHR.com","partner_141":"Hilton.com","partner_143":"Hotel.info","partner_145":"HotelBook.com","partner_147":"HotelClub.com","partner_149":"Hotelopia.com","partner_151":"Hotels.com","partner_153":"hotels4u","partner_155":"HotelsChart.com","partner_157":"hrs.com","partner_159":"InterContinental.com","partner_161":"lastminute.com","partner_163":"LateRooms.com","partner_165":"NeedItNow.com","partner_167":"OctopusTravel.com","partner_169":"Orbitz.com","partner_171":"Otel.com","partner_173":"Priceline.com","partner_175":"RatesToGo.com","partner_177":"ReserveTravel.com","partner_179":"RoamFree.com","partner_181":"Skoosh.com","partner_183":"Travelmate.com.au","partner_187":"Venere.com","partner_189":"EasyToBook.com","partner_191":"Travelocity.com","partner_193":"Synxis","partner_195":"StayPoland","partner_197":"NetHotels","partner_199":"skoosh","partner_201":"Octopus.com","partner_203":"Rumbo","partner_205":"getaroom.com","partner_209":"hotelreservierung.de","partner_213":"Derag Hotels","partner_215":"HotelVault","partner_217":"Clever-Hotels","partner_219":"lowcostholidays","partner_223":"Travelplanet24","partner_227":"Prestigia","partner_229":"Opodo\/Traveltainment","partner_231":"adagio","partner_233":"AllSeasons","partner_235":"CoraliaClub","partner_237":"ETAP","partner_239":"Formule1","partner_241":"HotelsBarriere","partner_243":"ciao","partner_245":"IBIS","partner_247":"Mercure","partner_249":"MGALLERY","partner_251":"Novotel","partner_253":"Orbis","partner_255":"Accor","partner_257":"Pullman","partner_259":"Sofitel","partner_261":"SuiteNovotel","partner_263":"Daydreams","partner_265":"HotelTravel","partner_267":"GetaRoom","partner_271":"Toprural","partner_273":"HotelConnect","partner_275":"Barcel\u00f3 Hoteles","partner_277":"thomascook.de","partner_279":"Olotels.com","partner_281":"M\u00f6venpick","partner_285":"Finest Hotels","partner_287":"Hotelreserv.","partner_291":"1-2-FLY.com","partner_293":"Escapio","partner_295":"blumar","partner_301":"Bookcyprus.com","partner_303":"Vivastay","partner_305":"Opodo","partner_307":"eLong.com","partner_309":"tripsta","partner_311":"Qype","partner_313":"Expedia","partner_315":"Charming Hotels & Resorts","partner_317":"Zoover","partner_319":"Lastminutetrav.","partner_321":"atrapalo","partner_323":"TUI.com","partner_325":"airtours.de","partner_327":"Booking.com","partner_331":"RatesToGo","partner_333":"Ibero Tours","partner_335":"DizzyGoat","partner_337":"Hotele.pl","partner_341":"Destinia","partner_343":"Viajes Iberia","partner_345":"VisitPrague","partner_353":"Olimar","partner_357":"Travelrepublic","partner_359":"Nozio","partner_361":"LHW","partner_365":"Unitravel","partner_367":"Fastbooking","partner_369":"Atel Hotels","partner_371":"WIHP","partner_373":"booked.net","partner_379":"Volayo","partner_381":"Booking.com","partner_383":"Atrapalo","partner_385":"Cityzenbooking","partner_387":"Cityhotels.com","partner_389":"Havas Voyages","partner_391":"HotelClub","partner_398":"NH Hotels","item_group_1":"Hotel","item_group_2":"Hotel","item_group_3":"B & B","item_group_4":"Pensi\u00f3n\/Posada","item_group_5":"Motel","item_group_6":"Aparthotel","item_group_7":"Ciudad de vacaciones","item_group_8":"Casa \/ Apartamento","item_group_9":"Albergue","item_group_10":"Cuartos de hu\u00e9spedes","item_group_11":"Camping","item_group_12":"Mirador","item_group_13":"Bar\/Pub","item_group_14":"Excursi\u00f3n en barca","item_group_15":"Monumento hist\u00f3rico\/Monumento","item_group_16":"Disco\/Club","item_group_17":"Edificio","item_group_18":"Campo de golf","item_group_19":"Casino","item_group_20":"Cine","item_group_21":"Catedral\/Iglesia\/Monasterio","item_group_22":"Pista para correr (footing)","item_group_23":"Museo\/Exposici\u00f3n\/Galer\u00eda de arte","item_group_24":"Paraje natural","item_group_25":"Jard\u00edn bot\u00e1nico","item_group_26":"Calle peatonal\/Calle de compras","item_group_27":"Cicloturismo","item_group_28":"Fiestas\/Eventos","item_group_29":"Restaurante","item_group_30":"Ruta guiada por la ciudad oficial","item_group_31":"Castillo \/ Palacio \/ Murallas","item_group_32":"Tiendas","item_group_33":"Estaci\u00f3n de esqu\u00ed","item_group_34":"Instalaciones deportivas\/Estadio","item_group_35":"Playa","item_group_36":"Submarinismo","item_group_37":"Teatro\/\u00d3pera","item_group_38":"Caminata\/Escalada","item_group_39":"Balneario\/Spa","item_group_40":"Windsurf","item_group_41":"Zool\u00f3gico\/Acuario","item_group_42":"Parque de atracciones","item_group_43":"Otros sitios de inter\u00e9s","item_group_44":"Monumento natural","item_group_45":"Aeropuerto\/Estaci\u00f3n\/Puerto","item_group_46":"Barrios","item_group_47":"Departamento","item_group_48":"Centro de convenci\u00f3n","field_1":"Cadena hotelera","field_2":"Leading Hotels of the World","field_3":"Relais & Ch\u00e2teaux","field_4":"Ring Hotels","field_5":"Romantik hotels","field_6":"Small luxury Hotels of the World","field_7":"The Luxury Collection","field_8":"Borrar otros","field_9":"Ninguno_BORRAR","field_10":"Centro de belleza","field_11":"Adaptado para minusv\u00e1lidos","field_12":"Escenario","field_13":"Centro de negocios","field_14":"Cafeter\u00eda","field_15":"Ba\u00f1o turco\/vapor","field_16":"Sala de videojuegos","field_17":"Disco\/Club","field_18":"Recepci\u00f3n\/ lobby","field_19":"Express check-in\/check-out","field_20":"Elevador","field_21":"Sala de televisi\u00f3n","field_22":"Detector de fuego","field_23":"Gimnasio","field_24":"Peluquer\u00eda","field_25":"Estacionamiento","field_26":"Jard\u00edn o parque","field_27":"Terraza","field_28":"Mozo portaequipajes","field_29":"Propio campo de golf","field_30":"Mascotas permitidas","field_31":"Bar en el hotel","field_32":"Bar hotel en la playa","field_33":"Bar hotel con vistas","field_34":"Bar en la alberca","field_35":"Alberca Exterior","field_36":"Alberca techada","field_37":"Caja de seguridad","field_38":"Cunas disponibles","field_39":"Ni\u00f1eras","field_40":"Tienda\/Boutique","field_41":"Sala de conferencias","field_42":"Masajes","field_43":"Portero nocturno","field_44":"Hab. no fumadores","field_45":"PC con acceso a internet","field_46":"Casino","field_47":"Restaurante","field_48":"Recepci\u00f3n 24 horas","field_49":"Acc. para silla de ruedas","field_50":"Habitaciones tranquilas","field_51":"Sauna","field_52":"Tiendas en el hotel","field_53":"Snack bar","field_54":"Cabina de rayos UVA","field_55":"Acceso directo a la playa","field_56":"Sombrillas","field_57":"Camastros","field_58":"Toallas en la piscina","field_59":"Lavander\u00eda","field_60":"Spa","field_61":"Jacuzzi","field_62":"Internet Wi-Fi","field_63":"Servicio de Camarista","field_64":"Servicio de Camarista 24 hrs.","field_65":"Hab. con balc\u00f3n\/terraza","field_66":"Bungalows","field_67":"Limpieza de bolero","field_68":"Borrar n\u00famero de habitaciones","field_69":"Chimenea (casa\/apartamento vacaciones)","field_70":"Lavavajillas (casa\/apartamento vacaciones)","field_71":"Lavadora","field_72":"Barcas disponibles","field_73":"Borrar otros","field_74":"Ba\u00f1o con ba\u00f1era","field_75":"Ba\u00f1o con regadera","field_76":"Ventilaci\u00f3n","field_77":"Equipo para planchar","field_78":"Fax","field_79":"Ventanas que se abren","field_80":"Televisi\u00f3n","field_81":"Detector de fuego","field_82":"Secador cabello","field_83":"Calefacci\u00f3n","field_84":"Plancha\/Prensa pantalones","field_85":"Cafetera","field_86":"Aire acondicionado","field_87":"Espejo facial","field_88":"Ventanas insonorizadas","field_89":"Frigobar","field_90":"Programaci\u00f3n Pay-Per-View","field_91":"Radio","field_92":"TV sat\u00e9lite","field_93":"Mesa de escritorio","field_94":"Zona de estar","field_95":"Tel\u00e9fono","field_96":"Control remoto","field_97":"Caja de seguridad","field_98":"DVD\/Video","field_99":"Est\u00e9reo\/Reproductor de CD","field_100":"Videojuegos\/Playstation","field_101":"Televisi\u00f3n por cable","field_102":"C\u00f3digo de vestir espec\u00edfico en la comida","field_103":"Traje de etiqueta en el buffet","field_104":"Servicio de comidas principales","field_105":"Autopista","field_106":"Aeropuerto","field_107":"Estaci\u00f3n de tren","field_108":"Recinto ferial\/Centro Congresos","field_109":"Transporte p\u00fablico","field_110":"Centro de la ciudad","field_111":"Playa","field_112":"Badminton","field_113":"Voleibol\/Voleibol en la playa","field_114":"Billar","field_115":"Deportes de tiro","field_116":"Renta de barca","field_117":"Bolos","field_118":"Renta de bicicletas","field_119":"Campo de golf","field_120":"Gimnasio","field_121":"Correr\/ Patinar en l\u00ednea","field_122":"Minigolf","field_123":"Juegos de h\u00edpica","field_124":"Navegar","field_125":"Esquiar","field_126":"Squash","field_127":"Surf\/Windsurf","field_128":"Cancha de tenis techada","field_129":"Cancha de tenis","field_130":"Rutas","field_131":"Dinero efectivo","field_132":"Cheque","field_133":"Factura mediante la empresa","field_134":"EC\/Maestro","field_135":"American Express","field_136":"Diner\u00b4s Club","field_137":"Eurocard\/ Mastercard","field_138":"JCB Intl.","field_139":"Visa","field_140":"Apasionados del deporte","field_141":"Apasionados del deporte de invierno","field_142":"Mochileros","field_143":"Relajarse","field_144":"Apasionados de la gimnasia","field_145":"Golfistas","field_146":"Gourmet","field_147":"Amantes de la cultura","field_148":"Fiesteros","field_149":"Buceadores","field_150":"Navegantes","field_151":"Amantes del sol","field_152":"Personas ahorradoras","field_153":"Submarinistas","field_154":"Asociaci\u00f3n\/Club de viajeros","field_155":"Senderistas","field_156":"Entusiastas de lo acu\u00e1tico","field_157":"Entusiastas de los SPA","field_158":"Surferos","field_159":"Gente de negocios","field_160":"Hotel","field_161":"Bed & Breakfast","field_162":"Pensi\u00f3n\/Posada","field_163":"Motel","field_164":"Suite\/Condominio","field_165":"Ciudad de vacaciones","field_166":"Casa\/Apartamento","field_167":"Albergue\/Hostal","field_168":"Cuarto de hu\u00e9spedes","field_169":"Mirador","field_170":"Pub\/ Bar","field_171":"Excursi\u00f3n en barca","field_172":"Monumento","field_173":"Disco\/Club","field_174":"Edificio emblem\u00e1tico","field_175":"Campo de golf","field_176":"Casino","field_177":"Cine","field_178":"Catedral\/Iglesia\/Monasterio","field_179":"Pista para correr","field_180":"Museo\/Galer\u00eda\/Expos.","field_181":"Paraje natural","field_182":"Parque\/Jard\u00edn bot\u00e1nico","field_183":"Calle peatonal\/Calle de compras","field_184":"Cicloturismo","field_185":"Fiestas\/Eventos","field_186":"Restaurante","field_187":"Ruta por la ciudad","field_188":"Castillo\/Murallas\/Palacio","field_189":"Tiendas","field_190":"Estaci\u00f3n de esqu\u00ed","field_191":"Instalaciones deportivas\/Estadio","field_192":"Playa","field_193":"Submarinismo","field_194":"Teatro\/\u00d3pera","field_195":"Rutas a pie \/ escalada","field_196":"Balneario\/Spa","field_197":"Windsurf","field_198":"Zool\u00f3gico\/Acuario","field_199":"Tel\u00e9fono","field_200":"M\u00f3vil","field_201":"Fax","field_202":"Direcci\u00f3n","field_203":"C\u00f3digo postal","field_204":"Peri\u00f3dico","field_205":"Formaci\u00f3n","field_206":"Sueldo neto","field_207":"N\u00famero de personas que viven en su regi\u00f3n","field_208":"Profesi\u00f3n","field_209":"N\u00famero de personas que viven en su casa","field_210":"Estatus social","field_211":"Servicio de investigaci\u00f3n de mercado","field_212":"Hotel est\u00e1ndar","field_213":"Atracci\u00f3n tur\u00edstica est\u00e1ndar","field_214":"El que tiene mayor sueldo","field_215":"Hotel\/Club con todo incluido","field_216":"Hotel All Suite","field_217":"Hotel de autopista","field_218":"Hotel econ\u00f3mico","field_219":"Hotel club","field_220":"Hotel de dise\u00f1o","field_221":"Hotel de atracciones","field_222":"Hotel de vacaciones","field_223":"Hotel de aeropuerto","field_224":"Hotel de negocios","field_225":"Hotel de golf","field_226":"Hotel de salud","field_227":"Hotel de lujo","field_228":"Hotel de equitaci\u00f3n","field_229":"Hotel de deportes","field_230":"Hotel de ciudad","field_231":"Hotel 1\u00aa l\u00ednea de playa","field_232":"Hotel de congresos","field_233":"Hotel de tenis","field_234":"Hotel de SPA","field_235":"Hotel de zona de esqu\u00ed","field_236":"Otros-ELIMINAR","field_237":"N\u00famero de habitaciones","field_238":"Traveller Checks","field_239":"\u00daltimo registro bloqueado","field_240":"Nivel del gu\u00eda","field_241":"INFOSOURCE_1","field_242":"INFOSOURCE_2","field_243":"INFOSOURCE_3","field_244":"COMENTARIO POR CONFIRMAR","field_245":"Habitaciones para al\u00e9rgicos","field_246":"Animaci\u00f3n","field_247":"Doctor en el hotel","field_248":"Renta de carros","field_249":"Concierge","field_250":"Parque infantil","field_251":"Sal\u00f3n de lectura","field_252":"Miniclub","field_253":"Internet","field_254":"Wi-Fi  en las habitaciones","field_255":"Cocina\/Cadena de cocina","field_256":"Microondas","field_257":"Nevera","field_258":"Ventilador","field_259":"Bucear","field_260":"Mesa de ping pong","field_261":"Tr\u00e1nsito","field_262":"Luna de miel","field_263":"Solteros","field_264":"Familias","field_265":"Turistas","field_266":"Grupos grandes","field_267":"Estudiantes","field_268":"Viajeros activos","field_269":"Viajeros aventureros","field_270":"Lugar de acampadas","field_271":"Parque de atracciones","field_272":"Otros sitios de inter\u00e9s","field_273":"Patrimonio Natural","field_274":"Casa rural","field_275":"Granja","field_276":"Hotel para familias","field_277":"\u00bfC\u00f3mo conoci\u00f3 trivago?","field_278":"Titular de la cuenta","field_279":"C\u00f3digo bancario","field_280":"Nombre del banco","field_281":"N\u00famero de cuenta","field_282":"Aeropuerto\/Estaci\u00f3n\/Puerto","field_283":"Paypal Email","field_284":"Formas de pago","field_330":"Certified Business Hotels","field_331":"Entusiastas de los deportes de invierno","field_332":"Gay Friendly","field_333":"Entusiastas de lo acu\u00e1tico","field_334":"Viajeros con mascotas","field_339":"BrownHouse Hotels & Resorts","field_347":"Alberca","field_351":"Barrios","field_353":"Apartamento","field_354":"Centro de convenciones"});

		APP.PRICE.REGION.FILTER.INCLUDEALL.Init();
		//page elements
		APP.PRICE.REGION.FILTER.PAGING.Init();
		APP.PRICE.REGION.DESIGN.Init();
		APP.PRICE.REGION.PROGESSBAR.Init();
		APP.PRICE.REGION.NO_RESULTS.Init();
		APP.PRICE.REGION.FILTER.PARTNER.Init();
		APP.PRICE.REGION.TRANSPARENCY.Init();
		APP.PRICE.REGION.CACHE.FILTER.Set(APP.SNAPSHOT.Get(), requestIdent);

		//action blocks
		APP.PRICE.REGION.FILTER_CITYLIST.Init();		
		APP.PRICE.REGION.FILTER.QUERYSTRING.Init();
		APP.PRICE.REGION.TOP_NAV.Init();

		APP.PRICE.REGION.MAP.Init();

		APP.PRICE.REGION.FILTER.PRICE.Init(currency_before_price);
		APP.PRICE.REGION.FILTER.ATTRACTION.Init();
		APP.PRICE.REGION.FILTER.STARS.Init();
		APP.PRICE.REGION.FILTER.RATING.Init();
		APP.PRICE.REGION.FILTER.TOP_OPTION.Init();
		
		//fix labels for ipads/iphone/ipod
		APP.LABELS.fix($('filterbox_main'));
	}

	//
	//  is the start-call on the php-page, than we call directly this function and we must load the get-part (no-data)
	//  is the start-call on the client-page, than we have the data directly and can display the actual list.
	//  
	
	this.InitRpc = function(s, r)
	{
		service = { 'run':0, 'status':ajax_state_incomplete, 'resultcount':0  };
		
		if (r)
		{
			if (typeof r.snapshot != 'undefined')
			{
				APP.SNAPSHOT.Response(eval('('+r.snapshot+')'), true);
				
				// cache the search-request with all filter-options
				APP.PRICE.REGION.CACHE.FILTER.Set(APP.SNAPSHOT.Get(), requestIdent);
				APP.PRICE.REGION.HASH.Set(APP.SNAPSHOT.GetQuery(true, true, false));
			}

			if (r.skip_loading == '0')
			{
				this.readystatechangefunction(r, false);
			}
			else
			{
				service['resultcount'] = r.count;
				APP.PRICE.REGION.FILTER.PAGING.Show();
				if (finish_timeout_event)
				{
					window.clearTimeout(finish_timeout_event);
				}
			}
		}
		else
		{
			this.FetchData(requestIdent, s);
		}
	}
	
	//
	//
	//
	
	this.SetDisableStart = function(val)
	{
		disable_start = val;
	}

	//
	//  starting the price search. (start-part is client-page and not the server-page)
	//  @param s display the animation or not in the loading-procedure
	//  @param skip_loading skip the response. don't load the list or navigation again
	//
	
	this.Start = function(s, skip_loading, update_slider, loading_try)
	{
		if (disable_start)
		{
			return;
		}
		
		if (typeof loading_try == 'undefined')
		{
			loading_try = 0;
		}
	
		if (typeof update_slider == 'undefined')
		{
			APP.PRICE.REGION.FILTER.SLIDER.PRICE.UpdateSliderStatus(true);
		}
	
		(typeof skip_loading == 'undefined') && (skip_loading=0);
		APP.SNAPSHOT.Request('request_ident', (++requestIdent));

		// change layout
		APP.PRICE.REGION.FILTER.PAGING.Hide();
		(s != 1) && APP.PRICE.REGION.TRANSPARENCY.Show();

		this.SetTimeout();

		// start the load session
		(http_obj) && http_obj.abort();

		APP.PRICE.REGION.CACHE.FILTER.Flush(requestIdent);
		
		APP.PRICE.REGION.SYNTHETIC_DELAY.Clear();
		
		var r = this.GetResponse();
		if (r && r.items)
		{
			r = r.items;
		}

		var request_url = '/trivago_rpc.php?skip_loading=' + skip_loading + '&action=starthotelservice&' + APP.SNAPSHOT.GetQuery(true) + "&cached_items=" + encodeURI(APP.PRICE.REGION.CACHE.RESPONSE.GetCachedItems( r ));
		http_obj = new COM.HTTP.Request('GET', request_url, {
										'onfinish':function(j) {
											if (j)
											{
												APP.PRICE.EvalCode("APP.PRICE.REGION.InitRpc("+j.serviceId+", "+j+");");
											}
						      				else
						      				{
						      					//COM.Log('request -> starthotelservice undefined response' + j);
						      					if (loading_try<=3)
						      					{
						      						APP.PRICE.REGION.Start(s, skip_loading, update_slider, ++loading_try);
						      					}
						      				}
										}});
		this.StartRequest();
	}

	//
	// todo: cschmidt: comment more detailed
	// @param string r, response json-object
	// @param integer id, requestIdent - needed??
	//
	
	this.readystatechangefunction = function(r, id)
	{
		if (r.standby)
		{
			APP.PRICE.REGION.FILTER.PARTNER.Show(r.standby, service['status']);
			APP.PRICE.REGION.PROGESSBAR.CreateStandBy(r.standby, service['status']);
		}
	
		// check the correct requestIdent
		if (requestIdent != r.requestIdent)
		{
			COM.Log('break related by '+requestIdent+'!='+r.requestIdent);
			return false;
		}
	
		++service['run'];
		service['status']      = r.state;
		service['resultcount'] = r.count;
	
		// finished and no results?
		if (service['status'] == ajax_state_complete)
		{
			finish_timeout_event && window.clearTimeout(finish_timeout_event);
			if (r.error)
			{
				APP.PRICE.REGION.NO_RESULTS.DisplayErrorMessage(r, service['resultcount']);
			}
			else
			{
				APP.PRICE.REGION.NO_RESULTS.Hide();
			}
		}
	
		// if we do not have a result, than we hide the top order-list
		if (r.update == 1)
		{
			r.items = APP.PRICE.REGION.CACHE.RESPONSE.Get(r.items);
	
			// Städteliste
			if (APP.SNAPSHOT.Get('view_type') == 1)
			{
				APP.PRICE.REGION.FILTER_CITYLIST.Hide();
			}
			else
			{
				APP.PRICE.REGION.FILTER_CITYLIST.Set(r.citylist, r.city_hdl);
				APP.PRICE.REGION.FILTER_CITYLIST.Show();
			}

			APP.PRICE.REGION.FILTER.RESET.Update(r);

			if (	service['status'] == ajax_state_complete ||
					r.items	)
			{
				// response wird lokal in einem Array gespeichert
				service_response = r;

				// Aufbau der Liste
				APP.PRICE.REGION.DESIGN.CreateList(r.items);

				// update filter-navigation (slider inklusive)
				APP.PRICE.REGION.FILTER.Update();
			}

			// Geodaten auslesen
			APP.PRICE.REGION.GEODATA.Init(r.items);
	
			// Karte updaten
			if (service['status'] != ajax_state_complete)
			{
				APP.PRICE.REGION.MAP.UpdateDisplayMapStatus(false);
			}
		}
	
		// Liste verarbeiten
		this.FetchData(requestIdent, r.serviceId);
	}
	
	
	//
	//  get actual data from php. we call this loop max max_service_runs times
	//  @param requestIdent request-id
	//

	this.FetchData = function(requestIdent, serviceId)
	{
		try
		{
		if (	(service['status'] == ajax_state_complete) ||
				(service['run'] > max_service_runs) ||
				(	service['resultcount'] > 0 &&
					(new Date().getTime()-execution_time) >= timeout_complete	)	)
		{
			APP.PRICE.REGION.FILTER.PARTNER.Hide();
			APP.PRICE.REGION.PROGESSBAR.Hide();
			this.Finish();
		}
		// new get call when not ready
		else if (service['status'] != ajax_state_complete)
		{
			var r = this.GetResponse();
			if (r && r.items)
			{
				r = r.items;
			}

			var request_url = '/trivago_rpc.php?run=' + service['run'] + '&request_ident='+APP.SNAPSHOT.Get('request_ident')+'&action=gethotelservice&service_id=' + serviceId + '&service_resultcount=' + service['resultcount'] + '&url_hash=' + APP.SNAPSHOT.Get('url_hash') + '&path=' + APP.SNAPSHOT.Get('path') + '&cached_items=' + encodeURI(APP.PRICE.REGION.CACHE.RESPONSE.GetCachedItems( r  ));

			(http_obj) && http_obj.abort();
			http_obj = new COM.HTTP.Request('GET', request_url, {
						      				"onfinish": function(j) {
						      					if (j)
						      					{
						      						APP.PRICE.EvalCode("APP.PRICE.REGION.readystatechangefunction("+j+", "+requestIdent+");");
						      					}
						      					else
						      					{
						      						COM.Log('request -> gethotelservice undefined response' + j);
						      					}
										}});
				
			//start-request with a synthetic delay
			window.setTimeout(function(){APP.PRICE.REGION.StartRequest();}, APP.PRICE.REGION.SYNTHETIC_DELAY.GetTimeout(service['run'], service['resultcount']));
		}
		
		}
		catch(e)
		{
			COM.Log('func: FetchData, error'+e);
		}
	}

	//
	//  todo: cschmidt: comment
	//
	
	this.Finish = function()
	{
		try
		{
			finish_timeout_event && window.clearTimeout(finish_timeout_event);
		
			APP.PRICE.REGION.FILTER.PARTNER.Hide();
			APP.PRICE.REGION.PROGESSBAR.Hide();
	
			if (service['resultcount'] > 0)
			{
				APP.PRICE.REGION.MAP.UpdateDisplayMapStatus(true);
			}
			else if(service['run'] == 0)
			{
				APP.PRICE.REGION.NO_RESULTS.DisplayErrorMessage(false, service['resultcount'])
			}
		
			// change icon highlighting
			APP.PRICE.REGION.TOP_NAV.ChangeButtonOrder(APP.SNAPSHOT.Get('order_by'));
			
			window.setTimeout(function(){APP.PRICE.REGION.TRANSPARENCY.Hide();}, 30);
		}
		catch(e)
		{
			COM.Log('func: Finish, error'+e);
		}
	}

	//
	//
	//
	
	this.StartRequest = function()
	{
		http_obj.start();
	}

	//
	//
	//
	
	this.GetResponse = function()
	{
		return service_response;
	}
	
	//
	//
	//
	
	this.GetResultCount = function()
	{
		return service['resultcount'];
	}

	//
	//
	//

	this.SetTimeout = function()
	{
		execution_time = new Date().getTime();
		(finish_timeout_event) && window.clearTimeout(finish_timeout_event);
		if (!APP.PRICE.REGION.NO_RESULTS.IsDisplayed())
		{
			finish_timeout_event = window.setTimeout(function(){APP.PRICE.REGION.Finish();}, timeout_complete);
		}
	}
	
};
APP.PRICE.REGION.SYNTHETIC_DELAY = new function()
{

	//
	// private vars
	//
	
	var counter = 0; // repeat-counter

	//
	// set timeout
	//
	
	this.Clear = function()
	{
		counter = 0;
	}
	
	//
	// return timeout between get-requests
	// the delay is with every rpc-call a little bit bigger (from 1.5 seconds to 6 seconds)
	//
	
	this.GetTimeout = function(run, resultcount)
	{
		// first run = no delay
		if (run == 0)
		{
			return 0;
		}
		
		// no answer from java, than is the delay only 1 second
		if (resultcount == 0)
		{
			return 1000;
		}
	
		switch(++counter)
		{
			case 1 :
			case 2 :
				return 1500;
			
			case 3 :
			case 4 :
				return 2000;
					
			case 5 :
				return 4000;
				
			default :
				return 6000;
		}
	}
};
APP.PRICE.REGION.DESIGN = new function()
{

	//
	// private vars
	//

	var node,
		displayed_items=0,
	
		cache_trivago_rating = [];

	//
	//
	//
	
	this.Init = function()
	{
		node = $('hotellistitems');
	}

	//
	//  todo: cschmidt: comment
	//
	
	this.CreateList = function(items)
	{
		if ((items) && (items.length>0))
		{
			if (displayed_items>0)
			{
				APP.PRICE.REGION.ONSCREEN.ReloadList('unset');
			}
	
			node.innerHTML = APP.PRICE.REGION.DESIGN.Get(items);
		
			APP.PRICE.REGION.FILTER.PAGING.Show();	
			APP.PRICE.REGION.DESIGN.Show();
			APP.PRICE.REGION.TRANSPARENCY.Hide();
			
			// set bookmark links
			// disabled until c-testing
			if(true)
			{
				for(k=0,n=items.length;k<n;k++)
				{
					APP.SIDEBAR.ShowBookmark(items[k].id);
				}
			}

			if (displayed_items>0)
			{
				APP.PRICE.REGION.ONSCREEN.ReloadList('set');
			}

			displayed_items = items.length;
		}
	}
	
	//
	//
	//
	
	this.Show = function()
	{
		node.appear();
	}
	
	//
	//
	//
	
	this.Hide = function()
	{
		node.disappear();
	}
	
	//
	//
	//
	
	this.GetBookingUrl = function(item)
	{
		var retval = " onclick=\"";
		
		if((item.price) && (item.price.url))
		{
			retval += "APP.CLICKOUT.Open('" + item.price.url + "','"+item.price.partner+"');";
		}
		else
		{
			retval += "window.location.href='/item.php?hlpath=" + APP.SNAPSHOT.Get('path') + "&item=" + item.id + "&pagetype=deals'";
		}
		
		retval += "\"";

		return retval; 
	}	
	
	//
	//  The showimg-function is the same like the php-function "showimg"
	//
	
	this.ShowImg = function(item_id, cimage, id, img_type, link, css_class, attribs)
	{
		var img_id = "" + id;
		var sub_path = img_id.length > 3? img_id.substring(0,2) + "/" + img_id.substring(2,4) + "/": "0/",
			retval = '';
		attribs = typeof attribs == 'undefined' ? '' : attribs;
		
		if (link)
		{
			retval += "<a href=\"" + link + "\""+(css_class ? " class=\""+css_class+"\"" : "")+">";
			css_class = false;
		}
		retval += "<img src='http://imgll.trivago.com/itemimages/" + sub_path + id + "_" + img_type + ".jpeg' "+attribs+(css_class ? " class=\""+css_class+"\"" : "")+" />";
		if (link)
		{
			retval += "</a>";
		}
		
		return retval;
	}
	
	//
	//
	//
	
	this.GetPartnerImg = function(file)
	{
		return "<img src=\"http://il1.trivago.com/images/partnerlogos/" + file + "\" />";
	}
	
	//
	// copy from the php function getTrivagoRating()
	//
	
	this.GetTrivagoRating = function(val, item_id, name)
	{
		var key = val + "|" + item_id + "|" + (APP.SNAPSHOT.Get('view_type') == 0 ? '1' : '0'),
			color_value;
		
		if (cache_trivago_rating[key])
		{
			return cache_trivago_rating[key];
		}

		if (val>=8181)
		{
			color_value = 1;
		}
		else if (val>=7863)
		{
			color_value = 2;
		}
		else if (val>=7530)
		{
			color_value = 3;
		}
		else if (val>=7173)
		{
			color_value = 4;
		}
		else if (Math.round(val/100)==0 || !val)
		{
			color_value = 0;
		}
		else
		{
			color_value = 5;
		}

		cache_trivago_rating[key] = "<div class=\"rating_quadrat"+color_value+" ";
		if (val)
		{
			cache_trivago_rating[key] += "pointer\" onclick=\"APP.PRICE.REGION.ONSCREEN.Engage(this,'rating','"+item_id+"');\" ";
			cache_trivago_rating[key] += " onmouseout=\"APP.PRICE.REGION.ONSCREEN.Hide();\"";
			cache_trivago_rating[key] += " title=\""+APP.PRICE.STRINGS.Get('list_title_ratings1').split('$name').join(name)+"\"";
		}
		else
		{
			cache_trivago_rating[key] += "\" title=\""+APP.PRICE.STRINGS.Get('list_title_ratings0').split('$name').join(name)+"\"";
		}
		
		cache_trivago_rating[key] += ">";
		cache_trivago_rating[key] += val ? Math.round(val/100) : '';
		cache_trivago_rating[key] += "</div>";

		return cache_trivago_rating[key];					 
	}
	
	//
	//  todo: cschmidt: comment (!!!)
	//
	
	this.Get = function(items)
	{
		var retval = '<div class="hotellistitems">';

		for (var i=0, n=items.length; i<n; ++i)
		{
			if (typeof items[i].name == 'undefined')
			{
				COM.Log('region-price-search | display undefined | ' + items[i].id);
			}
			
			retval += this.GetSingle(items[i], i, false);
		}
		
		retval += '</div>';
		
		return retval;
	}
	
	//
	//  todo: cschmidt: comment (!!!)
	//
	
	this.GetSingle = function(i, no, is_highlight)
	{
		var retval              = "",
			baselink            = "/item.php?hlpath=" + APP.SNAPSHOT.Get('path') + "&item=" + i.id + "&path=" + i.path + "&date_range::to="+APP.SNAPSHOT.Get('date_range::to')+"&date_range::from="+APP.SNAPSHOT.Get('date_range::from')+"&room_type="+APP.SNAPSHOT.Get('room_type');
		var dealslink           = baselink + "&pagetype=deals",
			do_available_search = APP.SNAPSHOT.Get('do_available_search'),
			attribs				= '',
			city_name			= '';
		
		retval  += "<div id=\"js_item_"+i.id+"\" class=\"hotellistitem"+(!do_available_search ? ' non_available' : '')+(is_highlight?" hover":"")+"\">"
				
		//build price-box
				+ this.GetPriceBox(i);
		
		if(APP.Retrieve('c4') == 1)
		{
			retval += "<div id=\"js_personal_bookmark_" + i.id + "\" class=\"gradient_bright_hover personal_bookmark\">"+APP.SIDEBAR.DisplayBookmark(i.id)+"</div>";			
		}
		
		//build hotelname
		retval  += "<h3 class=\"gradient_bright_hover"+(is_highlight?" gradient_hover":"")+"\">"
				+ "<a href='" + ((do_available_search && i.count_prices>0) ? dealslink : baselink) + "' class=\"cat"+i.cat+(i.cats?'s':'')+" "+(is_highlight?" hover":"")+"\">";

		if (!i.group)
		{
			retval += i.name;
		}
		else
		{
			retval += APP.PRICE.STRINGS.Get('seo_item_group_in_item').split('$item_name').join(i.name).split('$item_group').join(APP.PRICE.STRINGS.Get('item_group_' + i.group))
		}
 
		retval += "</a>"
				+ "</h3>";
	
		// build right highlighted-block
		if (i.cimage>0)
		{
			attribs  = " onclick=\"APP.PRICE.REGION.ONSCREEN.Engage(this,'gallery','"+i.id+"');\" ";
			attribs += " onmouseout=\"APP.PRICE.REGION.ONSCREEN.Hide();\"";
			attribs += "  title=\""+APP.PRICE.STRINGS.Get('list_title_images1').split('$name').join(i.name)+"\"";
		}
		else
		{
			attribs = " title=\""+APP.PRICE.STRINGS.Get('list_title_images0').split('$name').join(i.name)+"\"";
		}
		
		retval += "<div class=\"main_image\">"
				+ APP.PRICE.REGION.DESIGN.ShowImg(i.id, i.cimage, i.img, "sq", false, 'main_image', attribs);
		city_name = ((i.geo && i.geo.ref) ? i.geo.ref : '');
		if (city_name)
		{
			retval += "<div class=\"city\">"+city_name+"</div>";
		}
		retval += "</div>";
		
	
		// build details - block
		retval += "<div class=\"details\">"
				+ APP.PRICE.REGION.DESIGN.GetTrivagoRating(i.ol, i.id, i.name);
		
		
		retval += "<div class=\"distance ";
		if (i.geo && i.geo.ref && i.geo.icon=='disable')
		{
			retval += i.geo.icon+"\" title=\""+APP.PRICE.STRINGS.Get('list_title_distance1').split('$name').join(i.name)+"\"";
		}
		else if (i.geo && i.geo.dist || (i.geo && i.geo.icon!='disable'))
		{
			retval += i.geo.icon+"\"";
			retval += " onclick=\"APP.PRICE.REGION.ONSCREEN.Engage(this,'map','"+i.id+"');\" ";
			retval += " onmouseout=\"APP.PRICE.REGION.ONSCREEN.Hide();\"";
			retval += " title=\""+APP.PRICE.STRINGS.Get('list_title_distance1').split('$name').join(i.name)+"\"";
		}
		else
		{
			retval += " disable\" title=\""+APP.PRICE.STRINGS.Get('list_title_distance0').split('$name').join(i.name)+"\"";
		}
		retval += ">"+(i.geo?i.geo.dist:'')+"</div>";

	 	retval += "<div class=\"info";
	 	if (!i.info)
	 	{
	 		retval += " disabled\" title=\""+APP.PRICE.STRINGS.Get('list_title_info0').split('$name').join(i.name)+"\" ";
	 	}
	 	else
	 	{
	 		retval += "\" onclick=\"APP.PRICE.REGION.ONSCREEN.Engage(this,'info','"+i.id+"');\" ";
	 		retval += " onmouseout=\"APP.PRICE.REGION.ONSCREEN.Hide();\"";
	 		retval += " title=\""+APP.PRICE.STRINGS.Get('list_title_info1').split('$name').join(i.name)+"\"";
	 	}
	 	retval += "><!--  --></div>";
	 	
		// display alternative - partner
		if(APP.Retrieve('c11') && i.test_rate)
		{
			retval += "<div class=\"hoteltest\" onclick=\"APP.PRICE.REGION.DESIGN.ClickoutLink('', '"+i.test_rate.mg_request_id+"',"+APP.SNAPSHOT.Get('path')+", 0);\">\n";
			retval += "<div class=\"hoteltestpic\">";
			retval += APP.PRICE.STRINGS.Get('hoteltest_rate').split('$price').join(i.test_rate.price);
			retval += "</div></div>\n";
		}
		else if (i.cpartner>0)
		{
			retval  += "<div title=\""+APP.PRICE.STRINGS.Get('list_title_all_rates').split('$name').join(i.name)+"\" class=\"available_on round_borders gradient_bright_hover\" onclick=\"window.location.href='"+dealslink+"';\">"
					+  APP.PRICE.STRINGS.Get('all_prices_from_site'+(i.cpartner>1?'s':'')+'_x').split('$count').join(i.cpartner)
					+  "</div>";
		}

		retval +=  "<div class=\"clear\"><!-- --></div>";
		
		if (i.desc)
		{
			retval += "<div class=\"text\">";
		}
				  
		if (i.desc)
		{
			retval += i.desc
					+ "</div>";
		}
		retval += this.GetDealsList(i);

		retval  += "</div>";
				
		retval  += "<div class=\"deals_screen\" id=\"js_deals_screen_"+i.id+"\" style=\"display:none;\"><!--  --></div>";

		return retval + "</div>";
	}

	//
	//
	//
	
	this.GetDealsList = function(item)
	{
		var retval              = '',
			priceCols			= new Array(),
			bookingUrl          = '',
			dealslink           = '',
			count               = item.aprices ? item.aprices.length : 0,
			do_available_search = APP.SNAPSHOT.Get('do_available_search'),
			k                   = 0,
			baselink            = "/item.php?hlpath=" + APP.SNAPSHOT.Get('path') + "&pagetype=deals&date_range::to="+APP.SNAPSHOT.Get('date_range::to')+"&date_range::from="+APP.SNAPSHOT.Get('date_range::from')+"&room_type="+APP.SNAPSHOT.Get('room_type'),
			cssClass			= '',
			numCols				= 2,
			displayed_count_rates=0;

		retval = '<div class=\"alt_deals'+(!item.test_rate?' no_mg':'')+'\">';
		
		if (!APP.Retrieve('c11') && item.test_rate)
		{
			retval += "<ul class=\"alt_prices\">"
				   +  "<li onclick=\"APP.PRICE.REGION.DESIGN.ClickoutLink('', '"+item.test_rate.mg_request_id+"',"+APP.SNAPSHOT.Get('path')+",0);\" class=\"mystery_guest sprite_icon gradient_bright_only_hover\">"
				   +  "<div class=\"left\">" + item.test_rate.desc + "</div>"
			       +  "<div class=\"right\">" + item.test_rate.price + "</div>"
				   +  "</li>"
				   +  "</ul>";
		}
		
		// calculate displayed count of rates for the red-price
		for(i=0; i<count; i++)
		{
			if (item.aprices[i].url)
			{
				displayed_count_rates++;
			}
		}

		// display all alternative rates
		for(i=0; i<count; i++)
		{	
			k = i % numCols; //number of current column
			
			if(!do_available_search)
			{
				bookingUrl = " onclick=\"window.location.href='" + item.aprices[i].url + "';\"";
			}
			else if(item.aprices[i].url)
			{
				bookingUrl = " onclick=\"APP.PRICE.REGION.DESIGN.ClickoutLink('" + item.aprices[i].url + "',0,0,"+item.aprices[i].partner+");\"";
			}
			else
			{
				dealslink = baselink + "&item=" + item.id + "&path=" + item.path;

				bookingUrl = " onclick=\"window.location.href='" + dealslink + "';\"";
			}
	
			if(!priceCols[k])
			{
				priceCols[k] = '';
			}
			
			if (item.aprices[i].price)
			{
				priceCols[k]	+= "<li " + bookingUrl + " class=\"sprite_icon round_borders gradient_bright_only_hover " + cssClass + "\">"
					   			+  "<div class=\"left\">" + APP.PRICE.STRINGS.Get('partner_'+item.aprices[i].partner) + "</div>"
		    	       			+  "<div class=\"right"+(item.price_max!='0' && i+1==displayed_count_rates ? ' red' : '')+"\">" + item.aprices[i].price + "</div>"
					   			+  "</li>";
			}
			else
			{
				var partner_name = APP.PRICE.STRINGS.Get('partner_'+item.aprices[i].partner);
				priceCols[k]	+= "<li class=\"sprite_icon nonavailable " + cssClass + "\" title=\""+APP.PRICE.STRINGS.Get('hotel_booked_out_name').split('$name').join(partner_name)+"\">"
					   			+  "<div class=\"left\">" + partner_name + "</div>"
		    	       			+  "<div class=\"right\"></div>"
					   			+  "</li>";
			}
		}
		
		for(i=0,n=priceCols.length; i<n; i++)
		{
			retval	+= "<ul class=\"alt_prices row"+i+"\">"
					+  priceCols[i]
					+  "</ul>";
		}
		
		if (APP.Retrieve('c11') && item.test_rate)
		{
			var gnorfl = baselink + "&item=" + item.id + "&path=" + item.path;
			retval += "<div title=\""+APP.PRICE.STRINGS.Get('list_title_all_rates').split('$name').join(item.name)+"\" class=\"available_on c11 round_borders gradient_bright_hover\" onclick=\"window.location.href='"+gnorfl+"';\">\n";
			retval += APP.PRICE.STRINGS.Get('all_prices_from_site'+(item.cpartner>1?'s':'')+'_x').split('$count').join(item.cpartner).replace("<br/>"," ");
			retval += "</div>\n";
		}
		
		retval += "</div>";
		
		return retval;
	}	
	
	//
	//
	//
	
	this.HClickoutLink = function(link, mg_request_id, path, partner)
	{
		return this.ClickoutLink(APP.LB.base64_decode(link), mg_request_id, path, partner);
	}
	
	//
	//
	//

	this.ClickoutLink = function(link, mg_request_id, path, partner)
	{
		if (mg_request_id==0)
		{
			APP.CLICKOUT.Open(link, partner);
		}
		else
		{
			var url = '/screenform.php?&pagetype=mystery_guest_rate&path='+path+'&mg_request_id='+mg_request_id;
			COM.HTTP.Get(url, { 'onfinish':function(r) {
					APP.WIZ.Module(r, 'screenmodule mystery_guest');
					APP.InnerExec(r);
			}});
		}
	}
	
	//
	// build the price-box
	//
	
	this.GetPriceBox = function(i)
	{
		var retval             = '',
			non_available_mode = !APP.SNAPSHOT.Get('do_available_search'),
			onclick_event 	   = '';

		if(!(i.price && i.price.no_availability) || (i.price && i.price.no_availability && non_available_mode))
		{
			onclick_event = APP.PRICE.REGION.DESIGN.GetBookingUrl(i);
		}
		
		retval += "<div class=\"info_field"+(i.aprices && i.aprices.length<=1?' bottom':'')+"\" "+onclick_event;
		
		if((i.price) && (i.price.img_m))
		{	
			var partner_img = "http://il1.trivago.com/images/partnerlogos/" + i.price.img_m;	
			retval += " onmouseover=\"$(this).getElementsByTagName('img')[0].src='"+partner_img.split('_bg').join('')+"';\" "
					+ " onmouseout=\"$(this).getElementsByTagName('img')[0].src='"+partner_img+"';\"";
		}
		retval += ">";
		
		if((i.price) && (i.price.img_m))
		{
			retval += APP.PRICE.REGION.DESIGN.GetPartnerImg(i.price.img_m);
		}

		if(i.price && i.price.price)
		{
			retval += "<span class=\"best_price\">" + APP.PRICE.STRINGS.Get('best_price') + "</span>";
			retval += "<strong class=\"main_price\">" + i.price.price + "</strong>";
			if (i.price_max != '0')
			{
				retval += "<strike> " + i.price_max + "</strike>";
			}
			else
			{
				retval += "<br /><br />";
			}
		}
		else if(i.price && i.price.no_availability)
		{
			retval += "<br />";
			if(non_available_mode)
			{
				retval += "<a href=\"javascript:void(0);\"" + onclick_event + ">";
			}
			retval += i.price.no_availability;

			if(non_available_mode)
			{
				retval += "</a>";
			}
			retval += "<br /><br /><br />";
		}
		else if(i.price && i.avg_price && !i.price.no_availability)
		{
			retval += "<strong>" + i.avg_price + "</strong>";
		}

		if((non_available_mode && i.cpartner>0) || ((!non_available_mode) && (i.price) && (i.price.img_m)))
		{
			retval += "<div class=\"button_green\">" + APP.PRICE.STRINGS.Get(non_available_mode ? 'deals_proof' : 'deals_forward3') + "</div>";
		}

		retval += "</div>";

		return retval;
	}
	
	//
	//
	//	

	this.getCheckbox = function(name, id, is_checked, is_disabled, attribs)
	{
		var retval = '',
			key;

		attribs['onclick'] = "this.parentNode.className=(this.checked?'checkbox_active':'checkbox');"+attribs['onclick'];
			
		retval  = "<span class=\"checkbox"+(is_checked?"_active":"")+"\">";
		retval += "\t<input "+(is_checked ? " checked=\"checked\"" : "")+" type=\"checkbox\" class=\"checkbox\" ";
		for(key in attribs)
	  	{
			if({'function':1,'undefined':1}[typeof attribs[key]])
			{
				continue;
			}
			retval += " "+key+"=\""+attribs[key]+"\" ";
		}
		retval += " value=\"1\" id=\""+id+"\" name=\""+name+"\" onfocus=\"this.blur();\" />\n";
		retval += "</span>";
			
		return retval;
	}

};APP.PRICE.REGION.ONSCREEN = new function()
{
	var is_displayed = false,
		is_init = false,
		node,
		onscreens = new Array(),
		displayed_screen = '',
		engage_overlay=false,
		engage_overlay_screen='',
		engage_item='',
		item,
		last_display_item,
		timeout_id,
		has_focus,
		disable_function=false;
	
	//
	// init all onscreens
	//
	
	this.Init = function()
	{
		if (!is_init)
		{
			onscreens['info']    = new APP.PRICE.REGION.ONSCREEN.INFO();
			onscreens['map']     = new APP.PRICE.REGION.ONSCREEN.MAP();
			onscreens['rating']  = new APP.PRICE.REGION.ONSCREEN.RATING();		
			onscreens['gallery'] = new APP.PRICE.REGION.ONSCREEN.GALLERY();
			is_init = true;
		}
	}
	
	//
	//
	//

	this.GetInstance = function(screen)
	{
		return onscreens[screen];
	}

	//
	// public
	//

	this.Disp = function(mnode, screen, pitem)
	{
		if (disable_function || engage_overlay)
		{
			return;
		}

		this.Abort();
		timeout_id = window.setTimeout(function(){
							APP.PRICE.REGION.ONSCREEN.DispDelayed(mnode, screen, pitem);
						}, 175);
	}
	
	//
	// private
	//

	this.DispDelayed = function(mnode, screen, pitem)
	{
		this.Init();

		if ((engage_overlay_screen==screen && engage_item==pitem) || (item==pitem && displayed_screen==screen))
		{
			return;
		}
		else if (is_displayed)
		{
			node.style.height = '';
			node.disappear();
		}
		
		displayed_screen = screen;
		is_displayed = true;
		last_display_item = item = pitem;
		node = $('js_deals_screen_'+pitem);
		
		if (!node.isElement())
		{
			return;
		}

		if (node)
		{
			try
			{
				var all_items = $('hotellistitems').lastChild.childNodes;
				for (var i=0, n=all_items.length; i<n; i++)
				{
					$(all_items[i]).delClass('ie_fix');
				}
			}
			catch(e){}
		}
		
		$(node.parentNode).addClass('ie_fix');

		this.HasFocus(true);

		this.SetInnerHTML('');
				
		//hier comes an animated appear
		node.appear();
		node.style.height = '0px';

		var effect = new APP.EFFECT.SlideDown(node, {	'scaleY' : true,
														'target_size' : 306,
														'steps' : 5,
														'duration' : 0.04,
														'onfinish' : function()
														{
															if(APP.PRICE.REGION.ONSCREEN.HasFocus())
															{
																onscreens[screen].Get(item);
															}
															else
															{
																var node = $('js_deals_screen_'+pitem);
																node.disappear();
																node.style.height = '';
															}
														},
														'onchange' : function(step)
														{
															if(APP.PRICE.REGION.ONSCREEN.HasFocus() == false)
															{
																effect.Abort();
																var node = $('js_deals_screen_'+pitem);
																node.disappear();
																node.style.height = '';
															}
														}
													});
	} 
	
	//
	//
	//
	
	this.Engage = function(mnode, screen, pitem)
	{
		var disp_new_overlay = (item!=pitem || displayed_screen!=screen);
	
		if (!engage_overlay || (pitem!=engage_item || engage_overlay_screen!=screen))
		{
			this.EnableEngage(screen, pitem);
		}
		else
		{
			engage_overlay = false;
			engage_overlay_screen = false;
			engage_item = '';
			
			if (!disp_new_overlay)
			{
				this.Hide(true);
			}
		}
		
		this.EnableEngage(screen, pitem);
		node = $('js_deals_screen_'+pitem);

		if (disp_new_overlay && node)
		{
			this.Hide(true, {'onfinish':function(){
					APP.PRICE.REGION.ONSCREEN.DispDelayed(mnode, screen, pitem);
					APP.PRICE.REGION.ONSCREEN.EnableEngage(screen, pitem);
				}});
		}
		else
		{
			this.Hide(true, {});
		}
	}
	
	//
	//
	//

	this.EnableEngage = function(screen, pitem)
	{
		engage_overlay = true;
		engage_overlay_screen = screen;
		engage_item = pitem;
	}
	
	//
	//
	//

	this.SetInnerHTML = function(val)
	{
		if	(
				typeof(val) !== 'undefined' &&
				typeof(item) !== 'undefined'
			)
		{
			$('js_deals_screen_'+item).innerHTML = val + "<div class=\"footer gradient_dark_hover\" onclick=\"APP.PRICE.REGION.ONSCREEN.Hide(true);\"><div class=\"arrow\"><!--  --></div></div>";
		}
	}
	
	//
	//
	//
	
	this.Hide = function(manual_close, params)
	{
		engage_overlay=true;

		if (this.SetDisableFunction())
		{
			return;
		}
		manual_close = typeof manual_close == 'undefined'?false:manual_close;

		if (engage_overlay && engage_overlay_screen==displayed_screen && !manual_close)
		{
			return;
		}
		this.Abort();
		this.HasFocus(false);
		if (displayed_screen && onscreens[displayed_screen])
		{
			onscreens[displayed_screen].UnLoad();
		}
		this.SetInnerHTML('');

		var item_tmp = item;
		engage_overlay_screen = false;
		engage_overlay = false;
		engage_item = false;
		item = false;
		displayed_screen = false;

		//here comes disappear
		new APP.EFFECT.SlideUp(node, {	'scaleY' : true,
										'target_size' : 0,
										'onfinish' : function(){
											var node = $('js_deals_screen_'+item_tmp);
											if (node.isElement())
											{
												node.disappear();
												node.style.height = '';
											}
											try{
											if (params && params['onfinish'])
											{
												params['onfinish'] = COM.GET.Function(params['onfinish']);
												params['onfinish']();
											}
											}catch(e){}
									}});
		engage_overlay=false;
	}
	
	//
	//
	//

	this.HasFocus = function(val)
	{
		if(typeof(val) !== 'undefined')
		{
			has_focus = val;
		}
		
		return has_focus;
	}
	
	//
	// 
	//
	
	this.Abort = function()
	{
		(timeout_id) && (window.clearTimeout(timeout_id));
	}
	
	//
	//
	//

	this.ReloadList = function(type2)
	{
		try
		{
			switch(type2)
			{
				case 'unset' :
					this.HasFocus() && (disable_function = true);
					var node = $('js_deals_screen_'+item);
					if (node.isElement())
					{
						$(node.parentNode).removeChild(node.parentNode.lastChild);
						try{
						var node_overlay = $('js_overlay_tmp');
						node_overlay.appendChild(node.cloneNode(true));
						node_overlay.style.top = node.getAbsTop()+"px";
						node_overlay.style.left = node.getAbsLeft()+"px";
						node_overlay.style.height = node.getHeight()+"px";
						node_overlay.style.width = node.getWidth()+"px";
						node_overlay.appear();
						
						$(node_screen.parentNode).delClass('ie_fix');
						}catch(e){}
					}
					break;
					
				case 'set' :
					if (this.HasFocus())
					{
						window.setTimeout(function(){APP.PRICE.REGION.ONSCREEN.SetDisableFunction(false);}, 125);
					}
					var node = $('js_overlay_tmp').cloneNode(true);
					if ($(node).isElement() && item && $('js_deals_screen_'+item).isElement())
					{
						var node_overlay = $('js_overlay_tmp');
						node_overlay.disappear();
						node_overlay.innerHTML='';

						var parent_node = $('js_deals_screen_'+item).parentNode;
						parent_node.removeChild(parent_node.lastChild);
						parent_node.appendChild(node.firstChild);
						$(parent_node).addClass('ie_fix');
					}
					break;
			}
		}
		catch(e)
		{
			COM.Log('.ReloadList() -> ' + e);
		}
	}
	
	//
	//
	//
	
	this.SetDisableFunction = function(val)
	{
		disable_function = val;
	}
};
APP.PRICE.REGION.ONSCREEN.GALLERY = function()
{
	var list,
		list_loaded = false,
		timeout_id,
		interval_id,
		displayed_no = 1,
		is_active = false,
		autorun = true,
		img_width,
		gallery_width;
	//
	//
	//

	this.Get = function(item)
	{
		this.UnLoad();
		is_active = false;
		displayed_no = 1;
		
		var Me = this;
		var request = new COM.HTTP.Request('GET', '/trivago_rpc.php?limit=10&action=item_gallery_images&offset=0&item=' + item + '&release=' + APP.Retrieve('release_version'), {
					'json':true,
					'onfinish':function(list)
					{
						if (list)
						{
							list_loaded = true;
							Me.CreateHTML(list);
						}
					}
					
					});
		request.start();

		return '';
	}
	
	//
	//
	//
	
	this.CreateHTML = function(plist)
	{
		list = plist;
		if (list.length>0)
		{
			var html = '<div class="gallery">'
					 + '<div id="gallery_container">';
			for(i=0, n=list.length; i < n; i++)
			{
				html += '<div class="img">'
					 + '<img id="js_gallery_img_'+list[i].id+'" src="' + list[i].large + '" />'
					 + '</div>';
			}
			html 	+= '</div>' 
					 + '<div id="arrow_left" class="arrow_left" onclick="APP.PRICE.REGION.ONSCREEN.GetInstance(\'gallery\').Backward();"><!--  --></div>'
					 + '<div id="arrow_right" class="arrow_right" onclick="APP.PRICE.REGION.ONSCREEN.GetInstance(\'gallery\').Forward()"><!--  --></div>'
					 + '</div>';
			APP.PRICE.REGION.ONSCREEN.SetInnerHTML(html);
	
			img_width = 389;
			gallery_width = list.length*img_width;
			$('gallery_container').style.width = gallery_width + 'px';
			
			if(list.length == 1)
			{
				$('arrow_left').style.display = 'none';
				$('arrow_right').style.display = 'none';
			}
			
			this.AutoRun();
		}
	}
	
	//
	//
	//
	
	this.AutoRun = function()
	{
		var Me = this;
		interval_id = window.setInterval(function(){Me.Forward(true);}, 2000);
	}

	//
	//
	//

	this.UnLoad = function()
	{
		(interval_id) && (window.clearInterval(interval_id));
		(timeout_id) && (window.clearTimeout(timeout_id));
	}

	//
	// public function for disable the dia-show
	//
	this.Backward = function(item)
	{
		if (list_loaded == false && (typeof(item) == 'number'))
		{
			return this.initMain(item, 0);
		}
			
		if (is_active == false)
		{
			this.UnLoad();
			var Me = this;
			new Me.Slide(0);
		}
	}

	//
	// display next image from the dia-show
	// The gallery will continue with the next image if autorun is active
	//

	this.Forward = function(autorun, item)
	{
		if (list_loaded == false && (typeof(item) == 'number'))
		{
			return this.initMain(item, 1);
		}
	
		if (is_active == false)
		{
			this.UnLoad();
			
			var Me = this;
			new Me.Slide(1);
			
			if(autorun)
			{
				this.AutoRun();
			}
		}
	}
	
	//
	// slideshow for image gallery
	//
	this.Slide = function(direction)
	{
		var step = 1,
			timeout_id,
			steps = 14,
			prefix,
			position = $('gallery_container').style.left.replace(/px/,'') * -1,
			Me = this;
		
		//
		//
		//

		this.Init = function()
		{
			is_active = true;
			this.ShiftImage(direction);
			prefix = (direction == 0) ? -1 : 1;
		}
		
		//
		//
		//
		
		this.Exec = function()
		{
			var offset = (img_width / steps * step) * prefix;
			
			$('gallery_container').style.left = Math.round((position + offset) * -1) + 'px';
			
			step++;
			if (step <= steps)
			{
				timeout_id = window.setTimeout(function(){Me.Exec();}, 30);
			}
			else
			{
				is_active = false;
			}
		}

		//
		// Append image before/after the gallery for endless scrolling
		//
		// @param integer direction (1=forward, 0=backward)
		//
		this.ShiftImage = function(direction)
		{
			var node = $('gallery_container'),
				newNode;

			if (	direction == 1 &&
					(position + img_width == gallery_width)	)
			{
				newNode = node.firstChild.cloneNode(true);
				position = position - img_width;
				node.style.left = (position * -1) + 'px';		
				node.appendChild(newNode);
				node.removeChild(node.firstChild);
			}
			else if (	direction == 0 &&
						position == 0	)
			{
				newNode = node.lastChild.cloneNode(true);
				position = img_width;
				node.style.left = (position * -1) + 'px';		
				node.insertBefore(newNode, node.firstChild);
				node.removeChild(node.lastChild);
			}
		}

		this.Init();
		this.Exec();
	}
	
	//
	// Init the main image slider
	//
	
	this.initMain = function(item, direction)
	{
		img_width = 200;
		autorun = false;
		
		list = new Array();
		list.push($('gallery_container').firstChild);
		
		var Me = this;
		var request = new COM.HTTP.Request('GET', '/trivago_rpc.php?limit=10&action=item_gallery_images&offset=0&item=' + item + '&release=' + APP.Retrieve('release_version'), {
					'json':true,
					'onfinish':function(list)
					{
						if (list && Me.CreateGallery(list))
						{
							list_loaded = true;
							
							if(direction == 0)
							{
								Me.Backward();
							}
							else
							{
								Me.Forward();
							}
						}
					}
					
					});
		request.start();
		
		return true;
	}
	
	//
	// Get images by rpc_call and append to gallery
	//
	this.CreateGallery = function(plist)
	{
		if(plist.length>0)
		{
			var node_gallery = $('gallery_container');
			for(i=0, n=plist.length; i < n; i++)
			{
				var node = document.createElement("div");
				node.className = 'img';
				node.id = 'galleryImage_' + i;
				
				var nodeImg = document.createElement("img");
				nodeImg.id = 'main_gallery_img_'+plist[i].id;
				nodeImg.src = plist[i].small;
				
				node.appendChild(nodeImg);
				
				list.push(node);
				node_gallery.appendChild(node);
			}
			
			gallery_width = (n+1)*img_width;
			node_gallery.style.width = gallery_width + 'px';
			
			$('arrow_left').appear();
			$('arrow_right').appear();
		}
		
		return true;
	}
};
APP.PRICE.REGION.ONSCREEN.RATING = function()
{
	//
	//
	//

	this.Get = function(item)
	{
		var request = new COM.HTTP.Request(	'GET', '/trivago_rpc.php?action=item_rating&item=' + item + '&release=' + APP.Retrieve('release_version'), {
						'onfinish':function(str){
							if (str)
							{
								APP.PRICE.REGION.ONSCREEN.SetInnerHTML(str);
							}
						}
					});
		request.start();
		return '';
	}
	
	//
	//
	//

	this.UnLoad = function()
	{
	}
};
APP.PRICE.REGION.ONSCREEN.INFO = function()
{
	//
	//
	//

	this.Get = function(item)
	{
		var request = new COM.HTTP.Request(	'GET', '/trivago_rpc.php?action=item_info&item=' + item + '&release=' + APP.Retrieve('release_version'), {
						'onfinish':function(str){
							if (str)
							{
								APP.PRICE.REGION.ONSCREEN.SetInnerHTML(str);
							}
						}
					});
		request.start();
		return '';
	}
	
	//
	//
	//

	this.UnLoad = function()
	{
	}
};
APP.PRICE.REGION.ONSCREEN.MAP = function()
{
	var img_icon_hotel = 'http://il1.trivago.com/images/layoutimages/new_design_3/hotel_pointer.png',
		img_icon_path  = 'http://il1.trivago.com/images/layoutimages/mappointer/locator_center.png';

	//
	//
	//

	this.Get = function(item)
	{
		var request = new COM.HTTP.Request('GET', '/trivago_rpc.php?action=item_map&item=' + item + '&release=' + APP.Retrieve('release_version'), {'json':true}, true);
		var request_response = request.start();

		var retval  = "<img src=\"http://maps.googleapis.com/maps/api/staticmap?"
					+ "size=384x284"
					+ "&maptype=roadmap"
					+ "&markers=icon:"+img_icon_hotel+"|"+request_response.item.lat+","+request_response.item.lon
					+ "&markers=icon:"+img_icon_path+"|"+request_response.path.lat+","+request_response.path.lon
					+ "&markers=size:tiny|"
					+ "&key=" + APP.Retrieve('google_key')
					+ "&sensor=false"
					+ "\" />";
		APP.PRICE.REGION.ONSCREEN.SetInnerHTML(retval);

		return '';
	}

	//
	//
	//

	this.SetInit = function()
	{
	}

	//
	//
	//

	this.UnLoad = function()
	{
	}

};
APP.PRICE.REGION.HASH = new function()
{
	//
	//
	//
	
	this.add_event = function()
	{
		APP.HASH.Reg(this.key(), function(){ APP.PRICE.REGION.HASH.ChangeHash(); });
	}

	//
	//
	//
	
	this.del_event = function()
	{
		APP.HASH.Reg(this.key(), function(){});
	}

	//
	//
	//

	this.Init = function()
	{
		if (document.location.hash == '' && Browser.IE) 
		{
			//replacing is a fix with the history-back-feature and the first-site from the region-price-search
			COM.HASH.Init(this.key()+':"'+APP.SNAPSHOT.GetQuery(true, true)+'"');
		}
		else if (document.location.hash == '' || typeof document.location.hash == 'undefined')
		{
			document.location.replace(document.location.href+'#'+this.key()+':"'+APP.SNAPSHOT.GetQuery(true, true)+'"');
		}
		
		this.add_event();
	}

	//
	//
	//

	this.Set = function(snapshot)
	{
		this.del_event();

		if (Browser.IE || Browser.Opera)
		{
			snapshot = APP.HASH.Unconvert(snapshot);
			snapshot['request_ident'] = '';
			
			var hash = APP.HASH.Get(this.key());
			var do_change = false;
			var hash_cnt  = 0;
			for(h in hash)
			{
				(snapshot[h] == hash[h]) || (do_change = true);
				hash_cnt++;
			}
			if (!do_change)
			{
			    var snapshot_cnt = 0;
				for(s in snapshot)
				{
					snapshot_cnt++;
				}
				(hash_cnt != snapshot_cnt) && (do_change = true); 
			}
			if (do_change)
			{
				APP.HASH.Set(this.key(), snapshot);
			}
		}
		else
		{
			snapshot['request_ident'] = '';
			APP.HASH.Set(this.key(), snapshot);
		}
		
		this.add_event();
	}

	//
	//
	//

	this.key = function()
	{
		return 'price_region';
	}

	//
	//
	//

	this.ChangeHash = function()
	{
		var hash,
			param,
			retval = false,
			new_snap = [],
			fields=[],
			new_hash = APP.SNAPSHOT.GetQuery(true, true);

		//request_ident, url_hash
		if (	(hash = APP.HASH.Get(this.key())) &&
				(new_hash != APP.HASH.Convert(hash))	
			)
		{
			hash['request_ident'] = APP.SNAPSHOT.Get('request_ident');

			//convert structure 'f_' and so on to the fields-array
			for (param in hash)
			{
				if(param.split('f_').length > 1)
				{
					var field_id = param.split('f_');
					fields[field_id[1]] = hash[param];
				}
				else
				{
					new_snap[param] = hash[param];
				}
			}
			
			if (fields)
			{
				new_snap['fields'] = fields;
			}

			APP.SNAPSHOT.Response(new_snap);
			APP.PRICE.REGION.Start();

			retval = true;
		}
		
		return retval;
	}
};
APP.PRICE.REGION.PROGESSBAR = new function()
{
	//
	//  init object
	//
	
	this.Init = function()
	{
		node       = $('progressbar');
		node_value = $('progressbar_value');
		node_ani   = $('js_progressbar_ani');
		node_points= $('js_progressbar_points');
		
		points_interval_id = window.setInterval(function(){APP.PRICE.REGION.PROGESSBAR.SetPointAnimation();}, 500);
	}
	
	//
	//
	//
	
	this.SetPointAnimation = function()
	{
		if (++view_points==4)
		{
			view_points = 0;
		}

		var count_of_points = view_points,
			retval = '';

		for (var i=0; i<count_of_points; i++)
		{
			retval += '.';
		}
		
		node_points.innerHTML = retval;
	}
	
	//
	//  hide progressbar
	//

	this.Hide = function()
	{
		if (fake_interval_id)
		{
			window.clearInterval(fake_interval_id);
		}
		if (points_interval_id)
		{
			window.clearInterval(points_interval_id);
		}
		if (timeout_id)
		{
			window.clearTimeout(timeout_id);
		}		
		node.disappear();
	}
	
	//
	//  create our progressbar
	//
	
	this.CreateStandBy = function(pdata, servicestatus)
	{
		if (fake_interval_id)
		{
			window.clearInterval(fake_interval_id);
		}
	
		if ((servicestatus==ajax_state_complete) || (pdata.length==0) || (block))
		{
			node_value.innerHTML = "100%";
			if (!block && !APP.PRICE.REGION.NO_RESULTS.IsDisplayed())
			{
				window.setTimeout(function(){
								APP.PRICE.REGION.PROGESSBAR.Hide();}, 1000);
			}
			else
			{
				this.Hide();
			}
		}
		else
		{
		  	var all_loaded_partners = this.GetAllLoadedPartners(pdata);
		  	var procent = (pdata.length - all_loaded_partners.length) / (pdata.length/100);
		  	var response = APP.PRICE.REGION.GetResponse();
		  	if (response)
		  	{
				this.SetPartnerData(response.standby);
			}

			node.style.backgroundPosition = (-145+Math.round(procent*1.4))+"px 0px";
			node_value.innerHTML = Math.round(procent) + "%";
		
			if (Math.round(procent) == 100)
			{
				block = true;
			}
		}
	}
	
	//
	//
	//

	this.SetPartnerData = function(data)
	{
		partner_data = data;
	}

	//
	//
	//
	
	this.GetAllLoadedPartners = function(pdata)
	{
		var retval = [];
		
		for (var i=0, n=pdata.length; i<n; i++)
		{
			if (pdata[i].s == 0)
			{
				retval.push(pdata[i].i);
			}
		}

		return retval;
	}
	
	//
	//
	//
	
	this.SetFakeCounter = function()
	{
		fake_interval_id = window.setInterval(function(){
				var max=10, min=1;              
        		var addition = min + parseInt(Math.random() * (max - min));
        		var value = parseInt(node_value.innerHTML.split('%').join(''));
        		if (value<30)
        		{
					node_value.innerHTML=(value+addition)+'%';
				}
			}, 500);
	}
	
	//
	// private vars..
	//

	var node,
		node_value,
		node_ani,
		node_points,
		
		block = false,
		
		fake_interval_id = false,
		points_interval_id = false,
		timeout_id = false,
		
		partner_data,
		last_disp_partner = 0,
		
		view_points = 0,
		
		//ajax - state
		ajax_state_complete = 1;
};
APP.PRICE.REGION.TOP_NAV = new function()
{

	//
	// private vars
	//

	var node_view_types = [],
		node_map,
		order_buttons = [],

		default_order = {
						 'overall_liking': 'desc',
						 'price'    : 'asc',
						 'distance' : 'asc',
						 'relevance': 'desc'
						},
		loading_try = 0,
		is_default_order = true;

	//
	// init header
	//

	this.Init = function()
	{
		var button_ids = ['overall_liking', 'price', 'distance', 'relevance'];
		for (var i=0, n=button_ids.length; i<n; i++)
		{
			var node = $('js_order_' + button_ids[i]);
			order_buttons[ button_ids[i] ] = node.isElement() ? node : false;
		}

		for (var i=0; i<2; i++)
		{
			node_view_types[i] = $('list_view_style_' + i);
		}

		node_map = $('js_view_type');
	}

	//
	//  change the css-styles from the 3 order - buttons (overall_liking, price, distance)
	//  @param order ['overall_liking', 'distance', 'price']
	//

	this.ChangeButtonOrder = function(order)
	{
		var new_order = order.split(' '),
			order_alignment = '',
			key;

	  	for (key in order_buttons)
	  	{
			if ({'function':1,'undefined':1}[typeof order_buttons[key]])
			{
				continue;
			}

			if (order_buttons[key])
			{
				order_alignment = (new_order[0] == key) ? new_order[1] : default_order[new_order[0]];
				if (new_order[0]==key)
				{
					order_buttons[key].setClass( 'tab_active '+order_alignment );
				}
				else
				{
					order_buttons[key].setClass( 'tab_inactive '+order_alignment );
				}
			}
		}

		return true;
	}

	//
	//  todo: cschmidt: comment
	//

	this.ToggleViewType = function()
	{
		//page loaded?
		if (APP.SNAPSHOT.Get('do_available_search') == null)
		{
			if (++loading_try <= 20)
			{
				window.setTimeout(function(){
						APP.PRICE.REGION.TOP_NAV.ToggleViewType();
					}, 100);
			}
			return;
		}

		//change view_type?
		var view_type = APP.SNAPSHOT.Get('view_type')==1 ? 3 : 1;

		APP.SNAPSHOT.Request('view_type', view_type);

		if (view_type==1)
		{
			$('js_view_type').addClass('tab_active');
			$('js_view_type').delClass('tab_inactive');
			$('js_filter_details').appear();
			$('search_order_by').addClass('active');
			$('js_searchmap_box').appear();
			node_map.delClass('open');
		}
		else
		{

			$('js_view_type').delClass('tab_active');
			$('js_view_type').addClass('tab_inactive');
			$('search_order_by').delClass('active');
			$('js_searchmap_box').disappear();
			node_map.delClass('open');
			if (!APP.PRICE.REGION.FILTER.RESET.GetDisp())
			{
				$('js_filter_details').disappear();
			}
		}

		APP.PRICE.REGION.Start();
	}

	//
	//  change the order from the hotellist and load the new list.
	//  we must change the view_type related by the order=='distance' (display google-map)
	//
	//  @param order (options: overall_liking, price, distance)
	//

	this.ChangeListOrder = function(order)
	{
		// page loaded?
		if (APP.SNAPSHOT.Get('do_available_search') == null)
		{
			if (++loading_try <= 20)
			{
				window.setTimeout(function(){
						APP.PRICE.REGION.TOP_NAV.ChangeListOrder(order);
					}, 100);
			}
			return;
		}

		var new_order = order.split(' '),
			exists_order = APP.SNAPSHOT.Get('order_by').split(' ');

		order = new_order[0] + ' ';
		if (new_order[0] == exists_order[0])
		{
			order += (exists_order[1] == 'asc' ? 'desc' : 'asc');
		}
		else
		{
			order += default_order[new_order[0]];
		}

		//select button
		this.ChangeButtonOrder(order);

		is_default_order = false;
		APP.SNAPSHOT.Request('order_by', order);
		APP.SNAPSHOT.Request('offset',   '0');
		APP.PRICE.REGION.Start();
	}

	//
	//
	//

	this.isDefaultSortOrder = function()
	{
		return is_default_order;
	}

}
APP.PRICE.REGION.FILTER = new function()
{

	//
	//
	//
	
	var loading_try = 0;

	//
	// update complete filter-box
	//
	
	this.Update = function()
	{
		try
		{
			var response = APP.PRICE.REGION.GetResponse(),
				snap = APP.SNAPSHOT.Get();
			var category  = snap['category']==null  ?   0 : snap['category'],
				price_max;

			APP.PRICE.REGION.FILTER.QUERYSTRING.SetQuery(snap['search_string']);

			APP.PRICE.REGION.FILTER.ATTRACTION.SetGeoDistanceLimit(snap['geo_distance_limit']);
			APP.PRICE.REGION.FILTER.ATTRACTION.SetResponseDistance(snap['geo_distance_limit']);
			APP.PRICE.REGION.FILTER.ATTRACTION.SetAttraction();
			APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.SetUserChanged(snap['geo_distance_limit']?true:false);

			APP.PRICE.REGION.FILTER.PARTNER.SetBlockedPartnerArray(snap['partner_filter']);

			if (response)
			{
				if (response.error)
				{
					APP.PRICE.REGION.FILTER.STARS.Set(category);
				}
			
				APP.PRICE.REGION.FILTER.TOP_OPTION.Set(response.stats.filter_fields);

				//APP.PRICE.REGION.FILTER.FIELDS.InitCheckboxes();
				APP.PRICE.REGION.FILTER.FIELDS.CreateHtml(response.stats.filter_fields);
				
				price_max = snap['price_max']==null ? response.stats.price_max : snap['price_max'];

				APP.PRICE.REGION.FILTER.PRICE.SetValue(response.stats.price_min, response.stats.price_max);
				APP.PRICE.REGION.FILTER.INCLUDEALL.SetIncludeAll(snap['include_all'] != 1);
				APP.PRICE.REGION.FILTER.PRICE.SetPriceValue(price_max);
				APP.PRICE.REGION.FILTER.PRICE.SetPreviewPrice();
				
				APP.PRICE.REGION.FILTER.STARS.Set(response.stats.category);
				APP.PRICE.REGION.FILTER.RATING.Set(response.stats.overall_liking);

				$('filterbox_main').appear();
			}

			// maximale Distanz eines Hotels (Stadtsuche), nur wenn nicht use_distance
			if 	(!APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.GetUserChanged())
			{
				var default_distance_limit = $('default_distance_limit').isElement() ? $('default_distance_limit').value : '';
				var max_distance = (response && response.stats.distance_max) ? response.stats.distance_max : default_distance_limit;
				if (max_distance != 'null')
				{
					APP.PRICE.REGION.FILTER.ATTRACTION.SetResponseDistance(max_distance);
				}
			}

			APP.PRICE.REGION.FILTER.FIELDS.InitCheckboxes();
		}
		catch(e)
		{
			COM.Log('func: APP.PRICE.REGION.FILTER.Update, error'+e);
		}
	}
	
	//
	//  we save every filter-configuration in the array "this.SearchCache". Maybe the user
	//  has a situation with no results, than we can go one filter-step back.
	//  is the array empty, than we reset the configuration (direct display-mode with prefilled filter)
	//
	
	this.LastRequest = function()
	{
		// load the last request
		var snap = APP.PRICE.REGION.CACHE.FILTER.GetLastSnapshot();

		if (snap != null)
		{
			APP.SNAPSHOT.Response(snap);
			APP.PRICE.REGION.Start(1);
		}
	}
	
	//
	// reset the filter settings and send a request to the server
	//
	
	this.ClearFilter = function()
	{
		//load first request
		var snap = APP.PRICE.REGION.CACHE.FILTER.GetFirstSnapshot();

		if (snap != null)
		{
			APP.SNAPSHOT.Response(snap);
			APP.PRICE.REGION.Start(1);
		}
	}

}
APP.PRICE.REGION.FILTER.STARS = new function()
{
	//
	// init class
	//
	
	this.Init = function()
	{
		for(var i=1; i<=5; i++)
		{
			node_stars[i] = $('js_star_'+i);
			node_checkboxes[i] = $('js_star_'+i+'_check');
		}
	}
	
	//
	//
	//
	
	this.Set = function(category_stats)
	{
		var category = APP.SNAPSHOT.Get('category'),
			do_available_search = APP.SNAPSHOT.Get('do_available_search'),
			status = '',
			category2enabled = [];

		if (category == null)
		{
			category = [0,1,2,3,4,5];
		}
		
		for (var i=0, n=category.length; i < n; i++)
		{
			category2enabled[ category[i] ] = category[i];
		}

		for (var i=1; i<=5; i++)
		{
			status = (!category2enabled[i]) ? 'inactive' : 'active';
			node_stars[i].setClass('stars round_borders star'+i+'_'+status);
			node_checkboxes[i].setAttribute('status', status);
			node_checkboxes[i].checked = (status=='active');
		}
	}
	
	//
	//
	//
	
	this.OnClick = function(no)
	{
		if (node_checkboxes[no].getAttribute('status') == 'disabled')
		{
			return;
		}
	
		if (APP.SNAPSHOT.Get('do_available_search') == null)
		{
			if (++loading_try <= 20)
			{
				window.setTimeout(function(){
						APP.PRICE.REGION.FILTER.STARS.OnClick(no);
					}, 100);
			}
			return;
		}

		var category = APP.SNAPSHOT.Get('category');
		if (category == null)
		{
			category = [0,1,2,3,4,5];
		}

		if (	node_checkboxes[no].checked ||
				(category.length == 6 && first_load == true)
			)
		{
			if(category.length == 6)
			{
				category = [];
			}
			
			if (no == 1)
			{
				category.push(0);
			}
			category.push(no);
			first_load = false;
		}
		else
		{
			var newCategory = [];
			for (var i=0, n=category.length; i < n; i++)
			{
				if	(
						(no!=category[i] && no!=1) ||
						(no!=category[i] && no==1 & 0!=category[i])
					)
				{
					newCategory.push(category[i]);
				}
			}
			category = newCategory;
			
			if (category.length == 0)
			{
				first_load = true;
			}
			else
			{
				first_load = false;
			}
		}

		APP.SNAPSHOT.Request('category', category);
		APP.SNAPSHOT.Request('offset', 0);
		APP.PRICE.REGION.Start();
	}
	
	//
	//
	//
	
	this.Clear = function()
	{
		APP.SNAPSHOT.Request('category', [0,1,2,3,4,5]);
		APP.SNAPSHOT.Request('offset', 0);
		APP.PRICE.REGION.Start();
	}
	
	//
	// private vars
	//
	
	var node_stars = [],
		node_checkboxes = [],
		loading_try = 0,
		first_load = true;
}
APP.PRICE.REGION.FILTER.QUERYSTRING = new function()
{

	//
	//  private vars
	//
	
	var node,
		node_submit,
		disable = false;

	//
	//  
	//
	
	this.Init = function()
	{
		node = $(document.forms['hotellist_search_string']['search_string']);
		node_submit = $('js_reset_search_string');
	}
	
	//
	// update the filter
	//

	this.SendRequest = function(send_request)
	{
		if (node.value != APP.PRICE.STRINGS.Get('searchstring'))
		{
			node.blur();
			
			if (node.value == APP.SNAPSHOT.Get('search_string'))
			{
				node.value = '';
			}
			
			APP.SNAPSHOT.Request('offset',	    '0');
			APP.SNAPSHOT.Request('search_string', node.value);
			
			if (send_request)
			{
				APP.PRICE.REGION.Start();
			}
		}
		
		return false;
	}

	//
	//  
	//

	this.SetQuery = function(value)
	{
		if (!disable)
		{
			node.value = (value==null ? '' : value);
			this.ChangeQuery(true);
		}
	}
	
	//
	//  
	//
	
	this.ChangeQuery = function(delete_default_text)
	{
		if (!node)
		{
			this.Init();
		}
		
		if (delete_default_text && node.value==APP.PRICE.STRINGS.Get('searchstring'))
		{
			node.value = '';
		}
		else if (delete_default_text && node.value == '')
		{
			if (APP.SNAPSHOT.Get('search_string'))
			{
				node.value = APP.SNAPSHOT.Get('search_string');
			}
			else
			{
				node.value = APP.PRICE.STRINGS.Get('searchstring');
			}
		}
		
		if(node.value == APP.SNAPSHOT.Get('search_string'))
		{
			node_submit.addClass('reset');
			node_submit.delClass('loupe');
		}
		else
		{
			if (node.value==APP.PRICE.STRINGS.Get('searchstring'))
			{
				node.addClass('gray');
			}
			else
			{
				node.delClass('gray');
			}
			
			node_submit.delClass('reset');
			node_submit.addClass('loupe');
		}
	}
	
	//
	//
	//
	
	this.Clear = function(send_request)
	{
		node.value = '';
		this.ChangeQuery(false);
		node.value = '';
		this.SendRequest(send_request);
	}
	
	//
	//
	//
	
	this.Disable = function(value)
	{
		disable = value;
		this.ChangeQuery(true);
	}

};
APP.PRICE.REGION.FILTER.FIELDS = new function()
{
	//
	//  the user click on a filter-field-option (checkbox) in the filter-navigation.
	//  The id "f_1" has a separate handling.
	//  @todo: make the separate-handling to the same? in php (complete app) is this field separate too.
	//

	this.Click = function(id, objekt, field_id)
	{
		if (APP.SNAPSHOT.Get('do_available_search') == null)
		{
			if(++loading_try <= 20)
			{
				window.setTimeout(function(){
						APP.PRICE.REGION.FILTER.FIELDS.Click(id, objekt, field_id);
					}, 100);
			}
			return;
		}
		
		var fields = APP.SNAPSHOT.Get('fields');
		if(fields == null)
		{
			fields = {};
		}
		
		var field_name = id.split('_');
		if(field_name[1] == '1')
		{
			fields[field_name[1]] = objekt.value = objekt.checked ? field_id : '';
		}
		else
		{
			fields[field_name[1]] = objekt.value = objekt.checked ? 1 : 0;
		}

		APP.SNAPSHOT.Request('fields', fields);
		APP.SNAPSHOT.Request('offset', 0);
		APP.PRICE.REGION.Start();
	}
	
	//
	// create one fields-group
	//
	// legend:
	// c: count
	// p: price
	// f: field
	// a: attrib
	// i: id
	//
	
	this.GetGroup = function(group_id, arr)
	{
		//empty?
		if(arr.length == 0)
		{
			return '';
		}
		
		var retval         = "",
			details,
			group_selected = this.GetGroupSelected(arr),
			field,
			str_hotels     = APP.PRICE.STRINGS.Get("hotels"),
			str_more       = APP.PRICE.STRINGS.Get("more"),
			count          = arr.length;
		var hash = APP.SNAPSHOT.Get('fields');

		for(var i=0; i<count; i++)
		{
			field = arr[i];
			
			if(!field.f)
			{
				continue;	
			}
			
			if((i == 3) && (count>3) && (!group_selected))
			{
				retval += "<div id=\"more_" + group_id + "\" class=\"more_button\">"
						+ "<em class=\"more_button\" onclick=\"$('less_"+group_id+"').appear();$('more" + group_id + "').toggle();$('more_" + group_id + "').disappear();\">" + str_more + "</em>"
						+ "</div>"
					    + "<div style=\"display:none;\" id=\"more" + group_id + "\">";
			}
			
			if(field.c)
			{
				details = " <span class=\"lighttext\">(" + field.c + " " + str_hotels + (field.p ? ' - ' + field.p : '') + ")</span>";
			}
			else
			{
				details = "";
			}
			
			var attribs = [];
			attribs['onclick'] = "APP.PRICE.REGION.FILTER.FIELDS.Click('" + field.a + "', this, '" + field.f + "');";
			var is_checked = hash?hash[field.f]:false;
			retval += APP.PRICE.REGION.DESIGN.getCheckbox('', field.i, is_checked, false, attribs)
					+ "<label for=\"" + field.i + "\"> "
					+ APP.PRICE.STRINGS.Get(((group_id == 1) ? 'value_label_1_' : 'field_') + field.f) // load string_name.hotel-chains have a different handling
					+ details
					+ "</label><br/>";
		}
		
		if(!retval)
		{
			return '';
		}

		if(count>3)
		{
			retval += "<div id=\"less_" + group_id + "\" class=\"more_button\" "+(!group_selected ? " style=\"display:none;\"" : "")+">"
					+ "<em class=\"more_button\" onclick=\"$('less_" + group_id + "').toggle();$('more_" + group_id + "').appear();$('more" + group_id + "').disappear();\">" + APP.PRICE.STRINGS.Get("less") + "</em>"
					+ "</div>";
					
			if (!group_selected)
			{
				retval += "</div>";
			}
		}

		return    "<div class=\"line filter_group"+(APP.Retrieve('c10')?" c10":"")+"\">"
				+ "<div id=\"js_filter__"+group_id+"\" class=\"group_headline bigtext\">" + APP.PRICE.STRINGS.Get("filter_group_" + group_id) + "</div>"
				+ "<div class=\"navigation_space\" id=\"js_filter_group_"+group_id+"\">" + retval + "</div>"
				+ "</div>";
	}
	
	//
	//
	//
	
	this.GetCompletedArray=function(group_id, arr)
	{
		for(var i=0, n=arr.length; i<n; i++)
		{
			if(group_id == 1) //hotel-chain has a different handling
			{
				arr[i].a = 'f_1';
				arr[i].i = 'f_1_' + arr[i].f;
			}
			else
			{
				arr[i].i = arr[i].a = 'f_' + arr[i].f;
			}
		}
		
		return arr;
	}
	
	//
	// create all fields
	//
	
	this.CreateHtml = function(arr)
	{
		if(!arr)
		{
			return false;
		}

		var retval = '',
			field,
			field_id;

		for(var i=0, n=arr.length; i<n; i++)
		{
			if (arr[i]['id'] > 0)
			{
				field    = arr[i];
				field_id = field['id'];
	
				field['c'] = this.GetCompletedArray(field_id, field['c']);
	
				retval += this.GetGroup(field_id, field['c']);
			}
		}
		
		$('js_filter_fields').innerHTML = retval;
		
		//fix labels for ipads/iphone/ipod
		APP.LABELS.fix($('js_filter_fields'));
	}
	
	//
	// 
	//
	
	this.InitCheckboxes = function()
	{
		var hash = APP.SNAPSHOT.Get('fields'), 
			key;

		for (key in hash)
		{
			if ({'function':1,'undefined':1,'object':1}[typeof hash[key]])
			{
				continue;
			}
			else
			{
				try
				{
					if(key=='1')
					{
						$("f_1_" + hash[key]).checked = true;
						$("f_1_" + hash[key]).parentNode.className = 'checkbox_active';
					}
					else if($('f_'+key).isElement())
					{
						$('f_'+key).checked = hash[key] == 1;
						$('f_'+key).parentNode.className = 'checkbox'+(hash[key] == 1?"_active":"");
					}
				}
				catch(e)
				{
					COM.Log('func:APP.PRICE.REGION.FILTER.FIELDS.InitCheckboxes(); '+key+': '+e);
				}
			}
		}
	}
	
	//
	//
	//
	
	this.GetGroupSelected = function(arr)
	{
		var retval = false,
			fields = APP.SNAPSHOT.Get('fields');
		
		if(fields)
		{
			for(var i=0, n=arr.length; i<n; i++)
			{
				if(fields[arr[i].f] == 1)
				{
					retval = true;
					break;
				}
			}
		}
		
		return retval;
	}
	
	//
	// private vars
	//
	
	var loading_try = 0;
};APP.PRICE.REGION.FILTER.ATTRACTION = new function()
{
	//
	//
	//

	this.SendRequest = function()
	{
		var node = $(document.forms['distance_search']['geo_address_string']);

		node.blur();
		if (	node.value != node.getAttribute('default')	)
		{
			APP.PRICE.MAP.SetDistanceChange(true);
			APP.PRICE.MAP.Search(true);
		}

		return false;
	}

	//
	//  todo: cschmidt: comment
	//

	this.Enable = function()
	{
		var lon,
			lat;

		for (var i=0, n=node_attractions.length; i<n; ++i)
		{
			if (node_attractions.options[i].selected == true)
			{
				lon = parseFloat(node_attractions.options[i].getAttribute('geo_longitude'));
				lat = parseFloat(node_attractions.options[i].getAttribute('geo_latitude'));
				break;
			}
		}

		// we reload the search-result-list only, when we have
		// the distance and the geo_longitude and latidute
		if((lon!='') && (lat!=''))
		{
			APP.PRICE.MAP.SetCenter({
			          'id': 0,
			       'class': 'center',
			    'position': 'default',
			     'display': 'marker',
			    'latitude': lat,
			   'longitude': lon
			});

			this.SetProperties(node_distance_limit.value, node_attractions.value, lon, lat, '1');

			APP.PRICE.REGION.Start();
		}
	}

	//
	//  todo: cschmidt: comment
	//

	this.Disable = function()
	{
		this.SetProperties('', '', '', '', '0');
		APP.PRICE.REGION.Start();
	}

	//
	//
	//

	this.SetProperties = function(geo_distance_limit, geo_distance_item, geo_longitude, geo_latitude, geo_use_distance)
	{
		APP.SNAPSHOT.Request('geo_distance_limit', geo_distance_limit);
		APP.SNAPSHOT.Request('geo_distance_item',  geo_distance_item);
		APP.SNAPSHOT.Request('geo_code::longitude',geo_longitude);
		APP.SNAPSHOT.Request('geo_code::latitude', geo_latitude);
		APP.SNAPSHOT.Request('offset',             '0');
		APP.SNAPSHOT.Request('geo_use_distance',   geo_use_distance);

		this.SetAttraction();
	}

	//
	//
	//

	this.Init = function()
	{
		node_distance_limit   = $('js_input_price_geo_distance_limit');
		node_attractions      = document.forms['distance_search'] && document.forms['distance_search']['js_geo_distance_item'] ? document.forms['distance_search']['js_geo_distance_item'] : null;
		node_tooltipp         = $('js_slider_tooltipp_geo_distance_limit');
		node_distance_unit    = $('js_distance_unit');
		node_selection		  = $('js_price_slider_selection');

		if(node_distance_limit.isElement())
		{
			APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.Init('geo_distance_limit');
			APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.SetValueCount(40);
			APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.SetValue(0,   20000);
			APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.SetPriceValue(node_distance_limit.value);
			APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.StickToPosition();
			APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.SetEvents(function(){APP.PRICE.REGION.FILTER.ATTRACTION.UpdateSelectionView();}, function(){APP.PRICE.REGION.FILTER.ATTRACTION.SliderOnfinish();});
		}
	}

	//
	//
	//

	this.SetCityCenter = function()
	{
		if(node_attractions)
		{
			this.SetProperties(node_distance_limit.value, node_attractions.value, parseFloat(node_attractions.options[0].getAttribute('longitude')), parseFloat(node_attractions.options[0].getAttribute('latitude')), '1');
		}
	}

	//
	//
	//

	this.SetAttraction = function()
	{
		if (node_attractions)
		{
			var ind = -1,
				count = node_attractions.length,
				form = document.forms['distance_search'],
				address = '' + APP.SNAPSHOT.Get('geo_address_string');

			if (	address != 'null' &&
					address.length > 0	)
			{
				(!geo_address_focus) && (form['geo_address_string'].value = address);
				for (var i=0, n=document.forms['distance_search'].length; i<n; i++)
				{
					if	(
							document.forms['distance_search'][i].getAttribute('geo_latitude') == APP.SNAPSHOT.Get('geo_code::latitude') &&
							document.forms['distance_search'][i].getAttribute('geo_longitude') == APP.SNAPSHOT.Get('geo_code::longitude')
						)
					{
						node_attractions.selectedIndex = i;
						break;
					}
				}
			}
			else
			{
				var item = APP.SNAPSHOT.Get('geo_distance_item'),
				    lng = APP.SNAPSHOT.Get('geo_code::longitude'),
				    lat = APP.SNAPSHOT.Get('geo_code::latitude');
				if (!geo_address_focus)
				{
					form['geo_address_string'].value = 'DirecciÃ³n';
				}
				if (parseInt(item))
				{
					for (var i=0; i<count; ++i)
					{
						if (node_attractions.options[i].value == item)
						{
							ind = i;
							break;
						}
					}
				}
				else if (	item &&
							item != '' &&
							parseFloat(lng) &&
							parseFloat(lat)	)
				{
					if ($('searchmap_dynamic_center').isElement())
					{
						var o = $('searchmap_dynamic_center');
					}
					else
					{
						var o = new Option('{'+lat+', '+lng+'}', 'distance', false, true);
						o.setAttribute('id', 'searchmap_dynamic_center');
						document.forms['distance_search']['js_geo_distance_item'].options[document.forms['distance_search']['js_geo_distance_item'].options.length] = o;
					}
					o.setAttribute('geo_latitude', lat);
					o.setAttribute('geo_longitude', lng);
					$('searchmap_dynamic_center').value = $('searchmap_dynamic_center').text = item;
					ind = form['js_geo_distance_item'].options.length-1;
				}
				(!geo_address_focus) && (node_attractions.selectedIndex = (ind < 0)? 0 : ind);
			}
		}
	}

	//
	//
	//

	this.SetGeoDistanceLimit = function(value)
	{
		if(node_distance_limit)
		{
			node_distance_limit.value = value;
		}
	}

	//
	//
	//

	this.SetPreviewText = function()
	{
		var min_value = APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.GetMinValue() / 1000,
			def_value = APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.GetValue() / 1000;

		node_tooltipp.innerHTML = min_value + ' - ' + def_value + ' ' + APP.PRICE.STRINGS.Get('distance_unit' + (def_value==1?'_single':'_plural'));
	}

	//
	//
	//

	this.SetResponseDistance = function(distance)
	{
		if(
			distance &&
			node_distance_limit &&
			node_distance_limit.isElement() &&
			!APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.GetUserChanged()
		  )
		{
			APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.SetPriceValue(distance);
			APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.StickToPosition();
		}
	}

	//
	//
	//

	this.SliderOnfinish = function()
	{
		this.UpdateSelectionView();
		APP.PRICE.MAP.SetDistanceChange(true);
		APP.PRICE.MAP.Search(true);
	}

	//
	//
	//

	this.UpdateSelectionView = function()
	{
		var distance = Math.round((APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.GetValue() / 1000) * 10) / 10;
		return $('js_price_slider_selection').innerHTML = distance + ' ' + APP.PRICE.STRINGS.Get('distance_unit' + (distance==1?'_single':'_plural'));
	}

	//
	//
	//

	this.SetGeoAddressFocus = function(val)
	{
		var node = $(document.forms['distance_search']['geo_address_string']);
		if (val)
		{
			if (node.value == node.getAttribute('default'))
			{
				node.value = '';
			}

			node.delClass('gray');
		}
		else
		{
			if(node.value == '')
			{
				node.value = node.getAttribute('default');
			}
		}

		if (node.value == '' || node.value == node.getAttribute('default'))
		{
			if (node.value == node.getAttribute('default'))
			{
				node.addClass('gray');
			}

			$('js_reset_geo_address_string').addClass('reset');
			$('js_reset_geo_address_string').delClass('loupe');
		}
		else
		{
			$('js_reset_geo_address_string').delClass('reset');
			$('js_reset_geo_address_string').addClass('loupe');
		}

		geo_address_focus = val;
	}

	//
	//
	//

	this.Clear = function()
	{
		this.SetGeoAddressFocus(false);
		APP.PRICE.MAP.SetDistanceChange(true);
		APP.PRICE.MAP.Search(true);
	}

	this.SetActive = function(status)
	{
		active = status
	}

	//
	// private vars
	//

	var node_distance_limit,
		node_attractions,
		node_tooltipp,
		node_distance_unit,
		node_selection,
		active = false,

		geo_address_focus = false,

		default_distance_limit = 5000;
};

APP.PRICE.REGION.FILTER.PRICE = new function()
{
	//
	//
	//

	this.Init = function(currency_for_price)
	{
		node_price = $('input_price');
		node_price_preview_min = $('js_preview_price_min');
		node_price_preview_max = $('js_preview_price_max');
		node_price_preview_selection = $('js_preview_price_selection');
		node_tooltipp          = $('js_slider_tooltipp_price_max');
		node_price_currency    = $('price_currency');
		currency_code    = node_price_currency.innerHTML;
		this.currency_before_price = currency_for_price;

		if (node_price_preview_min.isElement())
		{
			APP.PRICE.REGION.FILTER.SLIDER.PRICE.Init('price_max');
		}
	}

	//
	//
	//

	this.SetMaxDisplayedPrice = function(val)
	{
		max_displayed_price = val;
	}

	//
	//
	//

	this.SetValue = function(price_min, price_max)
	{
		if (node_price_preview_min.isElement())
		{
			if (price_max > max_displayed_price)
			{
				price_max = max_displayed_price;
			}

			APP.PRICE.REGION.FILTER.SLIDER.PRICE.SetValue(price_min, price_max);

			this.SetPreviewPrice();
		}
	}
	
	//
	//
	//

	this.Reset = function()
	{
		this.SetPriceValue(APP.PRICE.REGION.FILTER.SLIDER.PRICE.GetMaxValue());
		this.StartRequest();
	}

	//
	//
	//

	this.LockAutoChangePrice = function()
	{
		APP.PRICE.REGION.FILTER.SLIDER.PRICE.LockAutoChangePrice();
	}

	//
	// Start request for price slider
	//

	this.StartRequest = function()
	{
		APP.PRICE.REGION.FILTER.SLIDER.PRICE.UpdateSliderStatus(false);
		var value     = APP.PRICE.REGION.FILTER.SLIDER.PRICE.GetValue();
		var use_price = value == APP.PRICE.REGION.FILTER.SLIDER.PRICE.GetMaxValue() ? false : true;

		this.SetPreviewPrice();

		APP.PRICE.REGION.FILTER.INCLUDEALL.SetIncludeAll(true);

		APP.SNAPSHOT.Request('price_max',   use_price ? value : '0');
		APP.SNAPSHOT.Request('include_all', 0);
		APP.SNAPSHOT.Request('offset',      0);
		APP.PRICE.REGION.Start(0,0,0);
	}

	//
	//
	//

	this.SetPriceValue = function(val)
	{
		if (val && node_price_preview_min.isElement())
		{
			APP.PRICE.REGION.FILTER.SLIDER.PRICE.SetPriceValue(val);
			APP.PRICE.REGION.FILTER.SLIDER.PRICE.UpdateSliderStatus(true);
			APP.PRICE.REGION.FILTER.SLIDER.PRICE.StickToPosition();
		}
	}

	//
	//
	//

	this.SetPreviewPrice = function()
	{
		if (node_price_preview_min.isElement())
		{
			var max_value = parseInt(APP.PRICE.REGION.FILTER.SLIDER.PRICE.GetMaxValue()),
				min_value = APP.PRICE.REGION.FILTER.SLIDER.PRICE.GetMinValue(),
				price_selection = parseInt(APP.PRICE.REGION.FILTER.SLIDER.PRICE.GetValue());
			if (price_selection>max_value)
			{
				max_value = price_selection;
			}
			
			if (cache_prices['max']!=max_value || cache_prices['selection']!=price_selection || cache_prices['min']!=min_value)
			{
				cache_prices['max'] = max_value;
				cache_prices['selection'] = price_selection;
				cache_prices['min'] = min_value;
				
				node_price_preview_min.innerHTML = this.getCurrencyFormat(min_value);
				node_price_preview_max.innerHTML = this.getCurrencyFormat(max_value);
				node_price_preview_selection.innerHTML = APP.PRICE.STRINGS.Get("max") + " " + this.getCurrencyFormat(price_selection);
			}
		}
	}

	//
	//
	//

	this.SetHoverPreviewPrice = function()
	{
		node_price_preview_selection.innerHTML = APP.PRICE.STRINGS.Get("max") + " " + this.getCurrencyFormat(APP.PRICE.REGION.FILTER.SLIDER.PRICE.GetValue());
	}
	
	//
	//
	//
	
	this.getCurrencyFormat = function(price)
	{
		price = APP.HELPER.numberFormat(price);
		var retval = '';

		if (this.currency_before_price)
		{
			return currency_code + price;
		}
		else
		{
			return price + currency_code;
		}
	}
	
	//
	//
	//
	
	this.Clear = function()
	{
		node_price.value='';
	}

	//
	//
	//

	var node_price_preview_min,
		node_price_preview_max,
		node_price_preview_selection,
		node_tooltipp,
		node_price_currency,
		node_price,
		
		cache_prices = [],

		max_displayed_price,
		
		currency_before_price = false,
		currency_code = '';
}

APP.PRICE.REGION.FILTER.TOP_OPTION = new function()
{
	//
	//
	//

	this.Init = function()
	{
		for (var i=0, n=disp_fields.length; i<n; i++)
		{
			node_checkboxes[disp_fields[i]] = $('js_top_option_'+disp_fields[i]+'_check');
			node_categories[disp_fields[i]] = $('js_top_option_'+disp_fields[i]);
		}
	}

	//
	//
	//

	this.Set = function(filter_fields)
	{
		var do_available_search = APP.SNAPSHOT.Get('do_available_search'),
			fields = APP.SNAPSHOT.Get('fields');

		if (fields==null)
		{
			fields = [];
		}
		
		for (var i=0,n=filter_fields.length; i<n; i++)
		{
			if (filter_fields[i].id != 1) // no hotel-chain
			{
				for (var j=0,m=filter_fields[i].c.length; j<m; j++)
				{
					var field = filter_fields[i].c[j];
					if (
						field.f == '254' ||
						field.f == '60' ||
						field.f == '231' ||
						field.f == '220' ||
						field.f == '347'
						)
					{
						var status = '';
						if (fields[field.f])
						{
							status = 'active';
						}
						else if (field.c>0||!do_available_search)
						{
							status = 'inactive';
						}
						else
						{
							status = 'disabled';
						}
						
						node_categories[field.f].className = "round_borders top_optionen top_option"+field.f+"_"+status;
						node_checkboxes[field.f].setAttribute('status', status);
						node_checkboxes[field.f].checked = (status == 'active') ? true : false;
					}
				}
			}
		}
	}
	
	//
	//
	//

	this.OnClick = function(field_id)
	{
		if (node_checkboxes[field_id].getAttribute('status') == 'disabled')
		{
			return;
		}	
		else if (APP.SNAPSHOT.Get('do_available_search') == null)
		{
			if(++loading_try <= 20)
			{
				window.setTimeout(function(){
						APP.PRICE.REGION.FILTER.TOP_OPTION.OnClick(field_id);
					}, 100);
			}
			return;
		}
		
		var node_field = $('f_'+field_id);

		var fields = APP.SNAPSHOT.Get('fields');
		if(fields == null)
		{
			fields = {};
		}
		
		node_field.checked = !node_field.checked;
		fields[field_id] = node_checkboxes[field_id].checked?1:0;
		APP.SNAPSHOT.Request('fields', fields);
		APP.SNAPSHOT.Request('offset', 0);
		APP.PRICE.REGION.Start();
	}
	
	//
	//
	//
	
	var loading_try = 0,
		node_checkboxes = [],
		node_categories = [],
		disp_fields = new Array(254,60,231,220,347);
}
APP.PRICE.REGION.FILTER.RATING = new function()
{
	//
	//
	//
	
	this.Init = function()
	{
		for(var i=0; i<=4; i++)
		{
			node_checkboxes[i] = $('js_rating_'+i+'_check');
			node_ranges[i] = $('js_rating_range_'+i);
		}
	}

	//
	//
	//
	
	this.Set = function(stats_overall_liking)
	{
		var rating = APP.SNAPSHOT.Get('overall_liking'),
			do_available_search = APP.SNAPSHOT.Get('do_available_search'),
			rating2enabled = [],
			status = '';

		if (rating == null)
		{
			rating = [0,1,2,3,4];
		}

		for (var i=0, n=rating.length; i < n; i++)
		{
			rating2enabled[ rating[i] ] = true;
		}

		for (var i=0; i<=4; i++)
		{
			status = ((typeof rating2enabled[i]) == 'undefined') ? 'inactive' : 'active';
			node_ranges[i].className = 'round_borders top_rating rating'+i+'_'+status;
			node_checkboxes[i].setAttribute('status', status);
			node_checkboxes[i].checked = (status == 'active');
		}
	}
	
	//
	//
	//
	
	this.OnClick = function(no)
	{
		if (node_checkboxes[no].getAttribute('status') == 'disabled')
		{
			return;
		}

		if (APP.SNAPSHOT.Get('do_available_search') == null)
		{
			if(++loading_try <= 20)
			{
				window.setTimeout(function(){
						APP.PRICE.REGION.FILTER.RATING.OnClick(no);
					}, 100);
			}
			return;
		}

		var rating = APP.SNAPSHOT.Get('overall_liking');
		if (!rating)
		{
			rating = new Array();
			for(var i=0; i<=5; i++)
			{
				rating.push(i);
			}
		}

		if (	node_checkboxes[no].checked ||
				(rating.length == 5 && first_load == true)	)
		{
			if (rating.length == 5)
			{
				rating = new Array();
			}
		
			var found = false;
			for(var i=0; i < rating.length; i++)
			{
				if (no==rating[i])
				{
					found = true;
					break;
				}
			}
			if (!found)
			{
				rating.push(no);
			}
			
			first_load = false;
		}
		else
		{
			var newRating = new Array();
			for(var i=0, n=rating.length; i < n; i++)
			{
				if (no!=rating[i])
				{
					newRating.push(rating[i]);
				}
			}
			rating = newRating;
			
			if (rating.length == 0)
			{
				first_load = true;
			}
			else
			{
				first_load = false;
			}
		}

		APP.SNAPSHOT.Request('overall_liking', (rating.length==0 ? '' : rating));
		APP.SNAPSHOT.Request('offset', 0);
		APP.PRICE.REGION.Start();
	}
	
	//
	//
	//
	
	this.GetRange = function(i)
	{
		return node_ranges[i].firstChild.innerHTML;
	}

	//
	//
	//
	
	this.Clear = function()
	{
		APP.SNAPSHOT.Request('overall_liking', [0,1,2,3,4]);
		APP.SNAPSHOT.Request('offset', 0);
		APP.PRICE.REGION.Start();
	}
	
	//
	// private vars
	//
	
	var loading_try = 0,
		node_checkboxes = [],
		node_ranges = [],
		first_load = true;
}
APP.PRICE.REGION.FILTER.RESET = new function()
{
	var no,
		disp = false,
		count_active_filter = 0,
		mode='auto';
	
	//
	//
	//
	
	this.Update = function(response)
	{
		var snap 	= APP.SNAPSHOT.Get(),
			str		= '',
			var_name,
			field,
			price_string	= '',
			geo_title		= '';
			
		count_active_filter = 0;

		if (response)
		{
			$('js_count_visible').innerHTML = response.count;
			if (response.stats)
			{
				$('js_count_total').innerHTML = response.stats.count_total;
			}
		}

		no = 0;
		
		if (snap['do_available_search'] && snap['include_all']!=1)
		{
			price_string = APP.PRICE.STRINGS.Get('price_filter_include_all') + '';
			str += this.getSingleDesign("APP.PRICE.REGION.FILTER.INCLUDEALL.Set(false);", price_string);
			++count_active_filter;
		}
		if (snap['price_max']>0)
		{
			price_string = APP.PRICE.STRINGS.Get('price_filter_price_max') + '';
			str += this.getSingleDesign("APP.PRICE.REGION.FILTER.PRICE.Reset();", price_string.split('$value').join(APP.PRICE.REGION.FILTER.PRICE.getCurrencyFormat(snap['price_max'])));
			++count_active_filter;
		}
		if (snap['category'].length != 6)
		{
			price_string = APP.PRICE.STRINGS.Get('price_filter_category') + '';
			str += this.getSingleDesign("APP.PRICE.REGION.FILTER.STARS.Clear();", price_string.split('$value').join(snap['category'].sort().join(',')));
			++count_active_filter;
		}
		if (snap['overall_liking'].length != 5)
		{
			price_string = APP.PRICE.STRINGS.Get('price_filter_overall_liking') + '';
			var format = [];
			snap['overall_liking'].sort();
			for(var i=0, n=snap['overall_liking'].length; i<n; i++)
			{
				var k = i;
				for (var j=1; j<n-i; j++)
				{
					if ((parseInt(snap['overall_liking'][i])+j) != parseInt(snap['overall_liking'][i+j]))
					{
						break;
					}
					else
					{
						k=i+j;
					}
				}
				var value1 = APP.PRICE.REGION.FILTER.RATING.GetRange(snap['overall_liking'][i]).toLowerCase().split('<br>');
				var value2 = APP.PRICE.REGION.FILTER.RATING.GetRange(snap['overall_liking'][k]).toLowerCase().split('<br>');
				
				format.push(value1[0]+"-"+value2[1]);
				i = k;
			}
			str += this.getSingleDesign("APP.PRICE.REGION.FILTER.RATING.Clear();", price_string.split('$value').join(format.join(',')));
			++count_active_filter;
		}
		if (snap['geo_use_distance']==1)
		{
			if (snap['geo_address_string'])
			{
				geo_title = snap['geo_address_string'];
			}
			else if($('js_geo_distance_item'))
			{
				geo_title = $('js_geo_distance_item').options[$('js_geo_distance_item').selectedIndex].innerHTML; 
			}
			else
			{
				geo_title = '';
			}
		
			if (geo_title == '')
			{
				price_string = APP.PRICE.STRINGS.Get('price_filter_distance_limit');
			}
			else
			{
				price_string = APP.PRICE.STRINGS.Get('price_filter_distance_address_limit');
				price_string = price_string.split('$location').join(geo_title);
			}

			str += this.getSingleDesign("APP.PRICE.REGION.FILTER.CITYSEARCH.SetCitySearch();", price_string.split('$value').join(APP.PRICE.REGION.FILTER.ATTRACTION.UpdateSelectionView()));
			++count_active_filter;
		}
		if (snap['search_string']!='' && snap['search_string']!=null)
		{
			price_string = APP.PRICE.STRINGS.Get('price_filter_search_string') + '';
			str += this.getSingleDesign("APP.PRICE.REGION.FILTER.QUERYSTRING.Clear(true);", price_string.split('$value').join(snap['search_string']));
			++count_active_filter;
		}
		if (snap['partner_filter'])
		{
		    var blocked=APP.PRICE.REGION.FILTER.PARTNER.GetBlockedPartner();
			if (blocked.length>0)
			{
				if (blocked.length==1)
				{
					price_string = APP.PRICE.STRINGS.Get('price_filter_partner1') + '';
				}
				else
				{
					price_string = APP.PRICE.STRINGS.Get('price_filter_partner2') + '';
				}
				str += this.getSingleDesign("APP.PRICE.REGION.FILTER.PARTNER.Reset();", price_string.split('$value').join(APP.PRICE.STRINGS.Get('partner_'+blocked)));
				++count_active_filter;
			}
		}
		if (snap['fields'])
		{
			var filter_exists = false;
			for (field in snap['fields'])
			{
				if (snap['fields'][field])
				{
					var string = APP.PRICE.STRINGS.Get('field_'+field);
					if (field==1)
					{
						string += ": "+APP.PRICE.STRINGS.Get('value_label_1_'+snap['fields'][field]);
					}
					str += this.getSingleDesign("$('f_"+field+"').checked=false;APP.PRICE.REGION.FILTER.FIELDS.Click('f_"+field+"', $('f_"+field+"'), '"+field+"');", string);
					filter_exists = true;
				}
			}
			if (filter_exists)
			{
				++count_active_filter;
			}
		}
		
		if (!APP.PRICE.REGION.TOP_NAV.isDefaultSortOrder())
		{
			var order_by = snap['order_by'].split(' ');
			var string_name = 'sort_'+order_by[0],
				name = '',
				node_attractions = document.forms['distance_search'] && document.forms['distance_search']['js_geo_distance_item'] ? document.forms['distance_search']['js_geo_distance_item'] : null;
			str += "<strong>"+APP.PRICE.STRINGS.Get('sort_by')+"</strong>";
			if (order_by[0] == 'distance')
			{
				if (snap['geo_address_string'])
				{
					string_name += "_address";
					name = snap['geo_address_string'];
				}
				else if(node_attractions && node_attractions.selectedIndex == 0)
				{
					string_name += "_city_center";
				}
				else if (node_attractions)
				{
					string_name += "_item";
					name = node_attractions.options[node_attractions.selectedIndex].firstChild.nodeValue;
				}
			}
			str += "<div class=\"sprite_icon_list sortorder\">"+APP.PRICE.STRINGS.Get(string_name).split('$name').join(name)+"&nbsp;("+APP.PRICE.STRINGS.Get('sort_by_'+order_by[1])+")</div>";
		}
		
		$('js_filter_reset').innerHTML = str;
		if (str == '')
		{
			$('js_no_filter_is_selected').appear();
			$('js_filter_reset').disappear();
			$('js_filter_reset_all').disappear();
		}
		else
		{
			$('js_no_filter_is_selected').disappear();
			$('js_filter_reset').appear();
			this.DispResetLink();
		}
	}
	
	//
	//
	//
	
	this.getSingleDesign = function(func, string)
	{
		return "<div onclick=\""+func+"\" title=\""+ APP.PRICE.STRINGS.Get('disable_filter')+"\" class=\"sprite_icon_list row"+(no++%2==1?1:0)+"\">"+string+"</div>";
	}
	
	//
	//
	//
	
	this.DispResetLink = function()
	{
		try
		{
			if (count_active_filter>1 && APP.PRICE.REGION.PROGESSBAR.GetAllLoadedPartners(APP.PRICE.REGION.GetResponse().standby).length==0)
			{
				$('js_filter_reset_all').appear();
			}
		}catch(e){}
	}
	
	//
	//
	//
	
	this.Open = function()
	{
		$('js_filter_list').appear();
		$('js_filter_stats').addClass('filter_stats_active');
		$('search_order_by').addClass('active');
		
		var node = APP.SNAPSHOT.Get('view_type')==0 ? $('js_filter_details') : $('js_filter_list');
		
		node.appear();
		var height = node.getHeight();
		node.style.height='0px';
		$('reset_filter').className='module';
		new APP.EFFECT.SlideDown(node,{scaleY:true,'target_size':height,
							'onfinish':function(){
								node.style.height='';
							}});
		this.DispResetLink();
		disp = true;
	}
	
	//
	//
	//

	this.Close = function(automatic)
	{
		if ((automatic  && mode=='auto') || (mode=='manual'))
		{
			
			var node = APP.SNAPSHOT.Get('view_type')==0 ? $('js_filter_details') : $('js_filter_list');
			new APP.EFFECT.SlideUp(
								   node,
								   {
									   scaleY: true,
									   'target_size': 0,
									   'onfinish': function()
								       {
							   				node.disappear();
							   				$('js_filter_list').disappear();
							   				node.style.height='';
							   				$('reset_filter').className='module close_filter';
								   			$('js_filter_stats').delClass('filter_stats_active');
								   			$('search_order_by').delClass('active');
								   		}});
			$('js_filter_reset_all').disappear();
			disp = false;
		}
	}
	
	//
	//
	//
	
	this.GetDisp = function()
	{
		return disp;
	}
	
	//
	//
	//
	
	this.Toggle = function()
	{
		mode='manual';
		if (!disp)
		{
			this.Open();
		}
		else
		{
			this.Close(false);
		}
	}
	
	//
	//
	//

	this.ResetAll = function()
	{
		var snap = APP.SNAPSHOT.Get();
		
		APP.PRICE.REGION.SetDisableStart(true);

		if (snap['include_all']!=1)
		{
			APP.PRICE.REGION.FILTER.INCLUDEALL.Set(false);
		}
		if (snap['price_max']>0)
		{
			APP.PRICE.REGION.FILTER.PRICE.Reset();
		}
		if (snap['category'].length != 6)
		{
			APP.PRICE.REGION.FILTER.STARS.Clear();
		}
		if (snap['overall_liking'].length != 5)
		{
			APP.PRICE.REGION.FILTER.RATING.Clear();
		}
		if (snap['geo_distance_limit']&&snap['geo_use_distance']==1)
		{
			APP.PRICE.REGION.FILTER.CITYSEARCH.SetCitySearch();
		}
		if (snap['search_string']!='' && snap['search_string']!=null)
		{
			APP.PRICE.REGION.FILTER.QUERYSTRING.Clear(true);
		}
		if (snap['partner_filter'])
		{
			APP.PRICE.REGION.FILTER.PARTNER.Reset();
		}
		if (snap['fields'])
		{
			for (field in snap['fields'])
			{
				if (snap['fields'][field])
				{
					$('f_'+field).checked=false;
					APP.PRICE.REGION.FILTER.FIELDS.Click('f_'+field, $('f_'+field), field);
				}
			}
		}
		
		APP.PRICE.REGION.SetDisableStart(false);
		APP.PRICE.REGION.Start();
	}

}

APP.PRICE.REGION.FILTER.INCLUDEALL = new function()
{
	//
	//
	//

	this.Init = function()
	{
		node = $('include_all_test');
	}

	//
	//  display in the price-search only available hotels or
	//  non-available too?
	//  we use this function only in the the price-search-mode
	//  and not in the non-available-mode
	//

	this.Set = function(is_checked)
	{
		if (!is_checked)
		{
			APP.PRICE.REGION.FILTER.PRICE.Clear();
			APP.SNAPSHOT.Request('input_price', '');
		}
		APP.SNAPSHOT.Request('include_all', is_checked ? '0' : '1');
		APP.SNAPSHOT.Request('offset', 0);
		APP.SNAPSHOT.Request('do_available_search', 1);

		APP.PRICE.REGION.Start();
	}

	//
	//
	//

	this.SetIncludeAll = function(enabled)
	{
		node.checked = enabled;
		$(node.parentNode).setClass('checkbox'+(enabled?'_active':''));
	}

	//
	//
	//

	var node;
}

APP.PRICE.REGION.FILTER.CITYSEARCH = new function()
{
	//
	//
	//
	
	this.SetCitySearch = function()
	{
		this.SwitchSearch(false);
	}
	
	//
	//
	//

	this.SetCatchmentAreaSearch = function()
	{
		this.SwitchSearch(true);
	}

	//
	//  switch from the the city-search to the distance-search (used only in the error-situation)
	//  @param state 1 is city-search, 0 is geocode-search
	//  @param setValue default geocode-max-distance-search (unit: meter)
	//

	this.SwitchSearch = function(state)
	{
		//page loaded?
		if (APP.SNAPSHOT.Get('do_available_search') == null)
		{
			if (++loading_try <= 20)
			{
				window.setTimeout(function(){
						APP.PRICE.REGION.FILTER.CITYSEARCH.SwitchSearch(state);
					}, 100);
			}
			return;
		}

		APP.PRICE.REGION.FILTER.ATTRACTION.SetCityCenter();
		APP.PRICE.REGION.FILTER.ATTRACTION.SetGeoDistanceLimit(max_distance);
		APP.PRICE.REGION.FILTER.ATTRACTION.UpdateSelectionView();
	
		if (!state)
		{
			APP.PRICE.REGION.FILTER.ATTRACTION.Disable();
		}
		else
		{
			//select first attraction
			$("attraction").selectedIndex = 0;

			//use filter
			APP.PRICE.REGION.FILTER.ATTRACTION.Enable();
		}
	}

	//
	//
	//

	var node,
		max_distance = 20000,
		loading_try = 0;
}
APP.PRICE.REGION.FILTER.PARTNER = new function()
{
	//
	//  init object
	//
	
	this.Init = function()
	{
		node = $('js_partner_banner');
	}
	
	//
	//  hide partner-slider     @todo: unbenennen
	//
	
	this.Hide = function()
	{
		if(array_partners_blocked.length == 0 && cache)
		{
			node.innerHTML = this.GetHtml(cache, user_conf_display_mode);
			
			//fix labels for ipads/iphone/ipod
			APP.LABELS.fix(node);
		}
	}

	var cache;//@todo: wirklich brauchen?
	
	//
	//  display the partner-slider
	//

	this.Show = function(pdata, servicestatus)
	{
		// We display the partner-box only, than we user do not break the loading-process
		if(pdata.length==0)
		{
			this.Hide();
		}
		else
		{
			cache = pdata;
			this.SetPartner(pdata);
		  	node.innerHTML = this.GetHtml(pdata, user_conf_display_mode);
	  	
			node.appear();
			
			//fix labels for ipads/iphone/ipod
			APP.LABELS.fix(node);
		}
	}

	//
	// create our partner-list
	//
	
	this.GetHtml = function(pdata, state_complete)
	{
		var retval = '',
			count  = pdata.length,
			partner,
			id,
			onclick;

		if(count > 0)
		{
			var attribs = [];
			attribs['onclick'] = "APP.PRICE.REGION.FILTER.PARTNER.SelectAllPartners();";
			var is_checked = array_partners_blocked.length==0;
		
		
		
			retval += '<div class="group_headline bigtext">' + APP.PRICE.STRINGS.Get('deals_partner') + '</div>'
					+ '<div class="navigation_space">'
					+ '<ul id="js_partner_list">'
			
					+ '<li id="js_enable_all_partners"'+(state_complete? ' style="display:none;"' : '')+'>'
					+ APP.PRICE.REGION.DESIGN.getCheckbox('', 'js_select_all_partners', is_checked, false, attribs)
					+ '<label class="item" for="js_select_all_partners">'+APP.PRICE.STRINGS.Get('all_notices')+'</label>'
					+ '</li>';

			var str_hotels    = APP.PRICE.STRINGS.Get('hotels'),
				str_no_answer = APP.PRICE.STRINGS.Get('partner_no_answer'),
				str_loading   = APP.PRICE.STRINGS.Get('partner_loading');

			for(var i=0; i<count; i++)
			{
				partner = pdata[i];
				onclick = 'APP.PRICE.REGION.FILTER.PARTNER.DeactivitatePartner(' + partner.i + ', this.checked)';
				
				var attribs = [];
				attribs['onclick'] = onclick;
				attribs['partner'] = partner.i;
				var is_checked = !this.IsBlockedPartner(partner.i);
				var is_disabled = partner.c==0;
			
				
				id = 'js_partner_' + partner.i; 
				retval += '<li id="js_partner_li_'+partner.i+'" ' + (state_complete && i>2 ? ' style="display:none;"' : '') + '>'
						+ APP.PRICE.REGION.DESIGN.getCheckbox('', 'js_partner_'+partner.i, is_checked, is_disabled, attribs)
						+ '<label for="' + id + '"' + ((partner.s==0 && partner.c==0) ? ' class="lighttext"' : '') + '>'
						+ APP.PRICE.STRINGS.Get('partner_' + partner.i)
						+ ' <span class="lighttext">('
						
				if((partner.s==partner_state_complete) && (partner.c>0))
				{
					retval += partner.c + ' ' + str_hotels + ' - ' + partner.m;
				}
				else if(state_complete || partner.s==1 || partner.s==-1)
				{
					retval += str_no_answer;
				}
				else
				{
					retval += str_loading;
				}

				retval += ')</span>'
						+ '</label>'
						+ '</li>';
			}
			
			retval += '</ul>'
			
					+ '<em ' + (!state_complete? 'style="display:none;"' : '') + ' id="js_partnerlist_more" class="more_button" onclick="APP.PRICE.REGION.FILTER.PARTNER.AppearPartnerList();">'
					+ APP.PRICE.STRINGS.Get('more')
					+ '</em>'
					+ '<em ' + (state_complete ? 'style="display:none;"' : '') + ' id="js_partnerlist_less" class="more_button" onclick="APP.PRICE.REGION.FILTER.PARTNER.DisappearPartnerList();">'
					+ APP.PRICE.STRINGS.Get('less')
					+ '</em>'
					+ '</div>';
		}
		
		return retval;
	}
	
	//
	//
	//

	this.SelectAllPartners = function()
	{
		var status = $('js_select_all_partners').checked,
			nodes  = $('js_partner_banner').getElementsByTagName('input'),
			partner,
			node_checkbox;

		for(var i=1, n=nodes.length; i<n; i++)
		{
			node_checkbox = nodes[i];
			partner       = node_checkbox.getAttribute('partner');
			
			node_checkbox.checked = status;
			node_checkbox.parentNode.className = (status?'checkbox_active':'checkbox');
			
			if(status)
			{
				this.DeleteBlockedPartner(partner);
			}
			else
			{
				this.SetBlockedPartner(partner);
			}
		}

		APP.SNAPSHOT.Request('partner_filter', APP.PRICE.REGION.FILTER.PARTNER.GetPartner());
		APP.PRICE.REGION.Start();	
	}
	
	
	//
	//
	//

	this.Reset = function()
	{
		array_partners_blocked = [];
		APP.SNAPSHOT.Request('partner_filter', APP.PRICE.REGION.FILTER.PARTNER.GetPartner());
		APP.PRICE.REGION.Start();	
	}

	//
	//
	//

	this.AppearPartnerList = function()
	{
		var nodes = $('js_partner_list').getElementsByTagName('li');

		for(var i=0, n=nodes.length; i<n; i++)
		{
			$(nodes[i].id).appear();
		}

		$('js_partnerlist_more').disappear();
		$('js_partnerlist_less').appear();
		
		user_conf_display_mode = false;
	}

	//
	//
	//

	this.DisappearPartnerList = function(node)
	{
		var nodes = $('js_partner_list').getElementsByTagName('li');
		
		$(nodes[0].id).disappear();
		
		for(var i=4, n=nodes.length; i<n; i++)
		{
			$(nodes[i].id).disappear();
		}
		
		$('js_partnerlist_more').appear();
		$('js_partnerlist_less').disappear();
		
		user_conf_display_mode = true;
	}
	
	//
	//
	//
	
	this.DeactivitatePartner = function(partner, val)
	{
		if(!val)
		{
			this.SetBlockedPartner(partner);
		}
		else
		{
			this.DeleteBlockedPartner(partner);
		}
		
		APP.SNAPSHOT.Request('offset', '0');
		APP.SNAPSHOT.Request('partner_filter', APP.PRICE.REGION.FILTER.PARTNER.GetPartner());
		APP.PRICE.REGION.Start();	
	}
		
	//
	//
	//
	
	this.IsBlockedPartner = function(val)
	{
		var retval = false;

		for(var i=0, n=array_partners_blocked.length; i<n; i++)
		{
			if(array_partners_blocked[i] == val)
			{
				retval = true;
				break;
			}
		}
		
		return retval;
	}
	
	//
	//
	//
	
	this.SetBlockedPartner = function(val)
	{
		if(!this.IsBlockedPartner(val))
		{
			array_partners_blocked.push(val);
		}
	}
	//
	//
	//
	
	this.GetBlockedPartner = function()
	{
		return array_partners_blocked;
	}

	//
	//
	//
	
	this.SetBlockedPartnerArray = function(val)
	{
		val = (val == null) ? array_partners : val.split(',');
		array_partners_blocked = [];

		for(var i=0, n=array_partners.length; i<n; i++)
		{
			var found = false;
			for(var j=0, m=val.length; j<m; j++)
			{
				if (val[j] == array_partners[i])
				{
					found = true;
					break;
				}
			}

			if (!found)
			{
				array_partners_blocked.push(array_partners[i]);
			}
		}
	}
	
	//
	//
	//
	
	this.DeleteBlockedPartner = function(val)
	{
		var retval = [],
			count  = array_partners_blocked.length;
		
		for(var i=0; i<count; i++)
		{
			if(array_partners_blocked[i] != val)
			{
				retval.push(array_partners_blocked[i]);
			}
		}
		array_partners_blocked = retval;
	}

	//
	//
	//

	this.SetPartner = function(pdata)
	{
		array_partners = [];
		
		for(var i=0, n=pdata.length; i<n; i++)
		{
			array_partners.push(pdata[i].i);
		}
	}

	//
	//
	//

	this.GetPartner = function()
	{
		var retval                 = [],
			count_blocked_partners = array_partners_blocked.length,
			found;

		for(var i=0, n=array_partners.length; i<n; i++)
		{
			found = false;
			
			for(var j=0; j<count_blocked_partners; j++)
			{
				if(array_partners_blocked[j] == array_partners[i])
				{
					found = true;
					break;
				}
			}
			
			if(!found)
			{
				retval.push(array_partners[i]);
			}
		}
		
		return retval.join(',');
	}

	//
	// private vars..
	//

	var node,
		
		partner_state_complete = 1,
		
		max_displayed_partners = 3,
	
		//all ajax - states
		ajax_state_error      =  -1,
		ajax_state_incomplete =  0,
		ajax_state_complete   =  1,
		
		user_conf_display_mode   = true,
		
		array_partners         = [],
		array_partners_blocked = [];
};
APP.PRICE.REGION.FILTER.PAGING = new function()
{

	//
	// private vars
	//

	var node,
		step = 25,
		cache_num_pages = 0,
		cache_offset = 0;

	//
	//
	//
	
	this.Init = function()
	{
		node = $('hotellistbottom');
	}

	//
	//  hide the footer-navigation
	//
	
	this.Hide = function()
	{
		if (node && node.isElement())
		{
			node.disappear();
		}
		cache_num_pages = 0;
		cache_offset    = 0;
	}
	
	//
	// build and display the footer-navigation
	//
	
	this.Show = function()
	{
		var c = APP.PRICE.REGION.GetResultCount();
		
		if (c < 25)
		{
			this.Hide();
		}
		else
		{
			this.CreateNavigation(c, APP.SNAPSHOT.Get('offset'));
			node.appear();
		}
	}
	
	//
	// If we have only one display - site, we can break this function
	// or the cache_num_page is identically to num_pages (not changed)
	//
	
	this.GetUpdateStatus = function(num_pages, cache_num_pages, poffset)
	{
		if (	num_pages == 1 ||
				(	cache_num_pages == num_pages &&
					cache_offset == poffset	)	)
		{
			return false;
		}
		return true;
	}	
	
	//
	//
	//
	
	this.CreateNavigation = function(count, input_offset)
	{
		
		// set max num_pages, currently js ignores if user is logged in @TODO
		if (count > 500)
		{
			count     = 500;
		}
		
		var offset	  = (typeof input_offset == 'undefined' ? 0 : input_offset), 
			num_pages = Math.ceil(count/step),
			retval	  = "";
		var poffset	  = Number((offset/step)+1);

		// we must build the footer again?
		if (!this.GetUpdateStatus(num_pages, cache_num_pages, poffset))
		{
			return "";
		}
		
		var y      	 = Math.max(
                           Number(poffset - (Math.max(
				               (Number(10				                   -(num_pages-poffset))),
				               (10/2)))),
				           1);
		var upper	 = ((num_pages > 10) ? Math.min(Number(y+10),num_pages) : num_pages);
		var intStart = (upper-10 < 1 ? 1 : upper-10);
	
		if ((num_pages>1) && (poffset>1))
		{ // backward / last page button
			retval += "<em class=\"button_transition round_borders l gradient_dark_hover\" onclick=\"APP.PRICE.REGION.FILTER.PAGING.SkimPage('down'," + step + ");\">"+APP.PRICE.STRINGS.Get('paging_backward')+"</em>";
		}
	
		retval += "<div class=\"m\">";
	
		for (var x=intStart; x<=upper; x++)
		{
			if (x==poffset)
			{ // current page button
				retval += "<em class=\"button_transition round_borders gradient_bright_hover\">"+ x +"</em>";
			}
			else
			{
				retval += "<em class=\"button_transition round_borders gradient_dark_hover\" onclick=\"APP.PRICE.REGION.FILTER.PAGING.SkimPage('new'," + Number((x*step)-step) + ");\">"+ x +"</em>";
			}
		}
	
		retval += "</div>";
	
		if (poffset<num_pages)
		{ // forward / next page button
			retval += "<em class=\"button_transition round_borders r gradient_dark_hover\" onclick=\"APP.PRICE.REGION.FILTER.PAGING.SkimPage('up'," + step + ");\">"+APP.PRICE.STRINGS.Get('paging_forward')+"</em>";
		}

		cache_num_pages= num_pages;
		cache_offset   = poffset;
		node.innerHTML = retval;
	}
	
	//
	//  footer-page-navigation
	//  @param direction mode-variant (up: next-page, down: last-page, new:special subpage)
	//  @param offset the offset is the absolute offset related by direction 'new'. in the other situation is it the relative offset.
	//
	
	this.SkimPage = function(direction, offset)
	{
		var current_offset = APP.SNAPSHOT.Get('offset');
			current_offset = Number(current_offset? current_offset: 0);

		// scroll to the top of the page
		window.scrollTo(1, 1);
		
		node.disappear();
		
		switch(direction)
		{
			case   'up': 
					APP.SNAPSHOT.Request('offset', current_offset + Number(offset));
					break;
					
			case 'down':
					APP.SNAPSHOT.Request('offset', current_offset - Number(offset));
					break;
					
			case  'new':
					APP.SNAPSHOT.Request('offset', offset);
		}
		
		APP.PRICE.REGION.Start();
	}

};APP.PRICE.REGION.FILTER_CITYLIST = new function()
{
	//
	// init path-list
	//

	this.Init = function()
	{
		node = $('top_childs');
		node_new = $('js_top_childs');
	}

	//
	// hide the path-list
	//
	
	this.Hide = function()
	{
		node.disappear();
	}

	//
	// display the path-list
	//

	this.Show = function()
	{
		node.appear();
	}

	//
	// set the path-list
	//

	this.Set = function(list, hdl)
	{
		// empty list?
		if (!list || list.length==0)
		{
			return;
		}
		this.CreateHtml(list, hdl);
	}
	
	//
	//
	//
	
	this.CreateHtml = function(list, hdl)
	{
		var html = "<h2 class=\"city\">"+hdl+"</h2>\n"
				 + '<ul class=\"list\">';
		for (var i=0, n=list.length; i<n; i++)
		{
			html += "<li class=\""+(Math.floor(i/2)%2==0?"":"highlight")+"\">"
				 + "<input onclick=\"APP.PRICE.REGION.FILTER_CITYLIST.DisplaySelectedChildrenPaths();\" class=\"checkbox\" id=\"children_path_"+i+"\" path_id=\""+list[i].id+"\" type=\"checkbox\""
				 + (list[i].searched ? " checked=\"checked\"" : "")+" />"
				 +  "<em";
				 
			if (list[i].searched)
			{
				html += " class=\"enable\" onclick=\"window.location.href=APP.PRICE.REGION.FILTER_CITYLIST.GetLink('"+list[i].id+"');return false;\" ";
			}
			else
			{
				html += " class=\"disable\" onclick=\"$('children_path_"+i+"').checked=true;APP.PRICE.REGION.FILTER_CITYLIST.DisplaySelectedChildrenPaths();\" ";
			}
			html += "> "
				 + "<span>"
				 + list[i].name
				 + "</span>"
				 + "&nbsp;("+list[i].count+' '+APP.PRICE.STRINGS.Get('hotels')+")"
				 + "</em>"
				 + "</li>\n";
		}
		html += "</ul>\n"
			 +	"<div class=\"clear\"><!-- --></div>";
		
		if (html != cache)
		{
			cache = html;
			node.innerHTML = html;
		}
	}

	//
	//  baby-lb for the children-pathlist (static - variant)
	//

	this.GetLink = function(path_id)
	{
		return "/region.php?pagetype=hotels&" + APP.SNAPSHOT.GetQuery(true) + "&path=" + path_id;
	}

	//
	//  we display in the region-price-search (available-mode) the sub-path-list.
	//  the user can activitate more citys or disable citys.
	//  maybe the user can activitate on city, but we do not have this city in the city-list. 
	//  @param additional_path path-id from the separate city
	//

	this.DisplaySelectedChildrenPaths = function(additional_path)
	{
		//add non-filter pathlist
		var path_list = (additional_path ? additional_path : ''), 
			node, 
			i;

		//add filter pathlist
		for(i=0; i<30; i++)
		{
			node = $('children_path_' + i);
			if(node.isElement())
			{
				if(node.checked)
				{
					path_list += ((path_list != '') ? ',' : '') + node.getAttribute('path_id');
				}
			}
			else
			{
				break;
			}
		}

		APP.SNAPSHOT.Request('path_id_multi_avail', path_list);
		APP.SNAPSHOT.Request('offset',              0);
		APP.PRICE.REGION.Start();
	}

	//
	// private vars
	//

	var node,
		node_new,
		cache;
}

APP.PRICE.REGION.SLIDER = function(priceHandle)
{
	//
	//
	//

	this.Init = function(name)
	{
		this.SetHover(false);

		//init nodes
		node_slider        = $('js_slider_' + name);
		node_highlight     = $('js_slider_highlight_' + name);
		node_price         = $('js_slider_input_' + name);
		node_input_price   = $('js_input_price_' + name);
		node_tooltipp      = $('js_slider_tooltipp_' + name);
		node_document_main = $('document_main');

		//init events depending on devide type
		if(Browser.iPad)
		{
			event_start		= 'touchstart';
			event_move		= 'touchmove';
			event_end		= 'touchend';
		}
		else
		{
			event_start		= 'mousedown';
			event_move		= 'mousemove';
			event_end		= 'mouseup';		
		}

		init_value     = node_input_price.value;

		this.SetEnvironmentVars();
		this.EnableSlider();
	}
	
	//
	//
	//
	
	this.HideTooltipp = function()
	{
		if(tooltipp_enabled && event_onchange)
		{
			node_tooltipp.disappear();
		}
	}

	//
	//
	//
	
	this.DisplayTooltipp = function(action)
	{
		var posx,
			sliderVal,
			sliderPos,
			newvalue,
			cache_value = node_input_price.value;

		if(tooltipp_enabled && event_onchange)
		{
			node_tooltipp.appear();
		
			if(Browser.iPad)
			{
				action = action.touches[0];
			}		
		
			if (action.pageX)
			{
			    posx = action.pageX;
			}
			else if (action.clientX)
			{
				var doc = document;
			    posx = action.clientX + doc.body.scrollLeft + doc.documentElement.scrollLeft;
			}
	
			//mouse position relativ to sliderdocument_main
			sliderVal = this.GetValidatePos( posx - node_slider.getAbsLeft() );
			
			if(priceHandle == false  || this.GetMaxValue() <= hurdle)
			{
				sliderPos = (sliderwidth / value_count) * Math.round(value_count * sliderVal / sliderwidth);
				newvalue  = Math.round((sliderPos * scale + from) * Math.pow(10, 0)) / Math.pow(10, 0);
			}
			else
			{
				sliderPercent = Math.round(sliderVal * 100 / sliderwidth);
				
				newvalue = this.CalcPrice(sliderPercent);
			}
			 
			node_input_price.value = newvalue;
			
			node_tooltipp.style.left = (sliderVal+20) + "px";

			//The slider is only activited, than the old-value is different from the new-value
			if((newvalue!=finish_old_value) && (newvalue!=change_old_value))
			{
				event_onchange();
			}
			
			node_input_price.value = cache_value;
		}
	}

	//
	//
	//

	this.SetEvents=function(onchange, onfinish)
	{
		event_onchange = onchange;
		event_onfinish = onfinish;
	}

	//
	//
	//

	this.MouseDown = function(act)
	{
		if(tooltipp_enabled && event_onchange)
		{
			node_tooltipp.appear();
		}

		var itsMe = this;
		node_document_main.addEvent(event_end, 		function(){		itsMe.DeactivateSlider();	});
		node_document_main.addEvent(event_move, 	function(act){	itsMe.MoveSlider(act);		});
		node_slider.setStyle('cursor', 'pointer');
		
		this.SetHover(true);
		this.MoveSlider(act);
		this.LockAutoChangePrice();
		
		return false;
	}

	//
	//
	//

	this.SetPosition = function(act)
	{
		this.SetHover(true);
		this.MoveSlider(act);
		this.DeactivateSlider();
	}


	/**
	 * Calculate slider position from input value
	 *
	 */
	this.getPosition = function()
	{
		if(priceHandle == false  || this.GetMaxValue() <= hurdle)
		{
			var position = Math.round((node_input_price.value - from) / scale);
		}
		else
		{
			var price = parseInt(node_input_price.value);
				 
			if (price <= hurdle)
			{
				var percent = Math.round((price-from)/(hurdle-from)*hurdle_percent);
					
			}
			else
			{
				var percent = Math.round((hurdle_percent/100 + (Math.pow((price-hurdle),0.3)/Math.pow((to-hurdle),0.3))*(1-hurdle_percent/100))*100);
			}
			var position = Math.round(percent*sliderwidth/100);
		}
	
		return position;
	}

	//
	//
	//

	this.OnMouseout = function()
	{
		if(this.GetHover())
		{
			this.HideTooltipp()
			this.DeactivateSlider();
		}
	}

	//
	//
	//

	this.SetEnvironmentVars = function()
	{
		//Min/Max value
		if(this.GetMinValue())
		{
			from = parseFloat(this.GetMinValue());
		}
		if(this.GetMaxValue())
		{
			to   = parseFloat(this.GetMaxValue());
		}

		//Slider-display scale [value-change per pixel of movement].
		scale = (to - from) / sliderwidth;
		
		if (scale == 0)
		{
			scale = 1;
		}
	}

	//
	//
	//

	this.GetMaxValue = function()
	{
		return node_input_price.getAttribute('to');
	}

	//
	//
	//

	this.GetMinValue = function()
	{
		return node_input_price.getAttribute('from');
	}

	//
	//
	//

	this.GetValue = function()
	{
		if (node_input_price)
		{
			return node_input_price.value;
		}
		return null;
	}

	//
	//
	//

	this.SetValue = function(price_min, price_max)
	{
		if(price_min == price_max)
		{
			this.DisableSlider();
		}
		else
		{
			this.EnableSlider();
		}
	
		//is price_min + price_max valid?
		if (( price_max==0 ) && ( price_min==0 ))
		{
			return false;
		}

		node_input_price.setAttribute('to',   price_max);
		node_input_price.setAttribute('from', price_min);

		if((init_value==node_input_price.value) && (!lock_auto_change))
		{
			init_value = this.SetPriceValue(node_input_price.value/*price_max*/);
		}

		this.SetEnvironmentVars();
		this.StickToPosition();

	}

	//
	//
	//

	this.LockAutoChangePrice = function()
	{
		lock_auto_change = true;
	}

	//
	//
	//

	this.StickToPosition = function()
	{
		if(this.UpdateSliderStatus() == false)
		{
			return false;
		}
		
		if(!node_input_price.value)
		{
			node_input_price.value = this.GetMaxValue();
			var position = sliderwidth;
		}
		else
		{
			var position = this.getPosition();
		}

		this.GetValidatePos( position );
		this.SetPos( this.GetValidatePos( position ) );
		
	}

	//
	//
	//

	this.MoveSlider = function(action)
	{
		if(!this.GetHover())
		{
			return;
		}

		var posx,
			sliderPos,
			newvalue,
			doc = document;

		if(Browser.iPad)
		{
			action = action.touches[0];
		}

		if (action.pageX)
		{
		    posx = action.pageX;
		}
		else if (action.clientX)
		{
		    posx = action.clientX + doc.body.scrollLeft + doc.documentElement.scrollLeft;
		}

		//mouse position relativ to sliderdocument_main
		var sliderVal = this.GetValidatePos( posx - node_slider.getAbsLeft());

		this.SetPos(sliderVal);
		
		if(tooltipp_enabled)
		{
			node_tooltipp.style.left = (sliderVal+20) + "px";
		}

		if(priceHandle == false  || this.GetMaxValue() <= hurdle)
		{
			sliderPos = (sliderwidth / value_count) * Math.round(value_count * sliderVal / sliderwidth);
	
			newvalue  = Math.round((sliderPos * scale + from) * Math.pow(10, 0)) / Math.pow(10, 0);
		}
		else
		{
			sliderPercent = Math.round(sliderVal * 100 / sliderwidth);
				
			newvalue = this.CalcPrice(sliderPercent);
		}

		//The slider is only activited, than the old-value is different from the new-value
		if((newvalue!=finish_old_value) && (newvalue!=change_old_value))
		{
			node_input_price.value = newvalue;

			if(event_onchange)
			{
				event_onchange();

				change_old_value = newvalue;
			}
		}
	}

	//
	//
	//

	this.GetValidatePos = function(value)
	{
		if (value > sliderwidth)
		{
			value = sliderwidth;
		}

		if (value < 0)
		{
			value = 0;
		}

		return Math.round(value);
	}

	//
	//
	//

	this.DeactivateSlider = function()
	{
		lastvalue = (node_input_price.value) ? node_input_price.value : 0;
		APP.SNAPSHOT.Request(node_input_price.name, lastvalue);

		var itsMe = this;
		node_document_main.delEvent(event_end, 		function(){		itsMe.DeactivateSlider();	});
		node_document_main.delEvent('mouseout', 	function(){		itsMe.OnMouseout();	});
		node_document_main.delEvent(event_move, 	function(act){	itsMe.MoveSlider(act);		});
		document.delEvent(event_start, 	function(){ return false;	});
		node_slider.addEvent('mouseout',  function(){	itsMe.HideTooltipp();	});
		node_slider.setStyle('cursor', 'pointer');

		if(event_onfinish)
		{
			event_onfinish();
		}
		this.HideTooltipp();

		this.SetHover(false);
			
		state_user_changed = true;
	}

	//
	//
	//

	this.GetUserChanged = function()
	{
		return state_user_changed;
	}

	//
	//
	//

	this.SetUserChanged = function(val)
	{
		return state_user_changed = val;
	}

	//
	//
	//

	this.SetHover = function(val)
	{
		mouseover = val;
	}

	//
	//
	//

	this.SetPriceValue = function(val)
	{
		return node_input_price.value = val;
	}
	
	
	//
	//
	//
	
	this.SetCurrencyFactor = function(val)
	{
		hurdle = Math.round(hurdle*val);
	}

	//

	//

	this.GetHover = function()
	{
		return mouseover;
	}

	//
	//
	//

	this.SetPos = function(value)
	{
		var pos_left,
			width;

		node_price.style.left = (value - Math.round(node_price.getWidth() / 2)) + "px";

		if(!highligh_invert)
		{
			node_highlight.style.width = value + "px";
		}
		else
		{
			node_highlight.style.left  = (pos_left = value + 10) + "px";

			width = sliderwidth<=pos_left ? 0 : (sliderwidth - pos_left + 9);
			node_highlight.style.width = width + "px";
		}
	}

	//
	//
	//

	this.SetInvertHighlight = function(val)
	{
		highligh_invert = val;
	}


	//
	//
	//

	this.SetValueCount = function(val)
	{
		if(val > 0)
		{
			value_count = val;
		}
	}
	
	//
	//
	//
	
	this.CalcPrice = function(percent)
	{
		if (percent <= hurdle_percent)
		{
			var returnvalue = Math.round(percent * (hurdle - from) / hurdle_percent + from);
		}
		else
		{
			var returnvalue = Math.round(Math.pow((percent/100-(hurdle_percent/100))*Math.pow((to-hurdle),(3/10))/(1-(hurdle_percent/100)),(10/3))+hurdle);
		}
	
		return returnvalue;
	}

	/**
	 * disable slider
	 *
	 * @author tschulte
	 * @since 14.11.2011
	 */
	 this.DisableSlider = function()
	 {
	 	if(slider_enabled == true)
	 	{
		 	node_price.disappear();
		 	node_highlight.disappear();
		 	node_slider.setStyle('cursor', 'default');
		 		
			var itsMe = this;
			node_slider.delEvent(event_start, function(act){	itsMe.MouseDown(act); });
			node_slider.delEvent('click', function(act){	itsMe.SetPosition(act);	});
			node_slider.delEvent(event_move, function(act){	itsMe.DisplayTooltipp(act);	});
			node_slider.delEvent('mouseout',  function(){	itsMe.HideTooltipp();	});
			
			slider_enabled = false;
		}
	 }

	/**
	 * enable slider
	 *
	 * @author tschulte
	 * @since 14.11.2011
	 */
	 this.EnableSlider = function()
	 {
	  	if(slider_enabled != true)
	 	{
			//attach events
			var itsMe = this;
			node_slider.addEvent(event_start, function(act){	itsMe.MouseDown(act); });
			node_slider.addEvent('click', function(act){	itsMe.SetPosition(act);	});
			node_slider.addEvent(event_move, function(act){	itsMe.DisplayTooltipp(act);	});
			node_slider.addEvent('mouseout',  function(){	itsMe.HideTooltipp();	});
			
			//disable text selection
			if(typeof node_slider.onselectstart != "undefined")
			{
				node_slider.onselectstart = function() { return false };
			}
			
			node_slider.setStyle('cursor', '');
			node_highlight.appear();
			node_price.appear();
			
			slider_enabled = true;
		}
	 }

	//
	//Change update status for price slider
	//

	this.UpdateSliderStatus = function(bool_value)
	{
		if (typeof bool_value != 'undefined')
		{
			update_slider = bool_value;
		}
		
		return update_slider;
	}

	//
	//
	//

	this.TooltippEnabled = function(bool_value)
	{
		if (typeof bool_value != 'undefined')
		{
			tooltipp_enabled = bool_value;
		}
		
		return tooltipp_enabled;
	}

	//
	// private vars
	//

	var mouseover,

		finish_old_value = -1,
		change_old_value = -1,

		//nodes
		node_slider,
		node_highlight,
		node_price,
		node_input_price,
		node_tooltipp,
		node_document_main,

		//mouse events
		event_start,
		event_move,
		event_end,

		highligh_invert = false,
		
		state_user_changed = false,

		to,
		from,
		scale,
		
		tooltipp_enabled = false,
		slider_enabled = false,
		update_slider = true,
		
		hurdle_percent = 70,
		hurdle = 220,
		

		//configuration
		value_count    = 100, //Allowed number of values in the interval.
		sliderwidth    = 260,

		init_value,
		lock_auto_change = false,

		//events
		event_onfinish = false,
		event_onchange = false;
};

APP.PRICE.REGION.FILTER.SLIDER          = new function(flase){}
APP.PRICE.REGION.FILTER.SLIDER.PRICE    = new APP.PRICE.REGION.SLIDER(true);
APP.PRICE.REGION.FILTER.SLIDER.DISTANCE = new APP.PRICE.REGION.SLIDER(false);
APP.PRICE.REGION.GEODATA = new function()
{

    //
    //  private vars
    //

	var G;

	//
	//  build dynamic the var "this.G" related by the actual client configuration.
	//  we need this var for builden the google-pointer
	//  @todo make an array with objects (structure from the arr is old)
	//
	
	this.Init = function(d)
	{
		var baseurl = '/item.php?hlpath='+APP.SNAPSHOT.Get('path')+'&item=';

		G = '';
		for (var i=0, n=d.length; i<n; i++)
		{
			if (d[i] && d[i].geo && d[i].geo.lon && d[i].geo.lat)
			{
				G += (i+1)+'*'+d[i].geo.lon+'*'+d[i].geo.lat+'**'+baseurl+d[i].id+'&pagetype='+((d[i].price && d[i].price.partner > 0)? 'deals':'overview');
			}
			G += ';';
		}
	}
	
	//
	//  todo: cschmidt: comment
	//
	
	this.Get = function()
	{
		return G;
	}
	
	//
	//  todo: cschmidt: comment
	//
	
	this.Set = function(v)
	{
		G = v;
	}

};APP.PRICE.REGION.NO_RESULTS = new function()
{
	//
	//
	//
	
	this.Set = function(err_hdl, err_desc)
	{
		node_hdl.innerHTML = err_hdl;
		node_desc.innerHTML = err_desc;
	}
	
	//
	//
	//
		
	this.Hide = function()
	{
		if (!node)
		{
			this.Init();
		}
		node.disappear();
		disp_error_message = false;
	}
	
	//
	//
	//
		
	this.Show = function()
	{
		node.appear();
		disp_error_message = true;
	}

	//
	//
	//

	this.IsDisplayed = function()
	{
		return disp_error_message;
	}
	
	//
	//  related by the serviceresultcount, we display the error-message. if we have more
	//  than 0 items, than we break the procedure. (no error-message)
	//  in the other situation we load the error-message and set the error-module css-class. 
	//
	
	this.DisplayErrorMessage = function(response, serviceresultcount)
	{
		var css_class = ((response && response.error && response.error.css) ? response.error.css : 'icon_error');
		this.Set(
					((response && response.error.hdl) ? response.error.hdl : error), 
					((response && response.error.desc) ? response.error.desc : '')
				);
	
		APP.PRICE.REGION.TRANSPARENCY.Hide();
		APP.PRICE.REGION.PROGESSBAR.Hide();
		
		if (css_class=='icon_error')
		{
			APP.PRICE.REGION.NO_RESULTS.Show();
			APP.PRICE.REGION.FILTER.PAGING.Hide();
			APP.PRICE.REGION.FILTER_CITYLIST.Hide();
			APP.PRICE.REGION.DESIGN.Hide();
			APP.PRICE.REGION.MAP.ViewBigMap(false);
		}
		APP.PRICE.REGION.FILTER.RESET.Open();
		
		node_hdl.className = 'sprite_icon '+css_class;
		this.Show();
	}

	//
	//
	//
	
	this.Init = function()
	{
		node     = $('js_error');
		node_hdl = $('js_error_hdl');
		node_desc= $('js_error_desc');
	}
	
	//
	// private vars
	//
	
	var node,
		node_hdl,
		node_desc,
		
		disp_error_message = false,
		
		error = "No se encontraron resultados. IntÃ©ntalo mÃ¡s tarde.";
};
APP.PRICE.STRINGS = new function()
{

	//
	// private vars
	//
	
	var S = [];

	//
	//
	//
	
	this.Init = function(s)
	{
		S = s;
	}

	//
	//
	//
	
	this.Set = function(k, v)
	{
		return S[k] = v;
	}

	//
	//
	//
	
	this.Get = function(k)
	{
		return S[k] ? S[k] : k;
	}
};
APP.PRICE.REGION.MAP = new function()
{
	//
	//  If the status is true, when we displayed the map and load
	//  the code from google
	//
	
	this.ViewBigMap = function(status)
	{
		if(!status)
		{
			node_js_searchmap_box.disappear();
		}
		else
		{
			node_js_searchmap_box.appear();
			APP.PRICE.MAP.Main();
		}
	}
	
	
	//
	//  todo: cschmidt: comment
	//
	
	this.UpdateDisplayMapStatus = function(is_finished)
	{
		if (	is_finished ||
				this.GetPointerDifference() >= 5	)
		{
			this.ViewBigMap(APP.SNAPSHOT.Get('view_type')==1? true: false);
		}
	}

	//
	//
	//
	
	this.GetPointerDifference = function()
	{
		if (!APP.PRICE.MAP.GetMarker())
		{
			if (APP.PRICE.REGION.GEODATA.Get())
			{
				return APP.PRICE.REGION.GEODATA.Get().split(";").length;
			}
			return 0;
		}

		var m1 = APP.PRICE.REGION.GEODATA.Get().split(";"),
			m2 = APP.PRICE.MAP.GetMarker().split(";");
		var c = m1.length - m2.length;

		for(var i=0, n=m1.length; i<n; i++)
		{
			if (!m2.hasValue(m1[i]))
			{
				++c;
			}
		} 

		return c;
	}
	
	//
	//
	//

	this.Init = function()
	{
		node_js_searchmap_box = $('js_searchmap_box');
	}
	
	//
	// private vars
	//
	var node_js_searchmap_box;
};
//
// search map on price search which reloads marker data with user interaction
// the shown center can be changed, the radius can be changed and the cut out.
//
// @author crankers
// @since 31.08.2011
// @todo (crankers 18.07.2011) complete comments
//
APP.PRICE.MAP = new function()
{

	//
	// private vars
	//
	// S - state of map scripts
	// Q - internal queue to excute function when loaded
	// D - loaded marker data
	// M - internal map reference APP.MAPS.MAP
	// C - internal center for circle draw around
	// E - actions executed by user
	//
	var S = 'unloaded',
		Q = [],
		D = null,
		M = null,
		C = null,
		E = { 'cut_out_change':false, 'distance_param_change':false };
	this.bMapIsIdle = false;
	this.bMapIsHidden = false;

	//
	// Initialize map listening when not running. Add events for zoom,
	// center_drag and border_drag.
	// Use of function is public.
	//
	// @author crankers
	// @since 31.08.2011
	//
	// @return (boolean)
	//
	this.Listener = function(active)
	{
		('undefined' === typeof active) && (active = false);
		if (M && !M.Listener())
		{
			M.Listen({
				'zoom'       : function() { APP.PRICE.MAP.Handle('cut_out_change'); },
				'move'       : function() { APP.PRICE.MAP.Handle('cut_out_change'); }/*,
				'center_drag': function() { APP.PRICE.MAP.Handle('center_drag'); },
				'border_drag': function() { APP.PRICE.MAP.Handle('border_drag'); }*/
			}, active);
		}
		return true;
	}

	//
	// Handle triggered map events. Available event (t)ypes are cut_out_change,
	// center_drag, border_drag,
	// location or point. Use of function is public.
	//
	// @author crankers
	// @since 31.08.2011
	//
	// @return (boolean)
	//
	this.Handle = function(t, r)
	{
		if(!M)
		{
			return false;
		}

		(typeof r == 'undefined') && (r = null);
		switch(t)
		{
			case 'cut_out_change':
				this.StoreMap()
				&& (E['cut_out_change'] = true)
				&& APP.PRICE.REGION.Start(1, 1);
				break;
			/*
			case 'center_drag':
				(!E['cut_out_change']) &&  (E['distance_param_change'] = true);
				(E['cut_out_change']) &&  (E['distance_param_change'] = false);

				M.MarkerEvent('locator_center', 'mouseout');
				c = M.MarkerData('locator_center').getLatLng();

				if ($('searchmap_dynamic_center').isElement())
				{
					var o = $('searchmap_dynamic_center');
					o.text = '{'+c.lat()+', '+c.lng()+'}';
				}
				else
				{
					var o = new Option('{'+c.lat()+', '+c.lng()+'}', 'distance', false, true);
					o.setAttribute('id', 'searchmap_dynamic_center');
					document.forms['distance_search']['js_geo_distance_item'].options[document.forms['distance_search']['js_geo_distance_item'].options.length] = o;
				}
				o.setAttribute('geo_latitude', c.lat());
				o.setAttribute('geo_longitude', c.lng());
				o.selectedIndex = document.forms['distance_search']['js_geo_distance_item'].options.length-1;

				APP.SNAPSHOT.Request('center_drag',  '1');

				APP.MAPS.Geo().request({
					'latitude': c.lat(),
					'longitude': c.lng(),
					'onfinish': function(r){ APP.PRICE.MAP.Handle('location', r); }
				});

				break;
			case 'border_drag':
				(!E['cut_out_change']) &&  (E['distance_param_change'] = true);
				(E['cut_out_change']) &&  (E['distance_param_change'] = false);

				M.MarkerEvent('border_marker', 'mouseout');

				ggMaps.maps['searchmap'].locator.settings['radius'] = (Math.round((ggMaps.maps['searchmap'].locator.settings['radius']*1000) / 500) * 500) / 1000;

				if (ggMaps.maps['searchmap'].locator.settings['radius'] > 20)
				{
					ggMaps.maps['searchmap'].locator.settings['radius'] = 20;
				}

				$('js_input_price_geo_distance_limit').value = parseInt(ggMaps.maps['searchmap'].locator.settings['radius']);
				APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.SetPriceValue(
						parseInt(ggMaps.maps['searchmap'].locator
								 .get_calculate_radius_unit(
								 	ggMaps.maps['searchmap']
								 	.locator.settings['radius'])*1000));
				APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.StickToPosition();
				APP.PRICE.REGION.FILTER.ATTRACTION.SetPreviewText();
				this.Search(true);
				APP.SNAPSHOT.Request('map_border_drags',  '1');
				break;
			case 'location':
				if (typeof r.Placemark[0] != 'undefined')
				{
					$('searchmap_dynamic_center').value = $('searchmap_dynamic_center').text = r.Placemark[0].address;
				}
				this.Search(true);
				break;
			*/
			case 'point':
				if(r)
				{
					// add new menue-entry in the selectfield
					if(document.forms['distance_search']['geo_address_string'].value)
					{
						// make the geocode compatible to the php-side
						var lat = Math.round(r.geometry.location.lat()*1000000)/1000000,
							lon = Math.round(r.geometry.location.lng()*1000000)/1000000,
							geocode_exists = false;
						for(var i = 0, n = document.forms['distance_search']['geo_distance_item'].length; i < n; i++)
						{
							if(
								(document.forms['distance_search']['geo_distance_item'][i].getAttribute('geo_latitude') == lat)
								&& (document.forms['distance_search']['geo_distance_item'][i].getAttribute('geo_longitude') == lon))
							{
								geocode_exists = true;
								break;
							}
						}
						if(!geocode_exists)
						{
							var o = new Option(document.forms['distance_search']['geo_address_string'].value, document.forms['distance_search']['geo_address_string'].value, false, true);
							o.setAttribute('geo_latitude', lat);
							o.setAttribute('geo_longitude', lon);
							document.forms['distance_search']['js_geo_distance_item'].options[document.forms['distance_search']['js_geo_distance_item'].options.length] = o;
						}
					}

					C = {
				 		'id'         : 0,
				 		'class'      : 'center',
				 		'position'   : 'default',
				 		'display'    :'marker',
				 		'description': document.forms['distance_search']['geo_address_string'].value
				 						+' ('+(Math.round(1000 * r.geometry.location.lat())/1000)
				 						+','+(Math.round(1000*r.geometry.location.lng())/1000)
				 						+' )',
				 		'latitude'   : r.geometry.location.lat(),
				 		'longitude'  : r.geometry.location.lng()
					 };
					APP.SNAPSHOT.Request('geo_distance_limit',
							APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.GetValue());
					APP.SNAPSHOT.Request('geo_distance_item',  '');
					APP.SNAPSHOT.Request(
						'geo_code::latitude',
						parseFloat(r.geometry.location.lat()));
					APP.SNAPSHOT.Request(
						'geo_code::longitude',
						parseFloat(r.geometry.location.lng()));
					APP.SNAPSHOT.Request('geo_use_distance',   '1');
					APP.SNAPSHOT.Request('offset',             '0');
					APP.SNAPSHOT.Request('geo_address_string',
						document.forms['distance_search']['geo_address_string'].value);
					APP.PRICE.REGION.Start();
					google.maps.event.addListenerOnce(M.Map(), 'idle',
						function()
						{
							window.setTimeout(function()
							{
								var map = APP.PRICE.MAP.getMap();
								map && google.maps.event.trigger(map, 'resize');
								map && map.setZoom(map.getZoom());
								APP.PRICE.MAP.Main();
							}, 750);
						});
				}
				else
				{
					document.forms['distance_search']['geo_address_string'].value =
						'Intenta otro tÃ©rmino de bÃºsqueda';
					APP.PRICE.REGION.TRANSPARENCY.Hide();
				}
				break;
		}
	}

	//
	// Initialize price map and starts object after loading.
	// Use of function is public.
	//
	// @author crankers
	// @since 31.08.2011
	//
	// @return (void)
	//
	this.Init = function(p, mapType)
	{
		p && p.onfinish && Q.push(p.onfinish);
		if('string' !== typeof mapType)
		{
			mapType = 'searchmap';
		}
		else
		{
			mapType = mapType.toLowerCase();
		}
		switch(mapType)
		{
			// allowed values:
			case 'searchmap':
			case 'attractionmap':
				break;
			// illegal parameters set to default value
			default:
				mapType = ' searchmap';
				break;
		}
		switch(S)
		{
			case 'unloaded':
				S = 'loading';
				APP.RUN.Exe('trivago.map', {
					'onfinish': function()
					{
						if(!M)
						{
							APP.MAPS.Map({
								'id':'searchmap',
								'dfn': '/trivago_rpc.php?&action=dfnmap&id=' + mapType,
								'onfinish': function()
									{
										APP.PRICE.MAP.Start('loaded');
									}
							});
						}
						else
						{
							APP.PRICE.MAP.Start('loaded');
						}
					}
				});
				break;

			case 'loaded':
				this.Start();
				break;
		}
	}

	//
	// Start map when loading is ready with given (s)tate.
	// Use of function is public.
	//
	// @author crankers
	// @since 31.08.2011
	//
	// @param (string) s, new loading state for object
	//
	// @return (void)
	//
	this.Start = function(s)
	{
		('undefined' != typeof s) && (S = s);
		if(S != 'loaded')
		{
			return false;
		}

		if(!M)
		{
			this.bMapIsIdle = false;
			M = APP.MAPS.Map('searchmap');
			M.Map();

			google.maps.event.addListenerOnce(M.Map(), 'idle', function()
				{
					APP.PRICE.MAP.bMapIsIdle = true;
				});

			for(var i=0, n=Q.length; i < n; ++i)
			{
				Q[i]();
			}
			Q = [];
		}
	}

	//
	// Returns internal stored marker data.
	// Use of function is public.
	//
	// @author crankers
	// @since 31.08.2011
	//
	// @param (string) s, new loading state for object
	//
	// @return (void)
	//
	this.GetMarker = function()
	{
		return D;
	}


	/**
	 * Returns the actual internal used google map object.
	 *
	 * @author René Kerner <rene.kerner@trivago.com>
	 * @since 23.01.2012
	 *
	 * @return object google.maps.Map
	 */
	this.getMap = function()
	{
		if(M && M.Map())
		{
			return M.Map();
		}
		return null;
	}

	//
	// Store new (c)enter internal when a circle should be drawn this would be
	// used.
	// Use of function is public.
	//
	// @author crankers
	// @since 22.09.2011
	//
	// @param (LatLng) c, center point to store
	//
	// @return (void)
	//
	this.SetCenter = function(c)
	{
		return (C = c);
	}

	//
	// Save map into Snapshot.
	// Use of function is private.
	//
	// @author crankers
	// @since 21.09.2011
	//
	// @return (boolean)
	//
	this.StoreMap = function(force_bounds, force_zoom)
	{
		if('boolean' !== typeof force_bounds)
		{
			force_bounds = false;
		}
		if('boolean' !== typeof force_zoom)
		{
			force_zoom = false;
		}
		var r = false;
		if(M && M.Map() && this.bMapIsIdle)
		{
			var ne = null,
				sw = null
				nb = null;
			if(M.Map().getBounds())
			{
				ne = M.Map().getBounds().getNorthEast();
				sw = M.Map().getBounds().getSouthWest();
				nb = ne.lat() + ";" + ne.lng() + ";" + sw.lat() + ";"
					 + sw.lng();
			}
			var ob = APP.SNAPSHOT.Get('map_bounds'),
				nz = M.Map().getZoom(),
				oz = APP.SNAPSHOT.Get('map_zoom');

			var changed = {'zoom': false, 'bounds': false};

			if(force_bounds || (nb != ob))
			{
				r = true;
				changed.bounds = true;
				APP.SNAPSHOT.Request('map_bounds', nb);
			}

			if(force_zoom || (nz != parseInt(oz)))
			{
				r = true;
				changed.zoom = true;
				APP.SNAPSHOT.Request('map_zoom',  nz);
			}

			if((true === r) && (false === changed.bounds))
			{
				APP.SNAPSHOT.Request('map_bounds', null);
			}
			if((true === r) && (false === changed.zoom))
			{
				APP.SNAPSHOT.Request('map_zoom', oz);
			}
		}
		return r;
	}


	this.fixGreyTiles = function()
	{
		var oMapDiv = $('js_searchmap_box');
		if(this.bMapIsHidden && oMapDiv.isElement()
			&& ('none' !== oMapDiv.getStyle('display')))
		{
			google.maps.event.addListenerOnce(M.Map(), 'idle',
				function()
				{
					window.setTimeout(function()
					{
						var map = APP.PRICE.MAP.getMap();
						map && google.maps.event.trigger(map, 'resize');
						map && map.setZoom(map.getZoom());
						APP.SNAPSHOT.Request('map_zoom', '');
						APP.SNAPSHOT.Request('map_bounds', '');
						APP.PRICE.MAP.Main();
					}, 750);
				});
			this.bMapIsHidden = false;
		}
	}


	//
	//
	//
	this.Main = function(mapType)
	{
		if(S != 'loaded')
		{
			this.Init({'onfinish': function() { APP.PRICE.MAP.Main(); }}, mapType);
			return false;
		}

		var m = [],
			e = APP.PRICE.REGION.GEODATA.Get(),
			t = (APP.SNAPSHOT.Get('offset') > 0) ? 'hotel' : 'hotelid';

		// parse marker data
		if(e)
		{
			D = e;
			var d = e.split(';');

			for (var i=0, n=d.length; i < n; i++)
			{
				if('' != d[i])
				{
					var ms = d[i].split('*');
					if(ms[2] && ms[1])
					{
						m.push(this.SetEvents({
					 		'id'         : (i+1),
					 		'type'       : t,
					 		'center'     : false,
					 		'visibility' : true,
					 		'anchor'     : ms[4],
					 		'title'      : '',
					 		'description': '',
					 		'latitude'   : ms[2],
					 		'longitude'  : ms[1]
						 }));
					 }
				}
			}
		}

		if (m.length > 0)
		{
			// deactivate listener
			M.Listener() && M.Listener().Deactivate();

			// reset and initialize map by given markers
			M.Reset();
			M.Marker(m);
			M.ShowMarkers(t, (APP.SNAPSHOT.Get('map_bounds') ? false : true));

			if(C)
			{ // show locator with given center
				M.ShowLocator(
					new google.maps.LatLng(C['latitude'], C['longitude']),
					APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.GetValue());
			}
			else
			{ // show locator without center
				var c = {};
				if(APP.SNAPSHOT.Get('geo_code::latitude')
					&& APP.SNAPSHOT.Get('geo_code::longitude'))
				{ // get center from snapshots
					c['latitude'] = APP.SNAPSHOT.Get('geo_code::latitude');
					c['longitude'] = APP.SNAPSHOT.Get('geo_code::longitude');
				}
				else
				{ // get center from map
					c['latitude']  = Math.round(
										1000 * M.Map().getCenter().lat()) / 1000;
					c['longitude'] = Math.round(
										1000 * M.Map().getCenter().lng()) / 1000;
				}
				M.ShowLocator(
					new google.maps.LatLng(c['latitude'], c['longitude']),
					APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.GetValue());
			}

			var restoredMap = false;
			// load plot-config
			var b;
			var s = APP.SNAPSHOT.Get('map_bounds');
			if(s && (4 == ((s = s.split(';')).length)))
			{
				var ne = new google.maps.LatLng(s[0], s[1]),
					sw = new google.maps.LatLng(s[2], s[3]),
					b = new google.maps.LatLngBounds(sw, ne);
				M.Map().fitBounds(b);
				restoredMap = true;
			}

			var z = APP.SNAPSHOT.Get('map_zoom');
			if((null !== z) && ('' !== z))
			{
				z = parseInt(z);
				if(z || (0 === z))
				{
					M.Map().setZoom(z);
					restoredMap = true;
				}
			}

			(!restoredMap) && this.StoreMap() && APP.PRICE.REGION.Start(1, 1);
		}
		// restart Listener
		this.Listener(true);
		this.fixGreyTiles();
	}

	//
	// Add events to (m)arker when a single view exists.
	// Use of function is private.
	//
	// @author crankers
	// @since 22.09.2011
	//
	// @param (object) m, marker object
	//
	// @return (object)
	//
	this.SetEvents = function(m)
	{
 		m['mouseover'] = '';
 		m['mouseout']  = '';
		var r = APP.PRICE.REGION.GetResponse();
		if(r && r.items)
		{
	 		m['mouseover'] = function()
	 			{
	 				$('searchmap_detail_info').innerHTML =
	 					APP.PRICE.REGION.DESIGN.GetSingle(
	 						r.items[m['id']-1], (m['id']-1), true);
	 			};
	 		m['mouseout'] = function()
	 			{
	 				$('searchmap_detail_info').innerHTML = '';
	 			};
		}
		return m;
	}

	//
	//
	//
	this.SetDistanceChange = function(b)
	{
		var display_mode = 'geo_distance_item';
		if($('geo_address_string').value
			!= $('geo_address_string').getAttribute('default'))
		{
			display_mode = 'geo_address_string';
		}

		if(('geo_address_string' == display_mode)
			|| (0 != $('js_geo_distance_item').selectedIndex))
		{
			APP.SNAPSHOT.Request('order_by', 'distance asc');
			APP.PRICE.REGION.TOP_NAV.ChangeButtonOrder('distance asc');
		}
		return (E['distance_param_change'] = b);
	}

	//
	//
	//
	this.Search = function(do_search)
	{
		APP.PRICE.REGION.TRANSPARENCY.Show();
		if (S != 'loaded')
		{
			this.Init({
				'onfinish': function()
					{
						APP.PRICE.MAP.Search('+do_search+');
					}});
			return false;
		}

		var oMapDiv = $('js_searchmap_box');
		this.bMapIsHidden = oMapDiv.isElement()
							&& ('none' === oMapDiv.getStyle('display'));

		var form = document.forms['distance_search'];

		APP.SNAPSHOT.Request('geo_distance_limit', '');
		APP.SNAPSHOT.Request('geo_distance_item',  '');
		APP.SNAPSHOT.Request('geo_code::latitude', '');
		APP.SNAPSHOT.Request('geo_code::longitude','');
		APP.SNAPSHOT.Request('geo_address_string', '');

		if(E['distance_param_change'])
		{
			APP.SNAPSHOT.Request('map_bounds', '');
			APP.SNAPSHOT.Request('map_zoom', '');
		}

		(do_search) && APP.SNAPSHOT.Request('geo_use_distance', 1);

		if(APP.SNAPSHOT.Get('geo_use_distance') == 0)
		{
			C = false;
			APP.PRICE.REGION.FILTER.ATTRACTION.Disable();
		}
		else
		{
			var display_mode = 'geo_distance_item';
			if($('geo_address_string').value
				!= $('geo_address_string').getAttribute('default'))
			{
				display_mode = 'geo_address_string';
			}

			if ('geo_address_string' == display_mode)
			{ // search by address field
				APP.MAPS.Geo().request({
						'address': form['geo_address_string'].value
						           + ', ' + form['path_info'].value,
						'onfinish': function(r)
					 	{
							if(-1 === document.forms['distance_search']['geo_address_string'].value.lastIndexOf(form['path_info'].value))
							{
								document.forms['distance_search']['geo_address_string'].value =
									form['geo_address_string'].value
							           + ', ' + form['path_info'].value;
							}
							APP.PRICE.MAP.Handle('point', r);
						}});
			}
			else if('' != APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.GetValue())
			{
				for(var j=0, n=form['geo_distance_item'].length; j < n; ++j)
				{
					var o = form['geo_distance_item'].options[j];
					if((true == o.selected)
						&& o.getAttribute('geo_longitude')
						&& o.getAttribute('geo_latitude'))
					{
						C = {
					 		'id'         : 0,
					 		'class'      : 'center',
					 		'position'   : 'default',
					 		'display'    : 'marker',
					 		'description': o.text + ' ('
					 						+ (Math.round(
					 							1000 * o.getAttribute('geo_latitude')) / 1000)
					 						+ ','
					 						+ (Math.round(
					 							1000 * o.getAttribute('geo_longitude')) / 1000)
					 						+ ' )',
					 		'latitude'   : o.getAttribute('geo_latitude'),
					 		'longitude'  : o.getAttribute('geo_longitude')};
						APP.SNAPSHOT.Request('geo_distance_limit',  APP.PRICE.REGION.FILTER.SLIDER.DISTANCE.GetValue());
						APP.SNAPSHOT.Request('geo_distance_item',   form['geo_distance_item'].value);
						APP.SNAPSHOT.Request('geo_code::latitude',  parseFloat(o.getAttribute('geo_latitude')));
						APP.SNAPSHOT.Request('geo_code::longitude', parseFloat(o.getAttribute('geo_longitude')));
						APP.SNAPSHOT.Request('geo_use_distance',    '1');
						APP.SNAPSHOT.Request('offset',              '0');
						APP.PRICE.REGION.Start();
						break;
					}
				}
			}
		}
	}

}
APP.PRICE.REGION.TRANSPARENCY = new function()
{

	//
	// private vars
	//
	
	var nt,
		ns,
		obj_fading,
		timeout_id;
	
	//
	//
	//
	
	this.Init = function()
	{
		nt = $('transparency');
		ns = $('searchmap_loader');
		nt.setOpacity(100);
	}
	
	//
	//
	//
		
	this.Hide = function()
	{
		if (obj_fading)
		{
			obj_fading.Abort();
		}
		if (timeout_id)
		{
			window.clearTimeout(timeout_id);
		}
		
		obj_fading = new APP.EFFECT.Fading(nt, true, {'target_opacity':20,'duration':1, 'onfinish':function(){nt.disappear();}});
	}
	
	//
	//
	//
		
	this.Show = function()
	{
		if (obj_fading)
		{	
			obj_fading.Abort()
		}
		nt.setOpacity(0);
		nt.delClass('ani');
		nt.appear();
		
		timeout_id = window.setTimeout(function(){APP.PRICE.REGION.TRANSPARENCY.DipAnimation();}, 1000);
		
		obj_fading = new APP.EFFECT.Fading(nt, false, {'target_opacity':80, 'duration':10});
	}
	
	//
	//
	//
	
	this.DipAnimation = function()
	{
		nt.addClass('ani');
	}
	
};APP.PRICE.REGION.CACHE = new function(){}
APP.PRICE.REGION.CACHE.FILTER = new function()
{
	//
	//
	//
	
	this.GetCopyProperties = function(properties)
	{
		var retval = Object.prototype.constructor(), 
			key;
	  	
	  	for(key in properties)
	  	{
			if({'function':1,'undefined':1}[typeof properties[key]])
			{
				continue;
			}

	  		try
	  		{
	  			if (properties[key]==null)
	  			{
	  				retval[key] = null;
	  			}
	  			else
	  			{
	  				retval[key] = properties[key].valueOf();
	  			}
	  		}
	  		catch(e)
	  		{
	  			COM.Log('func: APP.PRICE.REGION.CACHE.FILTER.GetCopyProperties();' + key + '=' + properties[key] + '-exception');
	  		}
	  	}

	  	return retval;
	}

	//
	//
	//

	this.Set = function(snap, request_ident)
	{
		arr_cache.push(this.GetCopyProperties(snap));
	}

	//
	//
	//

	this.GetFirstSnapshot = function()
	{
		//delete all cache without the first
		for (var i=arr_cache.length; i>1; i--)
		{
			arr_cache.pop();
		}

	    return this.GetLastSnapshot();
	}

	//
	//
	//
	
	this.GetLastSnapshot = function()
	{
	    if (arr_cache.length > 1)
	    {
	    	arr_cache.pop();
	    }

		// load last snap
	    return this.GetCopyProperties(arr_cache[arr_cache.length-1]);
	}
	
	//
	//
	//
	
	this.GetCountSnapshot = function()
	{
	    return arr_cache.length;
	}
	
	//
	// with the request_ident we flush all later steps 
	//

	this.Flush = function(request_ident)
	{
		var retval = [];

		// load last snap
		for (var i=0, n=arr_cache.length; i<n; i++)
		{
			if (arr_cache[i]['request_ident'] < request_ident)
			{
				retval.push(arr_cache[i]);
			}
		}

	    arr_cache = retval;
	}
	
	//
	// private vars
	// 
	
	var arr_cache = [];
};
APP.PRICE.REGION.CACHE.RESPONSE = new function()
{
	//
	//
	//
	
	this.GetCopyProperties = function(properties)
	{
		var retval = Object.prototype.constructor(), 
			key;
	  	
	  	for(key in properties)
	  	{
			if({'function':1,'undefined':1}[typeof properties[key]])
			{
				continue;
			}

	  		try
	  		{
	  			retval[key] = properties[key].valueOf();
	  		}
	  		catch(e)
	  		{
	  			COM.Log('func:APP.PRICE.REGION.CACHE.FILTER.GetCopyProperties();' + key + '=' + properties[key] + '-exception');
	  		}
	  	}

	  	return retval;
	}

	//
	//
	//
	
	this.GetCachedItems = function(arr_items)
	{
		var retval = '';
		
		if (arr_items)
		{
			for(var i=0, n=arr_items.length; i<n; i++)
			{
				if (arr_cache[ arr_items[i].id ])
				{
					retval += (retval == '' ? '' : '.') + arr_items[i].id;

					if (arr_items[i].price)
					{
						retval += ',' + arr_items[i].count_prices + ',' + (arr_items[i].price ? arr_items[i].price.partner : '0');
					}
				}
			}
		}

		return retval;
	}
	
	//
	//
	//
	
	this.Get = function(arr_items)
	{
		for(var i=0, n=arr_items.length; i<n; i++)
		{
			if(arr_cache[ arr_items[i].id ])
			{
				arr_items[i] = this.GetCopyProperties(this.MergeRecursive(arr_cache[ arr_items[i].id ], arr_items[i]));
			}

			arr_cache[ arr_items[i].id ] = arr_items[i];
		}
		
		return arr_items;
	}
	
	//
	// private function to merge the two objects
	//
	
	this.MergeRecursive = function(obj1, obj2) 
	{
		for(var p in obj2)
		{
			if ({'function':1,'undefined':1}[typeof obj2[p]])
			{
				break;
			}
			
			try
			{
				// Property in destination object set; update its value.
				obj1[p] = obj2[p];
			}
			catch(e)
			{
				COM.Log('error-MergeRecursive:' + e);
				// Property in destination object not set; create it and set its value.
				obj1[p] = obj2[p];
			}
		}

		return obj1;
	}
	
	//
	// private vars
	// 
	
	var arr_cache = new Array();
}
APP.RUN.Call("trivago.search");
APP.FORM = new function(){}
	var timeout_id;
	function getDelayCityMatch(delay_time)
	{
		if(typeof delay_time == "undefined")
		{
			delay_time = 10;
		}
		if (timeout_id > 0)
		{
			window.clearTimeout(timeout_id);
		}
		timeout_id = window.setTimeout("getCityMatch();", delay_time);
	}


	var arrMaxShares = new Array();
	var arrDispString= new Array();
	var arrEditData  = new Array();
	function getCityMatch()
	{
		if( ($("searchstring").value.length > 0) &&
			($("searchstring").value != $("default_item_query_string").value) &&
			($("last_query").value != $("country").value+"|"+$("searchstring").value)	) {
			$('item').value='';
			$('path').value='';
			$("last_query").value = $("country").value+"|"+$("searchstring").value;
			COM.HTTP.Get("/trivago_rpc.php?pagetype=" + $('pagetype').value + "&action=get_city_match&q=" + encodeURIComponent($('searchstring').value) + "&path=" + $('country').value,
							{
							"xml":true,
							"onfinish":function(matchResponse){
								var num_rows = matchResponse.getAttribute("num_rows");

								displayNewItemMode(false, true);


								if(num_rows == 1) {
									$("js_match_response").disappear();

									var item      = matchResponse.getElementsByTagName("item")[0];
									var edit_data = matchResponse.getElementsByTagName("edit_data")[0];


									//redirect the user
									if(getElD(item, "right") == 0) {
										var right = item.getElementsByTagName("right")[0];
										var redirectUrl = right.getAttribute("redirectUrl");
										if(redirectUrl) {
											window.location.replace(redirectUrl);
											return;
										}
									}

									if(edit_data != null) {
										//set default value
										initial_item_values(getElD(edit_data, "title"), getElD(edit_data, "summary"), getElD(edit_data, "opinion_id"), getElD(edit_data, "overall_liking"));
										$('opinion').value      = getElD(edit_data, "opinion_id");

									}
									$('searchstring').value = getElD(item, "item_name") + ", " + getElD(item, "path_name");
									$('item').value = getElD(item, "item_id");
									$('path').value = getElD(item, "path_id");
									$('max_shares').innerHTML = getElD(item, "max_shares");
								}

								else if(num_rows == 0) {
									// set the found path-id
									$('path').value = matchResponse.getAttribute("path");
									$('item').value = "";
									if($('opinion'))
										$('opinion').value = "";

									displayNewItemMode(true, true);
								}


								else if(num_rows > 1) {

									var items    = matchResponse.getElementsByTagName("items")[0];
									var arr_item = items.getElementsByTagName("item");
									var str   = "";

									for(var i=0; i<arr_item.length; i++) {
										var item   = arr_item[ i ];
										var itemId = getElD(item, "item_id");
										var tag_right   = item.getElementsByTagName("right")[0];
										var redirectUrl = tag_right.getAttribute("redirectUrl");
										var edit_data= item.getElementsByTagName("edit_data")[0];
										var right = getElD(item, "right");

										arrMaxShares [ itemId ] = getElD(item, "max_shares");
										arrDispString[ itemId ] = getElD(item, "item_name") + ", " + getElD(item, "path_name");

										//set default value
										if(edit_data != null) {
											if(edit_data.getAttribute("canEdit")) {
												arrEditData [ itemId ] = {	title:getElD(edit_data, "title"),
																			summary:getElD(edit_data, "summary"),
																			opinion_id:getElD(edit_data, "opinion_id"),
																			overall_liking:getElD(edit_data, "overall_liking")};
											}
										}

										str += "<li><a href='javascript:void(0);' onclick=\"setItem('"+right+"','"+redirectUrl+"','"+itemId+"','"+getElD(item, "path_id")+"');\">";
										str += "<input type=\"radio\" class=\"radio\" />";
										str += "<span>" + getElD(item, "item_name") + " (" + getElD(item, "item_group_name") + ") , " + getElD(item, "path_name") + "</span></a></li>";

									}

									str += "<li><a href='javascript:void(0);' onclick=\"displayNewItem();\">";
									str += "<input type=\"radio\" class=\"radio\" checked=\"checked\" />";
									str += "<span>AÃ±adir una nueva atracciÃ³n u hotel con este nombre</span></a></li>";
									$('js_match_response').innerHTML = "<ul>" + str + "</ul>";
									$('js_match_response').appear();
									COM.WIZARD.Size();
									displayNewItemMode(true, false);

								}
							}});
		}
	}
	

	function displayNewItem()
	{
		$('item').value='';
		displayNewItemMode(true, true);
		COM.WIZARD.Size();
	}


	function displayNewItemMode(status, disappear_match_response)
	{
		if(status)
		{
			$('searchstring').className = "text searchstring_small";
			$('country').className      = "country_small";

			if(disappear_match_response)
			{
				$('js_match_response').disappear();
			}
			$('item_group').style.display = "";
			$('max_shares').innerHTML = '';
		}
		else
		{
			$('searchstring').className = "text searchstring_big";
			$('country').className      = "country_big";
			$('item_group').disappear();
		}
	}


	function initial_item_values(title, summary, opinion, overall_liking)
	{
		if(!$("titel").value && !$("summary").value
				&& $("overall_liking").value == $("default_rating_field_value").value)
		{
			if (!overall_liking)
			{
				overall_liking = 1000*Math.round(10*Math.random());
				if (overall_liking < 3000)
				{
					overall_liking = 3000;
				}
				else if (overall_liking > 7000)
				{
					overall_liking = 7000;
				}
			}

			$('titel').value   = title;
			$('summary').value = summary;
			$('opinion').value = opinion;
			APP.FORM.RATES.MouseOver("overall_liking", overall_liking);
			APP.FORM.RATES.Set("overall_liking", "", overall_liking);
			$("default_rating_field_value").value = $("overall_liking").value;
		}
	}

	function setItem(perm, redirectUrl, item, path)
	{
		if("0" == perm)
		{
			window.location.replace(redirectUrl);
			return;
		}

		if(arrEditData[item])
		{
			initial_item_values(
					arrEditData[item].title,
					arrEditData[item].summary,
					arrEditData[item].opinion_id,
					arrEditData[item].overall_liking);
		}

		$('searchstring').value = arrDispString[ item ];
		$("last_query").value = $("country").value+"|"+$("searchstring").value;
		displayNewItemMode(false, true);
		$("js_match_response").disappear();

		$('item').value= item;
		$('path').value= path;

		$('max_shares').innerHTML = arrMaxShares[ item ];

		COM.WIZARD.Size();
	}


	function insert(aTag, eTag) {
		var input = $("text");
		input.focus();

				if(typeof document.selection != 'undefined') {
						var range = document.selection.createRange();
			var insText = range.text;
			range.text = aTag + insText + eTag;

						range = document.selection.createRange();
			if (insText.length == 0) {
				range.move('character', -eTag.length);
			} else {
				range.moveStart('character', aTag.length + insText.length + eTag.length);
			}
			range.select();
		}

				else if(typeof input.selectionStart != 'undefined') {
						var start = input.selectionStart;
			var end = input.selectionEnd;
			var insText = input.value.substring(start, end);
			input.value = input.value.substr(0, start) + aTag + insText + eTag + input.value.substr(end);

						var pos;
			if (insText.length == 0) {
			pos = start + aTag.length;
			} else {
			pos = start + aTag.length + insText.length + eTag.length;
			}
			input.selectionStart = pos;
			input.selectionEnd = pos;
		}
				else {
						var pos;
			var re = new RegExp('^[0-9]{0,3}$');
			while(!re.test(pos)) {
				pos = prompt("Einfügen an Position (0.." + input.value.length + "):", "0");
			}
			if(pos > input.value.length) {
				pos = input.value.length;
			}

						var insText = prompt("Bitte geben Sie den zu formatierenden Text ein:");
			input.value = input.value.substr(0, pos) + aTag + insText + eTag + input.value.substr(pos);
		}
	}

	function rejectContent()
	{
		var e = $('comment_box'),
		    r = e.getStyle('display') != 'none';

		e.appear();
		return r;
	}

	//
	//  waiting animation for FullfillmentRatingBox
	//

	function showwaiting()
	{
	   var e = $('transp_rating_box'),
	       f = $('module_body_content_rating_form');

	   e.appear();
	   e.resizeTo(f.getWidth(), f.getHeight());
	   e.setOpacity(50);
	}


	
	function toggleHotelCategory(cat_id)
	{
		$('item_category').disabled = (cat_id == 160) ? false : 'disabled';
	}
APP.IMG_UPLOADER = new function()
{
		this.useClassicImageUpload = true;
		this.aurigmaCdnUrl = '';
		this.uploaderActionUrl = '';
		this.aurigmaUploaderConfig = false;
		this.Uploader = false;

		this.getAurigmaUploaderConfig = function()
		{
			if(!this.aurigmaUploaderConfig)
			{
				this.aurigmaUploaderConfig =
				{
					id: 'Uploader1',
					width: '525px',
					height: '400px',
					licenseKey: '76FF2-004A8-43CA0-000D5-0E4C8-8C5CEF',
					enableDescriptionEditor: false,
					activeXControl:
					{
						codeBase:   '/contrib/imageupload/ImageUploader7.cab',
						codeBase64: '/contrib/imageupload/ImageUploader7_x64.cab'
					},
					javaControl:
					{
						codeBase: '/contrib/imageupload/ImageUploader7.jar'
					},
					uploadSettings:
					{
						filesPerPackage: 0,
						chunkSize: 0,
						actionUrl: APP.IMG_UPLOADER.uploaderActionUrl
					},
					converters: [{ mode: '*.*=SourceFile' }],
		            events:
		            {
		            	 beforeUpload: APP.IMG_UPLOADER.beforeUpload,
		            	 afterUpload:  APP.IMG_UPLOADER.afterUpload
		             },
		             paneLayout: "TreePanes",
		             loadingFolderContentText: "Loading content...",
		             enableDragAndDrop: true,
		             enableUploadPane: true,
		             treePane:
		             {
		            	 width: 170,
		            	 titleText: "Folders"
		             },
		             folderPane:
		             {
		            	 height: 270,
		            	 showAllowedItemsOnly: true,
		            	 headerText: "<totalLink>Total [totalCount]</totalLink>, <allowedLink>Allowed [allowedCount]</allowedLink>",
		            	 filterHintText: "Search"
		             },
		             uploadPane:
		             {
		            	 viewMode: 'List',
		            	 tileHeight: 100,
		            	 dropFilesHereText: "Drop files here"
		             },
		             uploadButtonImageFormat: "width=1;height=1;UrlNormal=http://il1.trivago.com/images/layoutimages/1x1.png",
		             detailsViewColumns:
		             {
		            	 infoText: ''
		             },
		             paneItem:
		             {
		            	 showFileNameInThumbnailsView: true,
		            	 rotationIconTooltip:	 "Rotate",
		            	 imageEditorIconTooltip:"Preview / edit image",
		            	 descriptionEditorIconTooltip: "Edit description"
		             },
		             restrictions:
		             {
		            	 minImageHeight: 200,
		            	 minImageWidth:  200,
		            	 maxFileCount:   10,
		            	 maxFileSize: 10485760,
		            	 maxTotalFileSize: 11534336,
		            	 fileMask:       "*.jpg;*.jpeg"
		             },
		             imageEditor:
		             {
		            	 enableCrop: true
		             },
		             metadata:
		             {
		            	 additionalFormName:  "newitempicture_form"
		             },
		             messages:
		             {
		            	 fileSizeTooSmall:		"Foto muy pequeÃ±a",
		            	 dimensionsTooSmall:	"Foto muy pequeÃ±a",
		            	 maxFileSizeExceeded:	"The file \'[name]\' cannot be selected. This file size exceeds the limit.",
		            	 maxTotalFileSizeExceeded: "The file \'[name]\' cannot be selected. Total upload data size exceeds the limit.",
		            	 maxFileCountExceeded: "The file \'[name]\' cannot be selected. Amount of files exceeds the limit."
		             },
		             uploadProgressDialog:
		             {
		            	 titleText:			"Cargando archivos",
		            	 preparingText:		"Los datos estÃ¡n siendo enviados...",
		            	 estimationText:       "Tiempo estimado: [Current] de [Total]",
		            	 cancelUploadButtonText:"Cancelar",
		            	 hideButtonText:		"Cerrar",
		            	 infoText:				"Files uploaded: [files]/[totalFiles] ([bytes] of [totalBytes])"
		             },
		             contextMenu:
		             {
		            	 checkAllText:			"Seleccionar todo",
		            	 uncheckAllText:		"Desmarcar todo",
		            	 editText:				"Edit image...",
		            	 editDescriptionText:	"Edit description...",
		            	 checkText:			"Check",
		            	 uncheckText:			"Uncheck",
		            	 arrangeByText: 		"Sort by",
		            	 arrangeBySizeText:	"TamaÃ±o",
		            	 arrangeByModifiedText:"Modificada",
		            	 arrangeByTypeText:	"Tipo",
		            	 arrangeByNameText:	"Nombre",
		            	 thumbnailsViewText:	"Miniaturas",
		            	 detailsViewText:		"Detalles",
		            	 listViewText:			"Lista"
		             },
		             statusPane:
		             {
		            	 noFilesToUploadText:  "No files to upload",
		            	 filesToUploadText:    "Files selected to upload: [count]",
		            	 clearAllHyperlinkText:"clear all"
		             },
		             imageEditor:
		             {
		            	 descriptionHintText: 	"Type description here...",
		            	 rotateButtonText:		"Rotate",
		            	 cropButtonText:		"Crop",
		            	 cancelCropButtonText:  "Cancel crop",
		            	 saveButtonText:		"Save and close",
		            	 cancelButtonText:		"Cancel"
		             },
		             descriptionEditor:
		             {
		            	 saveButtonText: 		"Save and close",
		            	 cancelHyperlinkText:	"Cancel",
		            	 orEscLabelText:		"(or Esc)"
		             }
				};
			}
			return this.aurigmaUploaderConfig;
		}

		this.aurigmaCheckBrowser = function()
		{
			if(Browser.MacSafari || Browser.IE6)
			{
				$("block_comfort_upload").disappear();
				return;
			}
			if('object' == typeof $au)
			{
				var au = $au.uploader({id:'Uploader2'});
				if((false == au.activeXControl().isActiveXSupported())
					&& (false == au.javaControl().isJavaSupported()))
				{
					$("block_comfort_upload").disappear();
				}
			}
			else
			{
				window.setTimeout('APP.IMG_UPLOADER.aurigmaCheckBrowser()', 10);
			}
		}

		this.checkBrowserEnviroment = function(url)
		{
			this.aurigmaCdnUrl = url;
			this.useClassicImageUpload = true;
			COM.Include(this.aurigmaCdnUrl);
			this.aurigmaCheckBrowser();
		}

		this.getImageUploader = function(callback)
		{
			if('object' == typeof $au)
			{
				APP.IMG_UPLOADER.Uploader = $au.uploader(APP.IMG_UPLOADER.getAurigmaUploaderConfig());
				if('function' == typeof callback)
				{
					callback(APP.IMG_UPLOADER.Uploader);
				}
			}
			else
			{
				window.setTimeout(function(callback)
					{
						APP.IMG_UPLOADER.getImageUploader(callback);
					}, 10);
			}
		}

		this.initUploadWriter = function(Action)
		{
			this.useClassicImageUpload = false;
			this.uploaderActionUrl = Action;
			var imgUpl_tool = $('tool_ImageUploader1');
			$('BasicImageUpload').disappear();
			imgUpl_tool.appear();
			$($('switch_to_start').parentNode).appear();
			COM.WIZARD.Size();
			if('' != imgUpl_tool.innerHTML)
			{
				return;
			}
			COM.Include(this.aurigmaCdnUrl);
			this.getImageUploader(function(uploader)
			{
				imgUpl_tool.innerHTML = uploader.getHtml();
				COM.WIZARD.Size();
			});
		}

		this.onSendButton = function()
		{
			if(this.beforeUpload())
			{
				if((false === APP.IMG_UPLOADER.useClassicImageUpload) && (false != APP.IMG_UPLOADER.Uploader))
				{
					if(APP.IMG_UPLOADER.Uploader.files().count() > 0)
					{
						APP.IMG_UPLOADER.Uploader.metadata().addCustomField('statement_of_origin', $('statement_of_origin').checked ? '1' : '0');
						$('country').value && APP.IMG_UPLOADER.Uploader.metadata().addCustomField('country', $('country').value);
						$('searchstring').value && APP.IMG_UPLOADER.Uploader.metadata().addCustomField('searchstring', $('searchstring').value);
						$('item_group').value && APP.IMG_UPLOADER.Uploader.metadata().addCustomField('item_group', $('item_group').value);
						$('item').value && APP.IMG_UPLOADER.Uploader.metadata().addCustomField('item', $('item').value);
					}
					else
					{
						$('js_image_error').toggle();
						$('js_error48').toggle();
						return;
					}
					APP.IMG_UPLOADER.Uploader.upload();
				}
				else
				{
					var pic_form = $("newitempicture_form");
					pic_form.setAttribute("SourceAction", pic_form.action);
					pic_form.action="/screenform.php";
					var retval = AjaxForm.run(pic_form,
											  {
												"onfinish":function(response)
												{
													$("newitempicture_form").action=$("newitempicture_form").getAttribute("SourceAction");
													APP.IMG_UPLOADER.afterUpload(response);
												}}, true);
					if(retval)
					{
						pic_form.submit();
					}
				}
			}
		}

		this.beforeUpload = function()
		{
			$('js_image_error', 'js_error35', 'js_error214', 'js_error48').withEach('disappear');
			var has_error = false;

			if(!$('statement_of_origin').checked)
			{
				has_error = true;
				$('js_error35').toggle();
			}

			var oSsgStr = $('searchstring');
			if(oSsgStr.value == ''
				|| oSsgStr.value == $('default_item_query_string').value)
			{
				has_error = true;
				$('js_error214').toggle();
			}

			if (has_error)
			{
				$('js_image_error').toggle();
				COM.WIZARD.Size();
				return false;
			}
			else
			{
				return true;
			}
		}

		this.afterUpload = function(response)
		{
			$('tool_ImageUploader1').innerHTML = '';
			APP.SCREEN.Response('reload', response);
		}
};
function DynScroll_Engine() {
	this.is_loaded = false;
};

DynScroll_Engine.prototype = {

	init:function(settings) {
		this.settings = settings;

		this.cache_auto_scroll = false;

		if (this.settings["elems"]) {
			this.load();
		}
	},

	config:function(property, value) {
		this.settings[property] = value;
	},

	load:function() {
		if (!dynScroll.is_loaded) {
			dynScroll.is_loaded = true;
			dynScroll.run();
		}
	},

	activate_auto_scroll:function(id, alignment){

		if( alignment != "up" &&
			alignment != "down") {
			return;
		}
		this.cache_auto_scroll = window.setInterval("dynScroll."+alignment+"('"+id+"')", 250);
	},

	deactivate_auto_scroll:function() {
		window.clearInterval(this.cache_auto_scroll);
	},

	run:function()	{
		for(var i=0;i<this.settings["elems"].length;i++) {
			if ($(this.settings["elems"][i]["id"]).isElement()) {
				$(this.settings["elems"][i]["id"]).style["position"] = "relative";
				$(this.settings["elems"][i]["id"]).style["overflow"] = "hidden";
				if ($(this.settings["elems"][i]["id"]).hasChildNodes()) {
					var elems = $(this.settings["elems"][i]["id"]).childNodes;
					for(var j=0;j<elems.length;j++) {
						if (elems[j].nodeType == 1) {
							if (!elems[j].offsetHeight) {
								window.setTimeout("dynScroll.run();", 1000);
								break;
							}
							this.settings["elems"][i]["height"] = elems[j].offsetHeight;

							$(this.settings["elems"][i]["id"]).style["height"] = this.settings["elems"][i]["index"]*this.settings["elems"][i]["height"]+"px";
							$(this.settings["elems"][i]["id"]).style["overflow"] = "hidden";
							break;
						}
					}
				}
			}
		}
	},

	up:function(id) {
		var i = this.get_elem(id);

		if (i >= 0) {
			with($(id)) {
				scrollTop -= this.settings["elems"][i]["height"];

				//call event?
				if(scrollTop == 0) {
					if(this.settings["elems"][i]["barrier_limit"]){
						this.settings["elems"][i]["barrier_limit"]("up");
					}
				}
				else {
					if(this.settings["elems"][i]["change_view_area"])
						this.settings["elems"][i]["change_view_area"]("up");
				}


			}
		}
	},

	down:function(id) {
		var i = this.get_elem(id);
		if (i >= 0) {
			with($(id)) {
				scrollTop += this.settings["elems"][i]["height"];

				//call event?
				var elems = $(this.settings["elems"][i]["id"]).childNodes;
				var max_bottom = elems.length - 1 - this.settings["elems"][i]["index"];
				if(scrollTop == this.settings["elems"][i]["height"] * max_bottom) {
					if(this.settings["elems"][i]["barrier_limit"]){
						this.settings["elems"][i]["barrier_limit"]("down");
					}
				}
				else {
					if(this.settings["elems"][i]["change_view_area"])
						this.settings["elems"][i]["change_view_area"]("down");
				}

			}
		}
	},

	reset:function(id) {
		if(!this.settings) {
			this.init({"elems":[]});
		}
		for(var i=0; i<this.settings["elems"].length; i++) {
			if (	(	id &&
						this.settings["elems"][i]["id"] == id	) ||
					!id		)
			$(this.settings["elems"][i]["id"]).scrollTop = 0;
		}
	},

	get_elem:function(id) {
		for(var i=0;i<this.settings["elems"].length;i++) {
			if (this.settings["elems"][i]["id"] == id)
				return i;
		}
		return -1;
	}

}
if (!self.sources)
	self.sources = new Array();
if (!self.types)
	self.types = new Array();

function populate_extref_source()
{
	var languagebox= document.forms["extrefrating_form"].extref_language;
	var language   = languagebox.options[languagebox.selectedIndex].value;

	if (!language) {
		return;
	}

	if ($("js_select_extref_online")) {
		var onlinebox= document.forms["extrefrating_form"].extref_online;
		var online   = onlinebox.options[onlinebox.selectedIndex].value;

	} else {

		var online = 1;
	}

	var extrefsourcebox= document.forms["extrefrating_form"].extref_source;
	var extreftypebox  = document.forms["extrefrating_form"].extref_type;

	extrefsourcebox.options.length = 0;
	extreftypebox.options.length   = 0;

	var j = 0;
	var lastsource = 0;
	extrefsourcebox.options[j] = new Option("--Elige una opciÃ³n", "");
	j++;

	for(i=0; i<sources.length; i++) {
		if (sources[i][2] == language && sources[i][6] == online) {
			if (sources[i][1] != lastsource) {
				if (j > 0) {
					extrefsourcebox.options[j] = new Option(" "," ");
					j++;
				}
				extrefsourcebox.options[j] = new Option("<-- " + sources[i][4] + " -->","");
				j++;
			}
			extrefsourcebox.options[j] = new Option(sources[i][3],sources[i][0]);
			j++;
			lastsource = sources[i][1];
		}
	}
//	COM.WIZARD.Size();
}

function populate_extref_type()
{
	var extrefsourcebox = document.forms["extrefrating_form"].extref_source;
	var extrefsource = extrefsourcebox.options[extrefsourcebox.selectedIndex].value;
	if(!extrefsource) {
		return;
	}

	var extreftypebox = document.forms["extrefrating_form"].extref_type;
	extreftypebox.options.length = 0;
	var j = 0;

	for(i=0; i<types.length; i++) {
		if (types[i][0] == extrefsource) {
			extreftypebox.options[j] = new Option(types[i][2],types[i][1]);
			j++;
		}
	}

	if(extreftypebox.value == '') {
		$("js_extr_type").style.display= 'none';
	}

	COM.WIZARD.Size();
}

function showExtrefLink()
{
	if ($("js_select_extref_online")) {
		var onlinebox = document.forms["extrefrating_form"].extref_online;
		var online = onlinebox.options[onlinebox.selectedIndex].value;
	} else {
		var online = 1;
	}

	if (online == 1)
		$("js_extref_link_box").appear();
	else
		$("js_extref_link_box").disappear();
	COM.WIZARD.Size();
}

function init_extrefrating()
{
	var languagebox = document.forms["extrefrating_form"].extref_language;
	var language = 'es';

	for(var i = 0; i < languagebox.length; i++) {
		if(languagebox.options[i].value == language) {
			languagebox.options[i].selected=true;
			break;
		}
	}
	populate_extref_source();
	var extrefsourcebox = document.forms["extrefrating_form"].extref_source;
	var extreftypebox = document.forms["extrefrating_form"].extref_type;
	var default_type = $("default_type").value;
	var default_extref_source = $("default_extref_source").value;

	for(var i = 0; i < extrefsourcebox.length; i++) {
		if(extrefsourcebox.options[i].value == default_extref_source) {
			extrefsourcebox.options[i].selected=true;
			break;
		}
	}

	populate_extref_type();

	for(var i=0; i<extreftypebox.length; i++) {
		if(extreftypebox.options[i].value == default_type) {
			extreftypebox.options[i].selected=true;
			break;
		}
	}

	showExtrefLink();
}//
// geopicker using APP.MAPS
//
// @param (object) S - settings object for geopicker
//
// @author crankers
// @since 15.07.2011
// @todo (crankers 15.07.2011) describe settings object
// @todo (crankers 15.07.2011) complete comments
//
APP.GEOPICK = new function()
{

	//
	// private vars
	//
	//  S - settings object
	//
	var S = {'id':'geopicker'};

	//
	// Add configuration to object and loads map scripts data.
	// When map is supposed to be open init it.
	// Use of function is public.
	//
	// @author crankers
	// @since 15.07.2011
	//
	this.Set = function(s)
	{
		var id = S['id'];
		S = s;
		S['id'] = id;
		S['init'] = false;

		APP.RUN.Exe('trivago.map', {'onfinish':function(){
			APP.MAPS.Geo({});
			APP.MAPS.Map({
				'id':S['id']+'map',
				'dfn':S['dfn'],
				'onfinish':function(){
					S['open'] && APP.GEOPICK.Map();
				}
			});
		}});
		
		return true;
	};

	//
	// Show map and add click event when open first time.
	// Switch visibility of map container. 
	// Use of function is public.
	//
	// @author crankers
	// @since 15.07.2011
	//
	this.Map = function()
	{
		if (	S['open'] == true ||
				$(S['id']).getStyle('display') == 'none'	)
		{
			$(S['id']).appear();
			S['open'] = false;
			
			if (S['init'] == false)
			{
				S['init'] = true;
				M = APP.MAPS.Map(S['id']+'map').Map();
				google.maps.event.addListener(M, 'click', function(p){
					var m = [{
								'id':'geo',
								'type':'default',
								'center':true,
								'visibility':true,
								'animate':false,
								'latitude':p.latLng.lat(),
								'longitude':p.latLng.lng(),
								'title':($('name_lang').isElement() ? $('name_lang').value : $('basename').value),
								'description':($('name_lang').isElement() ? $('name_lang').value : $('basename').value)+'<br />'+$('address').value+'<br />'+' '+S['path_name']
							}];
					
					$('geo_flag').value = 6;
					$('lat').value = p.latLng.lat();
					$('lon').value = p.latLng.lng();
					
					M = APP.MAPS.Map(S['id']+'map');
					M.Reset();
					M.Marker(m);
					M.ShowMarkers();
				});
				
				$('lat').addEvent('blur', function(){APP.GEOPICK.Marker('4');});
				$('lon').addEvent('blur', function(){APP.GEOPICK.Marker('4');});
				
				this.Marker();
			}
		}
		else if (!S['open'])
		{
			$(S['id']).disappear();
		}
	};

	//
	// Set Marker. Could be used with given marker m or with interal stored settings.
	// Status is optional. In default way one status after another is tried since one
	// matches and marker could be displayed. Depends on given settings an quality given.
	// Use of function is private.
	//
	// @author crankers
	// @since 15.07.2011
	//
	this.Marker = function(s, m)
	{
		(typeof s == 'undefined') && (s = S['status']);
		S['status'] = s;

		if (typeof m == 'undefined')
		{
			m = false;

			switch(S['status'])
			{
				case '0':
					if (	S['item_lat'] &&
							S['item_lon']	)
					{
						m = [{
								'id':'geo',
								'type':'default',
								'center':true,
								'visibility':true,
								'animate':false,
								'latitude':S['item_lat'],
								'longitude':S['item_lon'],
								'title':($('name_lang').isElement() ? $('name_lang').value : $('basename').value),
								'description':($('name_lang').isElement() ? $('name_lang').value : $('basename').value)+'<br />'+$('address').value+'<br />'+' '+S['path_name']
							}];
		            }
		            else
		            {
						return this.Marker('1');
		            }
					break;
	
				case '1':
					if ($('address').value)
					{
						return this.Geo();
		            }
		            else
		            {
						return this.Marker('2');
		            }
					break;

				case '2':
					if (	S['path_lat'] &&
							S['path_lon']	)
					{
						m = [{
								'id':'geo',
								'type':'default',
								'center':true,
								'visibility':true,
								'animate':false,
								'latitude':S['path_lat'],
								'longitude':S['path_lon'],
								'title':S['path_name'],
								'description':'No hemos podido encontrar ni la direcciÃ³n ni la ciudad. TÃº mismo tambiÃ©n puedes pinchar en el mapa  y localizar el lugar.'
							}];
						$('geo_flag').value = 5;
						S['status'] = '0';
		            }
		            else
		            {
						return this.Marker('3');
		            }
					break;

				case '3':
					return APP.MAPS.Geo().request({'address':S['path_name'], 'onfinish':function(r){
							if (r === null)
							{
								return false;
							}
		
							var m = [{
										'id':'geo',
										'type':'default',
										'center':true,
										'visibility':true,
										'animate':false,
										'latitude':r.geometry.location.lat(),
										'longitude':r.geometry.location.lng(),
										'title':'Ciudad: '+S['path_name'],
										'description':'Ciudad: '+S['path_name']
									}];

							$('geo_flag').value = 5;
							$('lat').value = r.geometry.location.lat();
							$('lon').value = r.geometry.location.lng();

							return APP.GEOPICK.Marker('0', m);
						}});
					break;
				
				case '4':
					$('geo_flag').value = 6;
					m = [{
							'id':'geo',
							'type':'default',
							'center':true,
							'visibility':true,
							'animate':false,
							'latitude':$('lat').value,
							'longitude':$('lon').value,
							'title':($('name_lang').isElement() ? $('name_lang').value : $('basename').value),
							'description':($('name_lang').isElement() ? $('name_lang').value : $('basename').value)+'<br />'+$('address').value+'<br />'+' '+S['path_name']
						}];
					
					break;

			}
		}

		if (m)
		{
			M = APP.MAPS.Map(S['id']+'map');
			M.Reset();
			M.Marker(m);
			M.ShowMarkers();
		}
	};

	//
	// Geocode request to set marker by given address in edit form.
	// Calls Marker method with result. 
	// Use of function is private.
	//
	// @author crankers
	// @since 15.07.2011
	//
	this.Geo = function()
	{
		if ($('address').value)
		{
			return APP.MAPS.Geo().request({'address':$('address').value+', '+( $('city').value?$('city').value:S['path_name'] ), 'onfinish':function(r){
					if (r === null)
					{
						S['item_geo_flag'] && ($('geo_flag').value = S['item_geo_flag']);
						return APP.GEOPICK.Marker('0');
					}

					var m = [{
								'id':'geo',
								'type':'default',
								'center':true,
								'visibility':true,
								'animate':false,
								'latitude':r.geometry.location.lat(),
								'longitude':r.geometry.location.lng(),
								'title':($('name_lang').isElement() ? $('name_lang').value : $('basename').value),
								'description':($('name_lang').isElement() ? $('name_lang').value : $('basename').value)+'<br />'+$('address').value+'<br />'+' '+S['path_name']
							}];

					$('geo_flag').value = 2;
					$('lat').value = r.geometry.location.lat();
					$('lon').value = r.geometry.location.lng();

					return APP.GEOPICK.Marker('0', m);
				}});
		}
		
		return false;
	};

};//
// object picker using APP.MAPS, used in content forms to select path and / or item
//
// @param (object) S - settings object for object picker
//
// @author crankers
// @since 10.08.2011
//
APP.OBJECTPICK = new function()
{

	//
	// private vars
	//
	//  S - settings object
	//      'map': identifier for map element, can't be changed
	//      'open': state of map
	//      'type': pagetype of loaded object instance
	//      'rpc': link to the map definition file
	//  M - internal map reference APP.MAPS.MAP
	//  D - stored marker data
	//  I - internal selected item
	//  P - internal selected path
	//  T - timeout id for search requests in input field
	//  X - current ajax request
	//
	var S = {	'map':'pathmap',
				'open':false,
				'type':'',
				'rpc':''	},
		M = null,
		D = null,
		I = null,
		P = null,
		T = null,
		X = null;

	//
	// Add configuration to object and loads map scripts data.
	// When map is supposed to be open init it.
	// Use of function is public.
	//
	// @author crankers
	// @since 10.08.2011
	//
	// @return void
	//
	this.Set = function(s)
	{
		(typeof s['open'] == 'undefined') || (S['open'] = s['open']);
		(typeof s['type'] == 'undefined') || (S['type'] = s['type']);
		(typeof s['rpc'] == 'undefined') || (S['rpc'] = s['rpc']);

		if (APP.SCREEN.IsScreen($('main_box')))
		{
			APP.WIZ.Reg('onclose', function() {
				APP.OBJECTPICK.Shutdown();
			});
		}

		APP.RUN.Exe('trivago.map', {'onfinish':function(){
			APP.MAPS.Map({
				'id':S['map'],
				'dfn':S['rpc']+'&action=map_dfn&id='+S['map']+'&map='+S['type'],
				'onfinish':function(){
					l = S['open'];
					S['open'] = !S['open'];
					APP.OBJECTPICK.Map(l);
				}
			});
		}});
		
		return true;
	};

	//
	// Shutdown Module to its default and stop all current actions like running requests.
	// Reset settings to initial state. Use of function is public.
	//
	// @author crankers
	// @since 30.08.2011
	//
	// @return void
	//
	this.Shutdown = function()
	{
		M && M.Listener() && M.Listener().Deactivate();
		M && APP.MAPS.Destroy('map', S['map']);
		X && X.abort();
		M = D = I = P = T = X = null;
	};	

	//
	// Show map and add click event when open first time. Switch visibility of map container.
	// Map can be touched or (l)oading elements only can be used. 
	// Use of function is public.
	//
	// @author crankers
	// @since 12.08.2011
	//
	// @return void
	//
	this.Map = function(l)
	{
		(typeof l == 'undefined') && (l = true);
		
		// map is already open, close it
		if (S['open'])
		{
			S['open'] = false;
			
			if ($('js_display_map_1').isElement())
			{
				$('main_box', 'js_display_map_1').withEach('disappear');
			}
			else
			{
				$('main_box').appear();
			}

			$('js_display_map_2').isElement() && $('js_display_map_2').appear();

			l && M && M.Listener().Deactivate();
		}
		// map is closed, open it
		else
		{
			S['open'] = true;
			
			if ($('js_display_map_1').isElement())
			{
				$('main_box', 'js_display_map_1').withEach('appear');
			}
			else
			{
				$('main_box').appear();
			}
	
			$('js_display_map_2').isElement() && $('js_display_map_2').disappear();
			
			if (l)
			{
				if (!M)
				{
					M = APP.MAPS.Map(S['map']);
					if (D)
					{
						M.Marker(D);
						M.ShowMarkers(null, true);
					}

					var m = M.Map();
					google.maps.event.addListenerOnce(
						m,
						'tilesloaded',
						function()
						{
							M.Listen({
									'move':function(){APP.OBJECTPICK.Update(true);},
									'zoom':function(){APP.OBJECTPICK.Update(true);}
							});
						}
					);
				}
				else if (D)
				{
					this.Marker(D);
				}
			}
		}

		COM.WIZARD.Size();
	};

	//
	// Add (m)arker data. When map is not initialized marker data is only stored until
	// map opening is called. Second parameter defines if map is (f)lexible or not. Only
	// takes effect, when a map already exists, otherwise map is not fixed.
	// Use of function is private.
	//
	// @author crankers
	// @since 12.08.2011
	//
	// @return void
	//
	this.Marker = function(m, f)
	{
		(typeof f == 'undefined') && (f = true);
		D = m;

		if (S['open'] && M)
		{
			M.Listener() && M.Listener().Deactivate();
			M.Reset();
			M.Marker(D);
			M.ShowMarkers(null, f);
			M.Listen({
					'move':function(){APP.OBJECTPICK.Update(true);},
					'zoom':function(){APP.OBJECTPICK.Update(true);}
			});
			D = null;
		}
	};

	//
	// Show scrollable item lists for attractions and hotels.
	// Use of function is private.
	//
	// @author crankers
	// @since 12.08.2011
	//
	// @return void
	//
	this.ShowItems = function()
	{
		$('js_show_items').disappear();
		$('js_item_part').appear();

		self.dynScroll = new DynScroll_Engine();
		self.dynScroll.init({'elems':[{'id':'fp_hotel_list','index':'6'},{'id':'fp_attraction_list','index':'6'}]});

		COM.WIZARD.Size();
	};

	//
	// Mark new (i)tem as selected and store (u)rl on button.
	// Use of function is public.
	//
	// @author crankers
	// @since 12.08.2011
	//
	// @param integer i, item id
	// @param string u, url to set
	//
	// @return void
	//
	this.SetItem = function(i, u)
	{
		if ($('js_set_item').isElement())
		{
			$('fp_set_item').appear();
	
			if (I && $('js_item_'+I))
			{
				$('js_item_'+I).delClass = 'selected';
			}
	
			$('js_item_'+i).addClass = 'selected';
			$('js_set_item').setAttribute('href', u);
	
			I = i;
			COM.WIZARD.Size();
		}
	};

	//
	// Reset marked item and remove link.
	// Use of function is public.
	//
	// @author crankers
	// @since 12.08.2011
	//
	// @return void
	//
	this.ResetItem = function()
	{
		I = null;
		if ($('js_set_item').isElement())
		{
			$('fp_set_item').disappear();
			$('js_set_item').setAttribute('href', 'javascript:void(0);');
			COM.WIZARD.Size();
		}
	};

	//
	// Execute search request to given (s)string after certain timelimit. Only when user finished
	// his input send request. Therefore we use that loop way with timeout.
	// Use of function is public.
	//
	// @author crankers
	// @since 12.08.2011
	//
	// @param s
	//
	// @return void
	//
	this.Search = function(s)
	{
		if (	s.length > 2 ||
		    	s.length == 0	)
		{
		    (T > 0) && window.clearTimeout(T);

		    T = window.setTimeout(function(){
		    	APP.OBJECTPICK.SearchRequest(s);
		    }, 500);
		}
	};

	//
	// Execute search request to given (s)string. This method is only called with timeout from method Search.
	// Use of function is private.
	//
	// @author crankers
	// @since 12.08.2011
	//
	// @param s
	//
	// @return void
	//
	this.SearchRequest = function(s)
	{
		id = document.forms['fp_region_form']['path'].value;
		
		X && X.abort();
		X = new COM.HTTP.Request('GET', S['rpc']+'&action=mini_search&q='+escape(s)+'&id='+S['type']+( (id)?'&path='+id:'' ), {
			'onfinish':function(r) {
				var n = COM.Element(['div', {}]);
				n.innerHTML = r;

				self.dynScroll && self.dynScroll.reset();
				APP.OBJECTPICK.ResetItem();

				APP.OBJECTPICK.Response(n);				
				APP.InnerExec(r);
				
				M && M.HideLoader();
				COM.WIZARD.Size();
			}
		});
		X.start();
	};

	//
	// Handle Response where fragments are loaded to update content.
	// Use of function is private.
	//
	// @author crankers
	// @since 12.08.2011
	//
	// @param (DOMNode) n, node element
	//
	// @return (boolean)
	//
	this.Response = function(n)
	{
		var e = n.childNodes;
		for(var i=0;i<e.length;i++)
		{
			if (e[i].hasChildNodes())
			{
				this.Response(e[i]);
			}
			if (e[i].nodeType == 1)
			{
		  		if (	$(e[i]).hasClass('dyn_path') &&
		  				e[i].getAttribute('id')	)
		  		{
					$(e[i].getAttribute('id')).innerHTML = e[i].innerHTML;
		 	  	}
			}
		}
		
		return true;
	};

	//
	// Show markers with given bounds when requested otherwise show current request.
	// The (r)equest argument contains a path id or true to use the current map bounds.
	// Use of function is public.
	//
	// @author crankers
	// @since 12.08.2011
	//
	// @param (boolean)|(integer) r, path id or boolean to use map bounds
	//
	// @return (boolean)
	//
	this.Update = function(r)
	{
		P = (r === true)? document.forms['fp_region_form']['path'].value
					  	: r;

	  	var q = '';
	  	if (r === true)
	  	{
	  		q = '&latw='+M.Map().getBounds().getSouthWest().lat()+'&late='+M.Map().getBounds().getNorthEast().lat()+'&lngn='+M.Map().getBounds().getSouthWest().lng()+'&lngs='+M.Map().getBounds().getNorthEast().lng();
	  	}

		M && M.ShowLoader();
	  	M && M.Listener() && M.Listener().Deactivate();

		X && X.abort();
		X = new COM.HTTP.Request('GET', S['rpc']+'&action=form_path&id='+S['type']+'&path='+P+q, {
			'onfinish':function(r) {
				var n = COM.Element(['div', {}]);
				n.innerHTML = r;

				self.dynScroll && self.dynScroll.reset();
				APP.OBJECTPICK.ResetItem();
				
				APP.OBJECTPICK.Response(n);
				APP.InnerExec(r);
				
				M && M.HideLoader();
				COM.WIZARD.Size();
			}
		});
		X.start();
	};

	//
	// Executed given event and route to map when existing internal
	// Use of function is public.
	//
	// @author crankers
	// @since 15.08.2011
	//
	// @param (string) e, event type
	// @param (string) id
	//
	// @return (boolean)
	//
	this.Event = function(e, id)
	{
		M && M.MarkerEvent(e, id);
		return true;
	};

};APP.AUTHENTICATION = new function()
{
	//
	//
	//

	this.ExistsLogin = function(login, min_length, max_length)
	{
		if ($('authentication_2').checked==false)
		{
			if (login.length < min_length || login.length > max_length)
			{
				$('login').className = "text locked";
			}
			else
			{
				COM.HTTP.Get("/trivago_rpc.php?login=" + encodeURIComponent(login) + "&action=get_login_exists",{"onfinish":function(r) {if(r == 1) $('login').className = "text locked"; else $('login').className = "text";}});
			}
		}
		else
		{
			$('login').className = "text";
		}
	}
	
	//
	//
	//

	this.ChangeAuthentication = function(type, delay)
	{
		if (typeof delay == "undefined")
		{
			window.setTimeout("APP.AUTHENTICATION.ChangeAuthentication('" + type + "', 1);", 10);
			return;
		}

		switch (type)
		{
			case 'register':
				$('js_authentication_register').className = 'tab';
				$('js_authentication_login').className = 'tab nonactive';
				$('agree_agb','js_fields_register','hgw_register').withEach('appear');
				$('hgw_login').disappear();
				break;
			
			case 'login':
			default:
				$('js_authentication_register').className = 'tab nonactive';
				$('js_authentication_login').className = 'tab';
				$('agree_agb','js_fields_register','js_field_pass_rep','js_field_confirm_email','hgw_register').withEach('disappear');
				$('hgw_login').appear();
				$('login').className = 'text';
				break;
		}

		COM.WIZARD.Size();
		$("login").focus();
	}
};
APP.FORM.RATES = new function()
{

	//
	//
	//

	this.MouseOver = function(name, value)
	{
		var img_number,
			node_title = $('titel'),
			node_preview = $(name + '_preview'),
			node_preview_string = $(name + '_preview_string');
		
		value = value / 1000;

		for(var i=1; i<=10; i++)
		{
			node_array[i] = $(name+'_'+i);
			hover_tmp[name+'_'+i] = node_array[i].getClass();
			img_number = value % 2 == 0 ? value : value+1;

			if(i <= value)
			{
				node_array[i].setClass('rate_img sprite_icon value' + Math.ceil(img_number/2));

				if(node_preview.isElement())
				{
					if (node_title && (node_preview_string.innerHTML == node_title.value))
					{
						node_title.value = self.stringtable[ value ];
					}
					node_preview.src = this.getRadioButtonImg('form/' + value + '.png');
				}
				if (node_preview_string.isElement())
				{
					node_preview_string.innerHTML = self.stringtable[ (value == -1) ? 0 : value ];
				}
				self.stringtable && this.setTitle( self.stringtable[ value ]);
			}
			else
			{
				node_array[i].setClass('rate_img sprite_icon value0');
			}
		}
	}
	
	//
	//
	//

	this.MouseOut = function(name, value)
	{
		var img_number,
			node_title = $('titel'),
			node_preview = $(name + '_preview'),
			node_preview_string = $(name + '_preview_string');
		
		value = value / 1000;

		for(var i=1; i<=10; i++)
		{
			$(name + '_' + i).setClass(hover_tmp[ name + '_' + i ]);
		}

		(typeof LastSelectNo[name] == 'undefined') && (LastSelectNo[name] = 0); 
		if (node_preview.isElement())
		{
			if (node_title && (node_preview_string.innerHTML == node_title.value))
			{
				node_title.value = self.stringtable[ LastSelectNo[name] ];
			}
			node_preview.src = this.getRadioButtonImg('form/' + LastSelectNo[name] + '.png');
		}
		if (node_preview_string.isElement())
		{
			node_preview_string.innerHTML = self.stringtable[ (LastSelectNo[name] == -1) ? 0 : LastSelectNo[name] ];
		}
		self.stringtable && this.setTitle( self.stringtable[ LastSelectNo[name] ]);
	}
	
	//
	//
	//

	this.Set = function(name, src, value, obj)
	{
		value = value / 1000;
		var img_checked_no = value % 2 == 0 ? value : value+1;
	    var img_normal_no  = (img_checked_no == 0) ? 2 : img_checked_no,
	    	node_preview   = $(name + '_preview');

	    LastSelectNo[name] = value;

		for(var i=1; i<=10; i++)
		{
			if($(name + '_' + i).isElement())
			{
				hover_tmp[name+'_'+i] = 'rate_img sprite_icon value0';
				$(name+'_'+i).setClass(hover_tmp[name+'_'+i]);
			}
		}

		if($(name + '_-1').isElement())
		{
			hover_tmp[name+'_-1'] = 'rate_img sprite_icon value1';
			$(name + '_-1').setClass(hover_tmp[name+'_-1']);
		}

		for(var i=1; i<=value; i++)
		{
			if($(name + '_' + i).isElement())
			{
				hover_tmp[name+'_'+i] = 'rate_img sprite_icon value' + Math.ceil(img_checked_no/2);
				$(name + '_' + i).setClass(hover_tmp[name+'_'+i]);
			}
		}

		if ($( name ).isElement())
		{
			$( name ).value = value * 1000;
		}

		self.stringtable && this.setTitle( self.stringtable[ value ]);

		if(node_preview.isElement())
		{
			node_preview.src = this.getRadioButtonImg('form/' + Math.ceil(value) + '.png');
		}
		
		if(typeof obj != 'undefined')
		{
			var onfinish_evt = obj.getAttribute('onfinish');
			if(onfinish_evt)
			{
				window.setTimeout(onfinish_evt + '();', 10);
			}
		}
	}

	//
	// opinion form set title
	//
	
	this.setTitle = function(s)
	{
		var form = document.forms['newopinion_form'];
		if (	form &&
				form['titel'] &&
				form['titel'].defaultValue == form['titel'].value	)
		{
			form['titel'].defaultValue = form['titel'].value = s;
		}
	}
	
	//
	// need for the trivi - images
	//
	
	this.getRadioButtonImg = function(path)
	{
		return "http://il1.trivago.com/images/layoutimages/" + path + "";
	}
	
	//
	//
	//
	
	this.setSmallPreviewRating = function(newvalue, key)
	{
		var value = Math.round((newvalue/1000) ? newvalue/1000 : '0') * 1000;
		
		this.Set('headerPreview_'+key, '', value);
	}

	//
	// private vars
	//
	var node_array   = new Array(),
		hover_tmp    = new Array(),
		LastSelectNo = [];
}
APP.RUN.Call("trivago.base");

