﻿(function($, undefined){
  $.fn.geoimagemap = function(options) {
    var
    mapidcounter = 0, 
    id = "geoimagemap", 
    data = options.data,
    text = languagetext.search.imagemap;
  
    function getImageNode(node, ids) {
      var nodes = node.nodes;
      if(nodes && ids) {
        for(var i in nodes) {
          var n = nodes[i];
          if(ids[n.id] && n.image)
            return getImageNode(n, ids);
        }
      }
      return node;
    }
    
    return this
      .empty()
      .append($("<img/>"))
      .bind("click.feline",function(){
        var
        $this = $(this),
        ids = $this.data("ids"),
        node = getImageNode(data,ids),
        $map=$("<map name='" + id + "map' id='" + id + "map'></map>"),
        $img=$("<img usemap='#" + id + "map'/>"),
        $ok=$("<input type='button' name='ok' value='" + text.ok + "'/>")
          .bind("click.feline",function(){
            var ids = [];
            $fieldset.find("select").each(function(e){
               var val = $(this).val();
               if(val) ids.push(val);
            });
            $.fn.colorbox.close();
            $this.trigger("selected.feline", [ids]);
          }),
        $cancel=$("<input type='button' name='cancel' value='" + text.cancel + "'/>").bind("click.feline",function(){$.fn.colorbox.close();return false;}),
        $fieldset=$("<fieldset class='content'/>")
          .append($("<div class='buttons'/>")
            .append($cancel)
            .append($ok)
          ),
        $geoimagemap=$("<div class='popup popupnarrow' id='" + id + "'/>")
          .append($("<div class='container'/>")
            .append($("<h1>" + text.header + "</h1>"))
            .append($("<a href='#' class='close'>" + text.close + "</a>").bind("click.feline",function(){$.fn.colorbox.close();return false;}))
            .append($("<div class='header'/>"))
            .append($("<div class='outer selmapouter'>")
              .append($img)
              .append($fieldset)
            )
            .append($("<div class='popupfooter'/>"))
          )
          .bind("update.feline", function(e, ids){
            var
            mapareas = [],
            mapid = (id + "map"+ (mapidcounter++)),
            index = 0,
            $this = $(this),
            image = '',
            areas=null,
            level=-1;
            $select = $(this).find("select").first();

            function traverseNodes(node) {
              if(!node) return;
              var 
              nodes = node.nodes
              n = null;
              
              if(node.image) {
                if(node.imagetype!=1) {
                  level++;
                  areas = nodes;
                }
                image = node.image;
              }
              if(nodes && ids) {
                var 
                $dropdown = $("<select/>")
                
                $dropdown.prepend($("<option value=''>" + options.labels[index].label + "</option>"));
                
                $each(node.nodes,function(a,b){
                  //if(b.image){
                  if(b.type!=2) {
                    $dropdown.append($("<option value='" + b.id + "'" + (ids[b.id]?" selected='selected'":"") + ">" + b.name + "</option>"));
                    if(ids[b.id]) n = b;
                  }
                  //}

                });
                if($dropdown.children().length>1) {
                  if(!$select.length) {
                    $fieldset.append($dropdown);
                  } else if($select.html()!=$dropdown.html()) {
                    $select.nextAll().remove();
                    $select.replaceWith($dropdown);
                  }
                } else {
                  $select.nextAll().andSelf().remove();
                }
                $select = $select.next();
                index++;
                traverseNodes(n);
              }
            }
            
            traverseNodes(data);

            $select.nextAll().andSelf().remove();
            
            $this.find("map").remove();  
            if(areas) {
              $each(areas, function(i, n){
                if(n.image){
                  mapareas.push("<area href='#" + n.id + "' shape='poly' coords='" + n.coords + "' alt='" + n.name + "' title='" + n.name + "'/>");
                }              
              });
            }
            $("<map id='" + mapid + "' name='" + mapid + "'>" + mapareas.join("") + "</map>")
              .bind("click", function(e) {
                e.target.blur();
                $fieldset.find("select").eq(level).nextAll().remove().end().val($(e.target).attr("href").substring(1)).trigger("change.feline");return false;
              })
              .appendTo($this.find(".outer"))
            $this.find("img").attr({src:image,usemap:"#" + mapid}); 
          })
          .prependTo("#temp");
        
        $fieldset.bind("change.feline",function() {
          var ids = {};
          $(this).find("select").each(function(e){
            var val = $(this).val();
            if(val) ids[val] = true;
            return this!=e.target;
          });
          $geoimagemap.trigger("update.feline",[ids]);
          return false;
        });
          
        $geoimagemap.data("source", $this);

        $geoimagemap.trigger("update.feline", [ids]);
                
        $.fn.colorbox({height:485,width:340,open:true, inline:true, href:"#"+id, onClosed:function(){$("#"+id).remove();}});
        
        return false;
      })
      .bind("update.feline",function(e, ids) {
        var 
        $this=$(this),
        node = getImageNode(data,ids);
        
        $this.find("img").attr("src", node.image);
        $this.data("ids", ids);
      }).trigger("update.feline",[options.ids]);
  };

  $.fn.felineDatePicker = function(options) {
    return this
      .datePicker(options)
      .bind("dpDisplayed.feline", function(e, div) {
        var $div = $(div);
        $div.children(":not(iframe):lt(3)").wrapAll("<div class='dp-top'></div>");
        $div.find(".dp-top").wrap("<div class='dp-topouter'></div>");
        $div.find(".dp-calendar").wrap("<div class='dp-calendarouter'></div>");
        $div.append("<div class='dp-bottom'></div>");
      })
      .bind("dpMonthChanged.feline dpDisplayed.feline", function() {
        var 
        dp = $.event._dpCache[this._dpId],
        $popup = $(dp.context),
        currentMonth = new Date(dp.displayedYear, dp.displayedMonth, 1),
        minMonth = (new Date(currentMonth.getTime())).addYears(-2),
        maxMonth = (new Date(currentMonth.getTime())).addYears(2),
        startMonth = new Date(dp.startDate.getFullYear(), dp.startDate.getMonth(), 1),
        endMonth = new Date(dp.endDate.getFullYear(), dp.endDate.getMonth(), 1),
        $months = $("<select/>");
        
        if(startMonth<minMonth) startMonth = minMonth;
        if(endMonth>maxMonth) endMonth = maxMonth;
                       
        while(startMonth<=endMonth) {
          $("<option" + ((startMonth.getMonth() == dp.displayedMonth && startMonth.getFullYear() == dp.displayedYear) ? " selected='selected'" : "") + ">" + startMonth.getMonthName() + " " + startMonth.getFullYear() + "</option>").appendTo($months).data("date", new Date(startMonth.getTime()));
          startMonth.addMonths(1);
        }

        $months.bind("change.feline",function() {
          var 
          $this = $(this),
          date = $this.find("option:selected").data("date");
          $(dp.ele).dpSetDisplayedMonth(date.getMonth(), date.getFullYear());
        });
                       
        $popup.find(".jCalendar").attr({cellspacing: 0, cellpadding: 0 });
        $popup.find(".dp-top h2").empty().append($months);
      });
  }

  function isoWeekNumber(da)
  {
    function dw(da) {
      var r = da.getDay()-1;
      return r < 0 ? 7 : r;
    }

    var 
    y = parseInt(da.getFullYear()),
    m = parseInt(da.getMonth()),
    d = parseInt(da.getDate()),
    dow = dw(da),
    dow0101 = dw(new Date(y, 0, 1));

    if( m == 0  &&  3 < dow0101 < 7 - (d-1) ){
      dow     = dow0101 - 1;
      dow0101 = dw(new Date(y-1, 0, 1));
      m       = 11;
      d       = 31;
    }
    else if ( m == 11  &&  30 - (d-1) < dw(new Date(y+1, 0, 1)) && dw(new Date(y+1, 0, 1)) < 4 )
    {
      return 1;
    }
    return parseInt(( dw(new Date(y, 0, 1)) < 4 ) + 4 * m + ( 2 * m + (d-1) + dow0101 - dow + 6 ) * 36 / 256);
  }

  function parseDate(v){
    var tests = [
      (/^(\d{2})(\d{2})((?:\d{2}){0,2})$/),
      (/^(\d{1,2})\/(\d{1,2})(?:\/((?:\d{2}){1,2}))?$/),
      (/^(\d{1,2})-(\d{1,2})(?:-((?:\d{2}){1,2}))?$/),
      (/^(\d{1,2})\/(\d{1,2})-((?:\d{2}){1,2})$/)];
                          
    var date = null;
    $each(tests, function(index, item){
      var match = item.exec(v);
      if(match) {
        var d = Number(match[1]);
        var m = Number(match[2])-1;
        var y = match[3].length == 4 ? Number(match[3]) : (match[3].length == 2 ? Number(Date.fullYearStart + match[3]) : (new Date()).getFullYear()); 
        td = new Date(0);
        td.setFullYear(y,m,d);
        if(d == td.getDate() && m == td.getMonth() && y == td.getFullYear()) {
          date = td;
        }
      }
    });
    return date;
  }

  function createLookup(source) {
    var lookup = {};
    $each(source,function(){
      lookup[this]=true;
    });
    return lookup;
  }
    
  function replaceTld(domain) {
    var tld = location.hostname.substring(location.hostname.lastIndexOf(".")).toLowerCase();
    if ($.inArray(tld, debugTlds) != -1) 
      return domain + tld; 
    return domain;
  }
  
  function getSld() {
    var hostname = location.hostname;
    var tmpHostname = hostname.replace(".co.uk",".co_uk");
    var tld = location.hostname.substring(location.hostname.lastIndexOf(".")).toLowerCase();
    var searchPosStart = hostname.length-1;
    if ($.inArray(tld, debugTlds) != -1) searchPosStart -= tld.length;
    return hostname.substring(tmpHostname.lastIndexOf(".", tmpHostname.lastIndexOf(".", searchPosStart)-1)+1);
  }
  
  function $cookie(name, value) {
    if(value===undefined) {
      var value = $.cookie(name);
      return (value ? value : {});
    } else {
      $.cookie(name, value, {expires:300,domain:getSld(),path:'/'});
    }
  }
    
  function checkSelectChanged(e) {
    switch(e.type) {
      case "keyup":
        $(e.target).data("_change_data2", e.target.selectedIndex);
        return (e.keyCode == '38' || e.keyCode == '40');
      case "change":
        return (e.target.selectedIndex!=$(e.target).data("_change_data2"));
      case "created":
        return true;
    }
    return false;
  }
  
  function createSection(section, params) {
    var 
    
    checkboxes = section.checkboxes,
    dropdowns = section.dropdowns,
    fields = section.fields,
    
    // create section
    $section = $("<div class='section'/>"),
    
    // create fieldset, append it to section and add a legend
    $fieldset = $("<fieldset/>")
      .appendTo($section)
      .append($("<legend><span>" + section.legend + "</span></legend>"));
   
    // append fields to fieldset 
    if($.isArray(fields)) {
      $.each(fields, function(){
        if(this.hidden) {
          var $hidden = $("<input type='hidden' name='" + this.name + "' id='field" + this.name+ "'" + (params[this.name] ? " value='" + params[this.name] + "'" : "") + "/>");
          $fieldset.append($("<div/>").append($hidden));
        } else if(this.datepicker) {
          var 
          dateMin = parseDate(this.datepicker.min ? params[this.datepicker.min] : null),
          dateMax = parseDate(this.datepicker.max ? params[this.datepicker.max] : null),
          dateValue = parseDate(params[this.name]),
          value = (dateValue && (!dateMin || dateValue >= dateMin) && (!dateMax || dateValue <= dateMax)) ? dateValue.asString("dd-mm-yyyy") : "",
          
          $dp = $("<input type='text' name='" + this.name + "' id='field" + this.name+ "'" + (value ? " value='" + value + "'" : "") + "/>");

          $dp.data("required",this.required);
          $dp.data("label",this.datepicker.label);
          $dp.data("invaliddate",this.datepicker.invaliddate);
          $dp.data("mindatetext",this.datepicker.mindate);
          $dp.data("maxdatetext",this.datepicker.maxdate);
          $dp.data("mindate", dateMin);
          $dp.data("maxdate", dateMax);
          
          $dp.data("_change_data", $dp.val());
          
          $dp.change(function(){
            var dateValue = parseDate($dp.val());
            if(dateValue) {
              $dp.val(dateValue.asString("dd-mm-yyyy"));
              if((dateMin && dateValue<dateMin) || (dateMax && dateValue>dateMax)) {
                $dp.data("isinvalid",true);
              } else {
                $dp.data("isinvalid",false);
              }
            } else {
              $dp.data("isinvalid",true);
            }
          }).bind("focusout.feline",function(){
            if($dp.val()=="") {
              $dp.val($dp.data("label"));
            }
          }).bind("focusin.feline",function(){
            if($dp.val()==$dp.data("label")) {
              $dp.val("");
            }
          }).trigger("focusout.feline");

          $fieldset.append($("<div/>").append($dp));
          $dp.felineDatePicker({ 'horizontalOffset': -167, 'verticalOffset': 21 });
          if(dateMin) $dp.dpSetStartDate(dateMin.asString("dd-mm-yyyy"));
          if(dateMax) $dp.dpSetEndDate(dateMax.asString("dd-mm-yyyy"));
        }
      });
    }
    
    // append checkboxes to fieldset
    if($isArray(checkboxes)) {
      $each(checkboxes, function(){
        $fieldset.append($("<div><input type='checkbox' name='" + this.name + "' id='field" + this.name+ "'" + (params[this.name] ? " checked='checked'" : "") + "/><label for='field" + this.name + "'>" + this.label + "</label></div>"));
      });
    }
    
    // append dropdowns to fieldset
    if($isArray(dropdowns)) {
      $each(dropdowns, function(){
        function appendOptions(options, $dropdown) {
          $each(options, function(){
            var $option = $("<option value='" + this.value + "'" + ((params[name]!="-1" && params[name]==this.value) ? " selected='selected'" : "") + ">" + this.text + "</option>");
            if(this.url) $option.data("url", this.url);
            $dropdown.append($option);
          });
        }
      
        var 
        name = this.name,
        $dropdown = $("<select name='" + name + "' id='field" + name + "'/>");
        $dropdown.data("required", this.required);
        
        if($isArray(this.options)) {
          appendOptions(this.options, $dropdown);
        }
        
        if($isFunction(this.options)) {
          this.options(params, function(options){
            appendOptions(options, $dropdown);
          });
        }
        $dropdown.data("_change_data",$dropdown.get(0).selectedIndex);
        $fieldset.append($("<div/>").append($dropdown));
        
        $dropdown.trigger("fieldcreated");
      });
    }
    
    return $section;
  }
  
  function isSelected(node, geolink) {
    var ret = false;
    if($isArray(node.ids)) {
      $each(node.ids,function(){
        if(geolink[this]) {
          ret = true;
          return false;
        }            
      });
    } else {
      if(geolink[node.id]) {
        ret = true;
      }
    }
    return ret;
  }
  
  function createSelect(nodes, index, label, geolink, index, url, useurl) {
    var
    $select = $("<select name='geo" + index + "' id='fieldgeo" + index + "'/>")
    $option = $("<option value=''>" + label + "</option>").appendTo($select);
    if(useurl && url) $option.data("url", url);
    $each(sortNodes(nodes), function() {
      var $option = $("<option value='" + this.id + "'" + (isSelected(this, geolink) ? " selected='selected'" : "") + ">" + this.name + "</option>").appendTo($select);
      $option.data("nodes", this.nodes);
      if(useurl && this.url) $option.data("url", this.url);
    });
    $select.data("_change_data",$select.get(0).selectedIndex);
    return $select;
  }
  
  function getLocationNodes(nodes) {
    var nodes = filterNodes(nodes,2);
    var unique = {};
    $each(nodes,function(){
      var node = unique[this.name];
      if(!node) {
        node = unique[this.name] = this;
        node.ids = [];
      }
      node.ids.push(this.id);
    });
    var a = [];
    for(var id in unique) {
      a.push(unique[id]);
    }
    return sortNodes(a);
  }
  
  function getAreaNodes(nodes) {
    return sortNodes(filterNodes(nodes,function(node){return node.type!=2}));
  }
  
  function sortNodes(nodes) {
    return nodes.sort(function(a,b){
        if($.isFunction(a.name.localeCompare)) {
          return a.name.localeCompare(b.name);
        }
        else if (a.name<b.name) {
          return -1;
        } else if(a.name<b.name) {
          return 1; 
        } else {
          return 0;
        }
    });
  }

  function filterNodes(nodes, filter) {
    var ret = [];
    if($isArray(nodes)) {
      if($isFunction(filter)) {
        $each(nodes, function(){
          if(filter(this)) {
            ret.push(this);
          }
        });
      } else {
        $each(nodes, function(){
          if(this.type == filter) {
            ret.push(this);
          }
        });
      }
    }
    return ret;
  }

  function getSubnodes(nodes) {
    var ret = [];
    if($isArray(nodes)) {
      $each(nodes, function(){
        ret.push(this)
        $.merge(ret, getSubnodes(this.nodes));
      });
    }
    return ret;
  }

  var 
  TRUE = true,
  FALSE = false,

  $param = $.param,
  $deparam = $.deparam,
  $isArray = $.isArray,
  $isFunction = $.isFunction,
  $each = $.each,
    
  dataname = "felinesearch",
  debugTlds = [".pcmbl",".pcjaj",".pcfch",".pcjkh",".dev01l1"];
  
  domains = [["www.feline.dk","skiferie.feline.dk"], 
             ["www.feline-holidays.de","skiurlaub.feline-holidays.de"],
             ["www.feline-holidays.co.uk","skiholiday.feline-holidays.co.uk"]],
             
  links = [["sommerhuse-ferieboliger/","feriecenter-katalog/","hotel-katalog/","camping-katalog/","skiferie/","sommerhus/lastminute.asp"],
           ["ferienhaus/","ferienpark-katalog/","","camping-katalog/","skiurlaub/","ferienhaeuser/lastminute.asp"],
           ["holiday-home/","holidaycentre-catalogue/","","camping-catalogue/","skiholiday/","holiday-homes/lastminute.asp"]],
  
  names = [["Sommerhuse", "Feriecentre", "Hoteller", "Camping", "Skiferie", "Last Minute"],
           ["Ferienhäuser", "Ferienparks", "Hotels", "Camping", "Skiurlaub", "Last Minute"],
           ["Holiday Homes", "Holiday Centres", "Hotels", "Camping", "Skiing holidays", "Last Minute"]],
           
  legends = ["Ferietype", "Urlaubsform", "Holiday type"],
  
  lang = { da:0, de:1, en:2},
  
  domaintype = [0,0,0,0,1,0],
  
  holidaytype = {fh:0,fc:1,ho:2,ca:3,sk:4,lm:5},
  
  createSelects = [
    function($div, nodes, index, idx, geooptions, geolink, url, useurl) {
      if ($isArray(nodes) && nodes.length) {
        createSelect(nodes, index, geooptions.labels[index].label, geolink, idx, url, useurl)
          .appendTo($div)
          .bind("created change keyup",function(e){
            if(checkSelectChanged(e)) {
              var $this = $(this).nextAll().remove().end();
              var $selected = $this.find(":selected");
              createSelects[geooptions.type]($this.closest("fieldset"), getAreaNodes($selected.data("nodes")), index+1, idx+1, geooptions, geolink, $selected.data("url"), useurl);
            }
          })
          .trigger("created")
          .data("required", geooptions.labels[index].required);
      }
    },
    function($div, nodes, index, idx, type, geolink, url, useurl) {
      if ($isArray(nodes) && nodes.length) {
        var $select = createSelect(nodes, index, geooptions.labels[index].label, geolink, idx, url, useurl).appendTo($div)
        if(index>0) {
        var allNodes = [];
          $.each(nodes,function(){
            if($isArray(this.nodes)) {
              $.merge(allNodes, this.nodes);
            }
          });
          $select.find("option:eq(0)").data("nodes",getAreaNodes(allNodes));
        }
        $select
          .bind("created change keyup",function(e){
            if(checkSelectChanged(e)) {
              var $this = $(this).nextAll().remove().end();
              var $selected = $this.find(":selected");
              createSelects[geooptions.type]($this.closest("fieldset"), getAreaNodes($selected.data("nodes")), index+1, idx+1, geooptions, geolink, $selected.data("url"), useurl);
            }
          })
          .trigger("created")
          .data("required", geooptions.labels[index].required);
      }
    },
    function($div, nodes, index, idx, type, geolink, url, useurl) {
      if ($isArray(nodes) && nodes.length) {
        var $select = createSelect(nodes, index, geooptions.labels[index].label, geolink, idx, url, useurl).appendTo($div);
        $select.find("option:eq(0)").data("nodes", nodes);
        $select
          .bind("created change keyup",function(e){
            if(checkSelectChanged(e)) {
              var $this = $(this).nextAll().remove().end();
              var $selected = $this.find(":selected");
              var nodes = $selected.data("nodes");
              if($selected.val()!="" && getAreaNodes(nodes).length) {
                createSelects[geooptions.type]($this.closest("fieldset"), getAreaNodes(nodes), index+1, idx, geooptions, geolink, $selected.data("url"), useurl);
              } else if(index>0) {
                createSelect(getLocationNodes(getSubnodes(nodes)), 999, geooptions.locationlabel, geolink, 999, $selected.data("url"), useurl)
                  .appendTo($div)
                  .trigger("created")
                  .bind('focusin', function() {
                    $(this).css("width", "auto");
                  })
                  .bind('focusout', function() {
                    $(this).css("width", "138px");
                  });
              }
            }
          })
          .trigger("created")
          .data("required", geooptions.labels[index].required);
      }
    }
  ];

  $.cookie = function(name, value, options){
    if(value === undefined) {
      var 
      cookie = document.cookie,
      cookieValue = null;
      if (cookie && cookie != ''){
        $each(cookie.split(";"), function() {
          var cookie = $.trim(this);
          if(cookie.substring(0, name.length + 1) == (name + "=")) {
            cookieValue = $deparam(cookie.substring(name.length + 1), TRUE);
            return FALSE;
          }
        });
        return cookieValue;
      }
    } else {
      options = options || {};
      if (value === null) {
          value = '';
          options.expires = -1;
      }
      var
      expires = '',
      path = options.path ? '; path=' + (options.path) : '',
      domain = options.domain ? '; domain=' + (options.domain) : '',
      secure = options.secure ? '; secure' : '';
        if (options.expires && (typeof options.expires == 'number' || options.expires.toGMTString)) {
            var date;
            if (typeof options.expires == 'number') {
                date = new Date();
                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
            } else {
                date = options.expires;
            }
            expires = '; expires=' + date.toGMTString();
        }
      document.cookie = [name, '=', $param(value), expires, path, domain, secure].join('');
    }
  };

  $.fn.felinesearch = function(options) {
    this.each(function(){
      function updatetoggleextended() {
        if($extended.is(":visible"))
          $toggleextended.removeClass("open").addClass("close");
        else
          $toggleextended.removeClass("close").addClass("open");
      }

      var
      
      $this = $(this),
      
      cookiename = "fesearch",
      
      searchgroup = options.searchgroup,

      searchParams = $deparam.querystring($this.attr("href"),TRUE),
      
      cookie = $cookie(cookiename),
      
      cookieParams = cookie[searchgroup] ? cookie[searchgroup] : {},

      params = cookie[searchgroup] = $.extend({}, cookieParams, searchParams),

      heading = options.heading,
      
      errorheading = options.errortext,
      
      updatecookie = function(name, value) {
        var cookie = $cookie(cookiename);
        if(!cookie) cookie = {};
        if(!cookie[searchgroup]) {
          cookie[searchgroup] = {};
        }
        cookie[searchgroup][name] = value;
        $cookie(cookiename, cookie);
      },

      geolink = params.geolink ? createLookup(params.geolink.split(",")) : {};

      $container = $("<div class='middle'/>")
        .append($("<h1>" + ($.isFunction(heading) ? heading(params) : heading) + "</h1>")),

      $geo = $("<fieldset class='geo'/>")
        .append($("<legend><span>" + options.geo.legend + "</span></legend>")),
        
      $geoimage = $("<a></a>").appendTo($geo),

      $extended = $("<div id='extended'/>").toggle(params.extended!==undefined && params.extended),
      
      //create link to toggle extended search
      $toggleextended = $("<a>" + options.extended.toggle + "</a>")
        .attr("href","#extended")
        .click(function(){
          $($(this)
            .attr('href'))
            .slideToggle("fast", function(){
              updatecookie("extended", $extended.is(":visible"));
              updatetoggleextended();
            });
          return false;
        }),
      
      $searchform = $("<form/>"),
      
      $submitbutton = $("<input type='submit' value='" + options.search + "' class='search'/>"),
      
      geooptions=options.geo,
      
      langidx = lang[options.lang],
      
      holidayoptions = [];
      
      $cookie(cookiename, cookie);
      
      params.holidaytype = ($isFunction(options.holidaytype) ? options.holidaytype(params) : options.holidaytype);
     
      $each(holidaytype,function(key,value){
        if (links[langidx][value] != '')
          holidayoptions.push({value:key,url:"http://"+replaceTld(domains[langidx][domaintype[value]])+"/"+links[langidx][value],text:names[langidx][value]});
      });
      
      $searchform
        .bind("focusin.feline",function(e){
          $(e.target).data("hasfocus",true);
        })
        .bind("focusin.feline dateSelected.feline",function(e){
          $(e.target).removeClass("felineSearchWarning");
        })
        .bind("focusout.feline",function(e){
          $(e.target).data("hasfocus",false);
          $(this).find("select,input[type=text]").each(function(){
            var $this = $(this);
            if(!$this.data("hasfocus") && (($this.data("required") && (!$this.val() || $this.val()===$this.data("label"))) || $this.data("isinvalid"))) {
              $this.addClass("felineSearchWarning");
            }
          });
        });
      
      $container.append(createSection({legend:legends[langidx],dropdowns:[{name:"holidaytype",options:holidayoptions}]}, params)); 
      
      $.getJSON("/geo/katalogdata.asp", { katalogid:geooptions.katalogid,incurl:!(params.miniferie||params.lastminite),incmap:true,v:4},function(data,status){
        if(params.lastminute) {
          var 
          lastminuteids = ["746F19A0BD72441087FDB8B3F9994444",
                           "B519C38F3E214A878CF67DECACB4D2BF",
                           "BA19E791CFD14B29853EFDDCADFF8A30",
                           "60CD8A0E8F4C4795AAD3A82430857074",
                           "A19A0B8778EA4774865AD43764B2ED31",
                           "6F82A2F13842420C90AA6D414E29E6B4",
                           "F8692C927135449ABFA28976BCECBEDD",
                           "20AAF369F6384189A97763F522C0060F",
                           "27DD7C9FE016487680C7EC832B683ED6",
                           "39AE673245B346BEAD31C00534E62FC3",
                           "2EAEE9336615463F9E1A9D7F15799A81",
                           "EC3D7CA0B4E04CDCA8453779AAB7AE59",
                           "79B69E5805964E9CB6463D2466BB49DA",
                           "AEEED8CAC722431EBFB4057ECDBFBD40",
                           "511704DD0DC9434C93F68E62029C7A01",
                           "4A30C4765CA546288CD6730DDEC50D53",
                           "B1DA8AD6E447436BBBBF36B1AD1279BA"];
          data.nodes = filterNodes(data.nodes,function(node){return $.inArray(node.id,lastminuteids)>-1;});                         
        }
        $geoimage
          .geoimagemap({data:data,ids:geolink,labels:options.geo.labels})
          .bind("selected.feline", function(e, ids) {
            var 
            $select = $geo.find("select").first(),
            $last = null;
            ids.push("");
            $each(ids,function(i,id){
              $select.val(id).trigger("created");
              if($select.length) $last = $select;
              $select = $select.next();
            });
            $last.trigger("change");
          });
        createSelects[options.geo.type]($geo, data.nodes, 0, 0, options.geo, geolink, data.url, !searchParams["nogeochange"]);
      });
      
      $geo.appendTo($("<div class='section'/>").appendTo($container));
      
      $each(options.sections, function(){
        $container.append(createSection(this, params));
      });
      
      $submitbutton.appendTo($container);
      
      $each(options.extended.sections, function(){
        $extended.append(createSection(this, params));
      });
      $container.append($extended);
      
      $geo.change(function(){
        var geolink=[];
        $searchform.find("fieldset.geo input[type=hidden], fieldset.geo select").each(function(){
          var val = $(this).val();
          if(val!="") {
            geolink.push(val);
          }
        });
        updatecookie("geolink", geolink.join(","));
        $geoimage.trigger("update.feline", [createLookup(geolink)]);
      });

      if($.isArray(options.persondistribution)) {
        $.each(options.persondistribution, function(i,o) {
          var
          name = o.name,
          $refadults = $container.find("select[name=" + o.refadults + "]"),
          $refchildren = $container.find("select[name=" + o.refchildren + "]"),
          $refsection = $refchildren.closest("div.section"),
          $section = $("<div class='section'/>"),
          $field = $("<input type='hidden' name='" + o.name + "'/>"),
          $fieldset = $("<fieldset/>")
            .appendTo($section)
            .append($("<legend><span>" + o.legend + "</span></legend>"))
            .append($field);
            
          $field.val(params[name]);         
          
          function updatepersondistribution() {
            var 
            value = $refchildren.val(),
            intVal = parseInt(value),
            children = [];
            
            $.each($field.val().split(","),function(i,s) {
              var age = parseInt(s);
              if(age<=15) {
                children.push(age);
              }
            });
            
            function appendOptions(options, $dropdown, i) {
              $each(options, function(){
                var $option = $("<option value='" + this.value + "'" + ((children[i]!="-1" && children[i]==this.value) ? " selected='selected'" : "") + ">" + this.text + "</option>");
                $dropdown.append($option);
              });
            }
            
            function updatefield() {
              var persondistribution = [];
              for(var i=0;i<parseInt($refadults.val());i++)
                persondistribution.push("v");
              if(intVal>0) {
                $fieldset.find("select").each(function(){
                  persondistribution.push($(this).val());
                });
              }
              $field.val(persondistribution.join(","));
              updatecookie(name, $field.val());
            }
            
            $section.toggle(intVal>0);
            if(intVal>0) {                            
              var 
              $dropdown = $field,
              $errorbox = $("#searcherrorpopup");

              for(var i=0;i<intVal;i++) {
                $dropdown = $dropdown.next("select");
                if($dropdown.length==0) {
                  $dropdown = $("<select/>");
                  $dropdown.data("required", o.required);
                  $dropdown.change(updatefield);
                  appendOptions(o.options, $dropdown, i);
                  $fieldset.append($dropdown);
                  $dropdown.trigger("focusout.feline");
                }
              }
              $dropdown.nextAll("select").each(function(){
                $errorbox.trigger("removeErrorline.feline", [this]);
              }).remove();
            }
            updatefield();
          }
          $refchildren.bind("change keyup",updatepersondistribution);
          $refadults.bind("change keyup",updatepersondistribution);
          updatepersondistribution();
          
          $refsection.after($section);
        });
      }

      $searchform.append($("<div class='search'/>")
          .append("<div class='top'/>",$container,$("<div class='bottom'/>")
            .append($toggleextended)))
        //replace existing box and link with searchform
        .replaceAll($this.closest("div.search"));
      
      $searchform.data(dataname, {});
      
      $searchform.focusin(function(e){
         var 
         id = $(e.target).attr("id"),
         cookie = $cookie(cookiename);
         if(!cookie) cookie = {};
         if(id)
           cookie.focusid = id;
         else
           delete cookie.focusid;
         $cookie(cookiename, cookie);
        })
      
      if(cookie && cookie.focusid) {
        setTimeout(function(){
          $searchform.find("#" + cookie.focusid).focus().trigger("focusin.feline");
        },200);
      }
      
      updatetoggleextended();
            
      $searchform
        //register for submit to make search
        .bind("submit.feline",function(e){
          var 
          $this = $(this),
          params = {},
          errors = [],
          geolink = [];
          
          $searchform.find("fieldset.geo input[type=hidden], fieldset.geo select").each(function(){
            var val = $(this).val();
            if(val!="") {
              geolink.push(val);
            }
          });
          params["geolink"]=geolink.join(",");
          params["geoid"]=geolink[geolink.length-1];
          $searchform.find("input[type=checkbox]:visible").each(function(){
            var 
            $this = $(this),
            name = $this.attr("name");
            if(name) params[name] = $this.is(":checked");
          });
          $searchform.find("select:visible, input[type=hidden], input[type=text]:visible").each(function(){
            var 
            $this = $(this),
            name = $this.attr("name"), 
            value = $this.val();
            if((value=="" || value==$this.data("label")) && $this.data("required")) {
              errors.push({target:this,message:$this.data("required")});
            } else {
              var date = parseDate(value)
              if($this.data("invaliddate") && !date) {
                errors.push({target:this,message:$this.data("invaliddate")});
              } else if($this.data("mindate") && $this.data("mindatetext") && date<$this.data("mindate")) {
                errors.push({target:this,message:$this.data("mindatetext").replace('%1%', $this.data("mindate").asString("dd-mm-yyyy"))});
              } else if($this.data("maxdate") && $this.data("maxdatetext") && date>$this.data("maxdate")) {
                errors.push({target:this,message:$this.data("maxdatetext").replace('%1%', $this.data("maxdate").asString("dd-mm-yyyy"))});
              } else {
                if(name) params[name] = value;
              }
            }
          });
                    
          $("#searcherrorpopup").trigger("remove.feline");
          if(errors.length) {
            var
            $okbutton = $("<input type='button' value='OK'/>"),
            $errorboxlines = $("<ul class='searcherrorerror'/>"),
            $errorbox = $("<div id='searcherrorpopup'/>").css({top:$submitbutton.position().top+95})
              .append($("<div class='searcherrormiddle'>")
                .append($("<img src='/settings/feline.dk/images/searcherroricon.png'/>"))
                .append($("<div class='searcherrorcontent'>")
                  .append($("<span class='searcherrorheader'>" + errorheading + "</span>"))
                  .append($errorboxlines)))
              .append($("<div class='searcherrorbottom'>")
                .append($okbutton)),
            $errors = $($.map(errors,function(e){return e.target;}));
            
            $(".footer2").css("zIndex",99);
            
            function removeErrorline()
            {
              var $this = $(this);
              if($this.val() && !$this.data("isinvalid")) {
                $errorbox.trigger("removeErrorline.feline", [this]);
              }
            }
            
            $errorbox.bind("removeErrorline.feline", function(e, target) {
              $(target).removeClass("felineSearchError").unbind("change.feline", removeErrorline);
              var $errorlines = $(this).find("li")
              $errorlines.each(function(){
                var $this = $(this);
                if($this.data("target")==target) {
                  $this.remove();
                  if($errorlines.length<=1) $errorbox.remove();
                }
              });
            });
            
            $.each(errors,function(i,e){
              $("<li>" + e.message + "</li>").appendTo($errorboxlines).data("target", e.target);
              $(e.target).addClass("felineSearchError").bind("change.feline", removeErrorline);
            });
            
            function removeErrorbox(e) {
              if(e.type !== "keydown" || e.which == 27) {
                var
                $errorlines = $errorbox.find("li"),
                $errorline = $errorlines.first()
                $target = $($errorline.data("target"));
                $errorlines.each(function(){
                  $errorbox.trigger("removeErrorline.feline", [$(this).data("target")]);
                });
                $target.focus().trigger("focusin.feline");
              }
              $(".footer2").css("zIndex",200);
            }
           
            $okbutton.bind("click.feline keydown.feline", removeErrorbox);
            $errorbox.bind("remove.feline", removeErrorbox);
            
            function tabhandler(e){
              if(e.which==9) {
                var 
                $errorlines = $errorbox.find("li"),
                $errorline = e.shiftKey ? $errorlines.last() : $errorlines.first();
                $okbutton.unbind("keydown.feline", tabhandler);
                $($errorline.data("target")).focus().trigger("focusin.feline");
                e.preventDefault();
              }
            }
            
            $okbutton.bind("keydown.feline", tabhandler);
            
            
            $("#container").prepend($errorbox);
            //$.scrollTo("#searcherrorpopup");
            
            $okbutton.focus();
          }
          if(!errors.length) {
            $searchform.trigger("changelocation");
            setTimeout(function(){
              location.href=options.action+"?"+$.param(params);
            },200);
          }
          e.preventDefault();
          return false;
        })
        //register for focusin to set which field has focus
        .bind("change.feline",function(e){
          var 
          
          $this = $(this),
          $target = $(e.target),
          name = $target.attr("name");
          
          $("#searcherrorpopup").css({top:$submitbutton.position().top+95})
          
          //update cookie with new value
          if(name) {
            updatecookie(name, $target.is("input[type=checkbox]") ? $target.is(":checked") : $target.val());
          }
          
          //if checkbox and new selected option has url then navigate to url
          if($target.is("select")) {
            var url = $target.find("option:selected").data("url");
            if(url) {
              $searchform.trigger("changelocation");
              setTimeout(function(){
                location.href=url;
              },200);
            }
          }
        }).trigger("focusout.feline");
    });
  }
  $.fn.felinesearch.isoWeekNumber = isoWeekNumber;
})(jQuery);