
Logger = Class.create();
Logger.prototype =
{
    initialize: function(view)
    {
        this.tsstart = $A();
        this.view = view;
    },
    start: function()
    {
        this.tsstart.push(new Date());
    },
    flush: function(m)
    {
        var e = this.view;
        if(!e)
            return;

        t = this.tsstart.pop();

        if(t)
            new Insertion.Bottom(e,'<div>' + m + ', took:' + (new Date() - t) + '</div>');
        else
            new Insertion.Bottom(e,'<div>' + m + '</div>');
    },
    clear: function()
    {
        var e = this.view;
        if(!e)
            return;

        e.update('');
    },
    log: function(m)
    {
        var e = this.view;
        if(!e)
            return;

        new Insertion.Bottom(e,'<div>' + m + '</div>');
    }
};

/**
 * Add a sorting property to the Array object
 */
Array.prototype.propertySort = function(index)
{
  var objectToString = Object.prototype.toString,
      arrayToString = Array.prototype.toString;

  if(typeof index != "function")
  {
    var property = index;
    index = function(){return this[property]};
  }
  Object.prototype.toString = index;
  Array.prototype.toString = index;

  this.sort();

  Object.prototype.toString = objectToString;
  Array.prototype.toString = arrayToString;
}

/**
 * We add some general functions to the array used as our recordsetlists
 */
Array.prototype.findObject = function(siteMask,rsIdx)
{
    var theRow = null;
    num = this.length;
    for(i = 0; i < num; i++)
    {
        if(this[i][0] == rsIdx && this[i][1] & siteMask)
        {
            theRow = this[i];
            break;
        }

    }
    return theRow;
}

/**
 * Simple class for translating between different site representations
 */
SiteTranslator = Class.create();
SiteTranslator.siteMaskToSite = function(m)
{
    switch(m)
    {
        case 0x01 :
        return "hemsedal";

        case 0x02 :
        return "salen";

        case 0x04 :
        return "trysil";

        case 0x08 :
        return "vemdalen";

        case 0x10 :
        return "are";
    }
};

SiteTranslator.siteMaskToSiteName = function(m)
{
    switch(m)
    {
        case 0x01 :
        return "Hemsedal";

        case 0x02 :
        return "Sälen";

        case 0x04 :
        return "Trysil";

        case 0x08 :
        return "Vemdalen";

        case 0x10 :
        return "Åre";
    }
};
SiteTranslator.siteMaskToSiteId = function(m)
{
    switch(m)
    {
        case 0x01 :
        return "A";

        case 0x02 :
        return "B";

        case 0x04 :
        return "C";

        case 0x08 :
        return "D";

        case 0x10 :
        return "E";
    }
};
SiteTranslator.siteToSiteMask = function(m)
{
    switch(m)
    {
        case "hemsedal" :
        return 0x01;

        case "salen" :
        return 0x02;

        case "trysil" :
        return 0x04;

        case "vemdalen" :
        return 0x08;

        case "are" :
        return 0x10;
    }
};
SiteTranslator.siteIdToSiteMask = function(m)
{
    switch(m)
    {
        case "A" :
        return 0x01;

        case "B" :
        return 0x02;

        case "C" :
        return 0x04;

        case "D" :
        return 0x08;

        case "E" :
        return 0x10;
    }
};
/**
 * General success function, decodes JSON
 * resonse and calls options.onSuccess(origrequest,evaluated JSON-object)
 */
_onSuccess = function(transport)
{
    if(this.options.onSuccess)
    {
        res = eval('(' + transport.responseText + ')');
        this.options.onSuccess(this,res);
    }
},
/**
 * General failure function, decodes JSON
 * resonse and calls options.onFailure(origrequest)
 */
_onFailure = function(transport)
{
    if(this.options.onFailure)
    {
//        res = eval('(' + transport.responseText + ')');
        this.options.onFailure(this);
    }
}

/**
 * The views
 *
 * In general, the following pattern apply:
 *
 * Each view knows its controller (which contains the model)
 * The views contains the following methods:
 *
 * setController(..) Sets the controller which contains model for view
 *                   to render
 * refresh(..) Repaint the view reflecting model changes, the view checks controller state
 *             To determine how to render itselves by calling controller.getState()
 *
 * controller.getState() returns the following states:
 *                       0 = NORMAL, simply fetch model and display it
 *                       1 = WAIT, Model uppdates in progress
 *                       2 = ERROR, Model is inconsitent, controller.getError(..) cotains an error
 */

/**
 * The view elements which shows (antal träffar, antal sidor)
 */
ResultSetInfoView = Class.create();
ResultSetInfoView.prototype =
{
    initialize: function(view,template,noHitsTemplate,extraInfoContainer)
    {
        this.view = view;
        this.template = template;
        this.noHitsTemplate = noHitsTemplate;
        this.controller = null;
        this.extraInfoContainer = extraInfoContainer;
    },
    setController: function(c)
    {
        this.controller = c;
    },
    refresh: function()
    {
//        theLog.start();

        // Check controller state
        myS = this.controller.getState();

        switch(myS)
        {
            case 0 :
            var d = $H({ total: this.controller.getNumHits(), pages: this.controller.getNumPages()});
            this.view.update(this.template.evaluate(d));

            var extraInfo = this.controller.getExtraInfo();
            if(extraInfo)
            {
              this.extraInfoContainer.show();
              this.extraInfoContainer.update(extraInfo);
            }
            break;

            case 1 :
            var d = this.view.descendants();
            d.each(function(e)
            {
               e.style.color = "#AAAAAA";
            });
            this.extraInfoContainer.hide();
            break;

            case 2 :
            var d = $H();
            this.view.update(this.noHitsTemplate.evaluate(d));
            this.extraInfoContainer.hide();
            break;

            default:
        }
//        theLog.flush('ResultSetInfoView.refresh()');
    }
};
/**
 * A View-element showing the navigation view
 */
ResultSetNavigationView = Class.create();
ResultSetNavigationView.prototype =
{
    initialize: function(view)
    {
        this.view = view;
        this.controller = null;
        this.startButts = 3;
        this.endButts = 3;
        this.middleButts = 7;
    },
    setController: function(c)
    {
        this.controller = c;
    },
    refresh: function()
    {
//        theLog.start();
        var html = "";

        // Check controller state
        myS = this.controller.getState();
        switch(myS)
        {
            case 0 :
            numPages = this.controller.getNumPages();
            currentIdx = this.controller.getCurrentPage();
            this.view.update('');
            var docFragment = document.createDocumentFragment();
            var div,a,txt;
            // OK, any next button
            if(currentIdx < (numPages - 1))
            {
                    a = document.createElement("a");
                    a.className = "bookingControl-actionButton";
                    a.onclick = this.controller.setCurrentPage.bind(this.controller,(currentIdx+1));
                    txt = document.createTextNode(this.translate("NEXT"));
                    div = document.createElement("span");
                    div.className = "inner";
                    div.appendChild(txt);
                    a.appendChild(div);
                    docFragment.appendChild(a);
                    //<a href=\"%s\" class=\"bookingControl-actionButton\" %s ><span class=\"inner\">%s</span></a>
            }
            
            if(numPages < (this.startButts + this.endButts + this.middleButts))
            {
                // Simple ..
                for(i = 0; i < numPages; i++)
                {
                    var a = this._getElement(currentIdx,i);
                    docFragment.appendChild(a);
                }
            }
            else
            {
                // Calc the button offsets, always center on selected
                var window = ((this.middleButts - 1)/2);

                // OK, start att currIdx
                var middleStart = currentIdx - window;
                var middleEnd = currentIdx + window;

                // OK, render start ..
                var idxShown = 0;

                for(var i = 0; i < this.startButts; i++)
                {
                    var a = this._getElement(currentIdx,i);
                    docFragment.appendChild(a);
                    idxShown++;
                }

                // OK, now the middle part
                if(idxShown > middleStart)
                    middleStart = idxShown;
                else
                {
                    // Append ...
                    div = document.createElement("div");
                    div.className = "navButtonSeparator";
                    txt = document.createTextNode("...");
                    div.appendChild(txt);
                    docFragment.appendChild(div);
                }

                // Show middle butts
                for(var i = middleStart; i <= middleEnd && i < numPages; i++)
                {
                    var a = this._getElement(currentIdx,i);
                    docFragment.appendChild(a);
                }

                // And possibly show end butts
                var i = (numPages - this.endButts) - 1;

                if(i <= middleEnd)
                {
                    i = middleEnd + 1;
                }
                else
                {
                    div = document.createElement("div");
                    div.className = "navButtonSeparator";
                    txt = document.createTextNode("...");
                    div.appendChild(txt);
                    docFragment.appendChild(div);
                }

                // Show middle butts
                for(;i < numPages; i++)
                {
                    var a = this._getElement(currentIdx,i);
                    docFragment.appendChild(a);
                }
            }
            this.view.appendChild(docFragment);
            break;

            case 1 :
            var d = this.view.descendants();
            d.each(function(e)
            {
                e.style.opacity = "0.5";
                e.style.filter = "alpha(opacity=50)";
            });

            break;

            case 2 :
            this.view.hide();
            break;

            default:
        }
//        theLog.flush('ResultSetNavigationView.refresh()');
    },
    _getElement: function(currentIdx,i)
    {
        var bCls = "S";
        var a,txt,div;

        if((i +1) >= 10)
            bCls = "W";

        if(i == currentIdx)
        {
            a = document.createElement("div");
            a.className = "navButton" + bCls + " nWhite" + bCls;
            txt = document.createTextNode((i + 1));
            div = document.createElement("div");
            div.className = "navTextHolderW";
            div.appendChild(txt);
            a.appendChild(div);
        }
        else
        {
            a = document.createElement("div");
            a.className = "navButton" + bCls + " nRed" + bCls;
            a.onclick = this.controller.setCurrentPage.bind(this.controller,i);
            txt = document.createTextNode((i + 1));
            div = document.createElement("div");
            div.className = "navTextHolder";
            div.appendChild(txt);
            a.appendChild(div);
        }

        return a;
    },
    translate: function(key)
    {
        // Should be overloaded
        alert('Translate not assign (key:' + key + ')');

        return key;
    }
};
/**
 * View element for the filter
 */
FilterView = Class.create();
FilterView.prototype =
{
    initialize: function(view)
    {
        this.view = view;
        this.controller = null;
        this.form = document.forms['filter'];
        this.subAreas = null;
        this.enabled = true;
    },
    setController: function(c)
    {
        this.controller = c;
    },
    setSubAreas: function(s)
    {
        this.subAreas = s;
        this._updateSubAreas();
    },
    refresh: function()
    {
//        theLog.start();
        // Check controller state
        myS = this.controller.getState();
        switch(myS)
        {
            case 0 :
            this._setEnabled(true);
            break;

            case 1 :
            this._setEnabled(false);
            break;

            case 2 :
            this._setEnabled(false);
            break;

            default:
        }
//        theLog.flush('FilterView.refresh()');
    },
    /**
     * The number of beds, 0 = means all
     */
    _getBeds: function()
    {
        return this.form.beds.value;
    },
    /**
     * A mask with correct bits set fot the sites which are "checked", the value
     * of the form-elemnt is used as mask
     */
    _getSiteMask: function()
    {
        i = 0;
        siteMask = 0;

        while(true)
        {
            c = this.form['site'+i];

            if(c == null)
                break;

            if(c.checked)
                siteMask = siteMask | c.value;

            i++;
        }
        return siteMask;
    },
    /**
     * A mask with correct bits set fot the destinations which are "checked", the value
     * of the form-elemnt is used as mask
     */
    _getDestinationMask: function()
    {
        i = 0;
        destinationMask = 0;

        while(true)
        {
            c = this.form['destination'+i];

            if(c == null)
                break;

            if(c.checked)
                destinationMask = destinationMask | c.value;

            i++;
        }
        return destinationMask;
    },
    /**
     * returns the selected sub area (0 if not selected)
     */
    _getSelectedSubAreaCode: function()
    {
        // The selected subarea
        var sa = this.form['subarea'];
        selectedSubArea = 0;
        if(sa)
        {
          if(sa.selectedIndex >= 0)
              selectedSubArea = sa[sa.selectedIndex].value;
        }
        return selectedSubArea;
    },
    /**
     * The mask for the Type
     */
    _getTypeMask: function()
    {
        i = 0;
        tMask = 0;
        while(true)
        {
            c = this.form['type'+i];

            if(c == null)
                break;

            if(c.checked)
                tMask = tMask | c.value;
            i++;
        }
        return tMask;
    },
    /**
     * Mask for the "positive" criteria
     */
    _getCriteriasMask: function()
    {
        i = 1;
        cMask = 0;
        for(i = 1; i <= 10; i++)
        {
            c = this.form['cp'+i];

            if(c && c.checked)
                cMask = cMask | c.value;
        }
        return cMask;
    },
    /**
     * Mask for the "not" criteria
     */
    _getNotCriteriasMask: function()
    {
        i = 1;
        cMask = 0;
        for(i = 1; i <= 10; i++)
        {
            c = this.form['cn'+i];

            if(c && c.checked)
                cMask = cMask | c.value;
        }
        return cMask;
    },
    /**
     * Return all filter elements as a Hashmap
     */
    getFilter: function()
    {
        f = new Filter();
        f.siteMask = this._getSiteMask();
        f.destinationMask = this._getDestinationMask();
        f.selectedSubArea = this._getSelectedSubAreaCode();
        f.typeMask = this._getTypeMask();
        f.beds = this._getBeds();
        f.criteriaMask = this._getCriteriasMask();
        f.notCriteriaMask = this._getNotCriteriasMask();
        f.onlyDiscounted = this._getOnlyDiscounted();
//        theLog.log(f.toString());

        return f;
    },
    selectSubArea: function(sid)
    {
        sa = this.form['subarea'];

        for(i = 0; i < sa.length;i++)
        {
            if(sa[i].value == sid)
            {
                sa.selectedIndex = i;
                return;
            }
        }
    },
    setFilter: function(f)
    {
        // Updates our controls ..
        // ..
    },
    /**
     * Enables/disables form
     */
    _setEnabled: function(e)
    {
        if(e == this.enabled)
            return;
        if(e)
            Form.enable($('filter'));
        else
            Form.disable($('filter'));

        this.enabled = e;
    },
    /**
     * Clear the sub area form
     */
    _clearSubAreas: function()
    {
        sa = form['subarea'];
        if(sa)
            sa.length = 0;
    },
    _updateCriteria: function(num,type,checked)
    {
        if(type == "pos")
        {
            c = this.form['cp' + num];

            if(c)
            {
                if(c.checked != checked)
                    c.checked = checked;

                // Do we have any negative ?
                cn = this.form['cn' + num];

                if(cn)
                {
                    if(checked && cn.checked)
                        cn.checked = false;
                }
            }
        }
        else
        {
            c = this.form['cn' + num];

            if(c)
            {
                if(c.checked != checked)
                    c.checked = checked;

                // Do we have any negative ?
                cn = this.form['cp' + num];

                if(cn)
                {
                    if(checked && cn.checked)
                        cn.checked = false;
                }
            }
        }
    },
    _updateSubAreas: function()
    {
        sa = this.form['subarea'];

        if(this.subAreas != null && sa)
        {
          destinationMask = this._getDestinationMask();

          l = $A();

          // We ignore all ..
          for(i = 1; i < this.subAreas.length; i++)
          {
              if(this.subAreas[i].destmask & destinationMask)
                  l[l.length] = this.subAreas[i];
          }
          // Sortera ..
          sa.length = 0;
          l.propertySort(function(r) { return this.name });

          num = l.length;

          // We add all ..
          sa.options[0] = new Option(this.subAreas[0].name,this.subAreas[0].id);

          for(i = 0; i < num; i++)
          {
              sa.options[i + 1] = new Option(l[i].name,l[i].id);
          }
        }
    },
    _getOnlyDiscounted: function()
    {
        onlyd = this.form['onlyDiscounted'];
        
        if(onlyd)
            return onlyd.checked;
        else
            return false;
    },
    onSiteChanged: function()
    {
        this._filterChanged();
    },
    onDestinationChanged: function()
    {
        this._updateSubAreas();
        this._filterChanged();
    },
    onTypeChanged: function()
    {
        this._filterChanged();
    },
    onBedsChanged: function()
    {
        this._filterChanged();
    },
    onCriteriasChanged: function(num,type,checked)
    {
        this._updateCriteria(num,type,checked);
        this._filterChanged();
    },
    onSubAreaChanged: function()
    {
        this._filterChanged();
    },
    onOnlyDiscountedChanged: function(element)
    {
        this._filterChanged();
    },
    _filterChanged: function()
    {
        this._setEnabled(false);
        // OK, disable ourselves, and dispatch notofication
        setTimeout(this._dispatchFilterChanged.bind(this),100);
    },
    _dispatchFilterChanged: function()
    {
        this.controller.onFilterChanged();
    }
};

/**
 * A resultView using DOM-manipulation
 */
DOMResultView = Class.create();
DOMResultView.prototype =
{
    /**
     * Constructor
     *
     * Parameters:
     * view            The view (div) which will contain resultset
     * showDestinatrion If true destination will be shown otherwise, not
     */
    initialize: function(view,showDestination)
    {
        this.view = view;
        this.controller = null;
        this.expandedItems = $H();
        this.showDestination = showDestination;
        this.sortingColumns = $H();
        if(showDestination)
        {
            this.maxChars = 34;
            this.maxTitle = 17;
        }
        else
        {
            this.maxChars = 30;
            this.maxTitle = 17;
        }

    },
    setController: function(c)
    {
        this.controller = c;
    },
    /**
     * Repaints the view
     */
    refresh: function()
    {
//        theLog.start();

        // Check controller state
        myS = this.controller.getState();
        switch(myS)
        {
            case 0 :
            var docFragment = document.createDocumentFragment();
            var table = document.createElement("table");
			if (this.showDestination)
				table.className = "showDestination";
            table.width="100%";
            table.id = "resultSet";
            table.cellPadding = 0;
            table.cellSpacing = 0;

            var head = document.createElement("thead");
            var trElem, tdElem, txtNode, aNode, tmpNode,div;

            // The head
            trElem = document.createElement("tr");
            trElem.className = "rsHead";

            if(this.showDestination)
            {
                // Destination
                tdElem = document.createElement("td");
                tdElem.className = "sort sNone";
                tdElem.onclick = this.selectSort.bind(this,9);
				tdElem.title = this.translate("DESTINATION2TITLE");
                txtNode = document.createTextNode(this.translate("Destination2"));
                tdElem.appendChild(txtNode);
                trElem.appendChild(tdElem);
                this.sortingColumns[9] = tdElem;
            }

            // Resmål
            tdElem = document.createElement("td");
            tdElem.className = "sort sNone";
            tdElem.onclick = this.selectSort.bind(this,1);
			tdElem.title = this.translate("DESTINATIONTITLE");
            txtNode = document.createTextNode(this.translate("Destination"));
            tdElem.appendChild(txtNode);
            trElem.appendChild(tdElem);
            this.sortingColumns[1] = tdElem;

            // Boende/anläggning
            tdElem = document.createElement("td");
            tdElem.className = "sort sNone";
            tdElem.onclick = this.selectSort.bind(this,2);
			tdElem.title = this.translate("SUBAREAMOREINFOTITLE");
            txtNode = document.createTextNode(this.translate("Subarea/moreinfo"));
            tdElem.appendChild(txtNode);
            trElem.appendChild(tdElem);
            this.sortingColumns[2] = tdElem;

            // Typ
            tdElem = document.createElement("td");
            tdElem.className = "sort sNone";
            tdElem.onclick = this.selectSort.bind(this,3);
			tdElem.title = this.translate("TYPETITLE");
            txtNode = document.createTextNode(this.translate("Type"));
            tdElem.appendChild(txtNode);
            trElem.appendChild(tdElem);
            this.sortingColumns[3] = tdElem;

            // Bäddar
            tdElem = document.createElement("td");
            tdElem.className = "sort sNone";
            tdElem.onclick = this.selectSort.bind(this,4);
			tdElem.title = this.translate("BEDSTITLE");
            txtNode = document.createTextNode(this.translate("Beds"));
            tdElem.appendChild(txtNode);
            trElem.appendChild(tdElem);
            this.sortingColumns[4] = tdElem;

            // Storlek
            tdElem = document.createElement("td");
            tdElem.className = "sort sNone";
            tdElem.onclick = this.selectSort.bind(this,5);
			tdElem.title = this.translate("ROOMSIZETITLE");
            txtNode = document.createTextNode(this.translate("Roomsize"));
            tdElem.appendChild(txtNode);
            trElem.appendChild(tdElem);
            this.sortingColumns[5] = tdElem;

            // // Avstånd lift
            tdElem = document.createElement("td");
            tdElem.className = "sort sNone";
            tdElem.onclick = this.selectSort.bind(this,6);
			tdElem.title = this.translate("LIFTSLOPETITLE");
            txtNode = document.createTextNode(this.translate("Lift/Slope"));
            tdElem.appendChild(txtNode);
            trElem.appendChild(tdElem);
            this.sortingColumns[6] = tdElem;

            // Period
            tdElem = document.createElement("td");
            tdElem.className = "sort sNone";
            tdElem.onclick = this.selectSort.bind(this,7);
			tdElem.title = this.translate("PERIODTITLE");
            txtNode = document.createTextNode(this.translate("Period"));
            tdElem.appendChild(txtNode);
            trElem.appendChild(tdElem);
            this.sortingColumns[7] = tdElem;

            // No pets
            tdElem = document.createElement("td"); trElem.appendChild(tdElem);

            // No smoking
            tdElem = document.createElement("td"); trElem.appendChild(tdElem);

            // Pris prislista
            tdElem = document.createElement("td");
            tdElem.className = "sort sNone";
            tdElem.colSpan = 2;
            tdElem.onclick = this.selectSort.bind(this,8);
			tdElem.title = this.translate("PRICETITLE");
            txtNode = document.createTextNode(this.translate("Price"));
            tdElem.appendChild(txtNode);
            trElem.appendChild(tdElem);
            this.sortingColumns[8] = tdElem;

            // Pirsicon
            tdElem = document.createElement("td"); trElem.appendChild(tdElem);

            // Select butt
            tdElem = document.createElement("td"); trElem.appendChild(tdElem);

            head.appendChild(trElem);
            table.appendChild(head);

            // OK, now our data
            var data = this.controller.getDisplayRows();
            num = data.length;
            var colsUsed = 12;
            var charsLeft,fastTitle,longestTitle,longestResmal;

            if(this.showDestination)
                colsUsed = 13;

            longestTitle = 0;
            longestResmal = 0;
            // OK, lets determine how long the Resmål column could be
            for(i = 0; i < num;i++)
            {
                var d = data[i];

                if(longestTitle < d[3].length)
                    longestTitle = d[3].length;

                if(longestResmal < d[2].length)
                    longestResmal = d[2].length;

            }
            // We need to cut at all ?
            if(this.maxChars < (longestTitle + longestResmal))
            {
                if(this.maxTitle < longestTitle)
                    longestTitle = this.maxTitle;

                charsLeft = this.maxChars - longestTitle;
            }
            else
                charsLeft = this.maxChars;


            for(i = 0; i < num;i++)
            {

                trElem = document.createElement("tr");

				trElem.onmouseover = function () { $jq(this).addClass('hover'); }
				trElem.onmouseout = function () { $jq(this).removeClass('hover'); }

                var d = data[i];

				trElem.onclick = this.toggleInfo.bind(this,d[0],d[1]);

                // OK, we prepare the columns
                if(i % 2)
                    trElem.className = "rsOdd";
                else
                    trElem.className = "rsEven";

                trElem.className = trElem.className + " rsRow";

                // Destination
                if(this.showDestination)
                {
                  tdElem = document.createElement("td");
                  tdElem.style.paddingLeft = 4;
                  txtNode = document.createTextNode(SiteTranslator.siteMaskToSiteName(d[1]));
				  if (this.controller.getCurrentSort() == 9)
					tdElem.className = " highlighted";
                  tdElem.appendChild(txtNode);
                  trElem.appendChild(tdElem);

                }

                // Resmål
                tdElem = document.createElement("td");

				tdElem.className = "rsColArea";
				
                if(!this.showDestination)
                  tdElem.style.paddingLeft = 4;

				if (this.controller.getCurrentSort() == 1)
					tdElem.className += " highlighted";

                if(d[2].length > charsLeft)
                {
                    fastTitle = d[2].substring(0,charsLeft) + '...';
                }
                else
                    fastTitle = d[2];

                txtNode = document.createTextNode(fastTitle);
                tdElem.title = d[2];

				areaSpan = document.createElement("span");
				areaSpan.appendChild(txtNode);
				
				tdElem.appendChild(areaSpan);
				
                trElem.appendChild(tdElem);

                // Anläggning
                tdElem = document.createElement("td");
                tdElem.className = "rsColInfo";

				aNode = document.createElement("a");
                aNode.className = "itemExpand";
				
				if (this.controller.getCurrentSort() == 2)
					tdElem.className += " highlighted";
                aNode.id = 'i' + d[22] + d[0];
                // Moved to TR aNode.onclick = this.toggleInfo.bind(this,d[0],d[1]);
                var h = d[3] + '\n' + d[23];
                if(d[24] != 0)
                    h = h + '\n' + d[24];
           //    aNode.title = h;

/*                tmpNode = document.createElement("div");
                tmpNode.className = "itemExpand";
                tmpNode.id = 'i' + d[22] + d[0];
                tmpNode.onclick = this.toggleInfo.bind(this,d[0],d[1]);
                tdElem.appendChild(tmpNode);
*/
                if(d[3].length > this.maxTitle)
                    fastTitle = d[3].substring(0,this.maxTitle) + '...';
                else
                    fastTitle = d[3];

                txtNode = document.createTextNode(fastTitle);
                aNode.appendChild(txtNode);
             //   aNode.title = d[3];
                
                
                //Lägg till en tooltip med hela namnet om det är trunkerat i tabellen
                if(fastTitle != d[3])
                {                    
                    aNode.onmouseover = this._onShowSubareaName.bindAsEventListener(this,d[3],'');
                    aNode.onmouseout = this._onHideSubareaName.bindAsEventListener(this);                                        
                }
                
                tdElem.appendChild(aNode);
                trElem.appendChild(tdElem);

                // Typ
                tdElem = document.createElement("td");
                tdElem.style.textAlign = "center";
                tmpNode = document.createElement("div");
                tmpNode.className = 'accoType' + d[4];
				if (this.controller.getCurrentSort() == 3)
					tdElem.className += " highlighted";

                tdElem.appendChild(tmpNode);
                trElem.appendChild(tdElem);

                // Storlek
                tdElem = document.createElement("td");
                tdElem.style.textAlign = "center";
				if (this.controller.getCurrentSort() == 4)
					tdElem.className = " highlighted";
                txtNode = document.createTextNode((d[5] - d[6]) + '+' + d[6]);
                tdElem.appendChild(txtNode);
                trElem.appendChild(tdElem);

                // Storlek
                var asize = "";
                if(d[7] > 0)
                    asize = d[7] + " m" + String.fromCharCode(0x00B2);

                tdElem = document.createElement("td");
                tdElem.style.textAlign = "center";
				if (this.controller.getCurrentSort() == 5)
					tdElem.className = " highlighted";
                txtNode = document.createTextNode(asize);
                tdElem.appendChild(txtNode);
                trElem.appendChild(tdElem);

                // Avstånd till lift
                lift =""
                if(d[8] > 0)
                    lift = d[8] + " m";
                if(d[8] >= 1000)
                    lift = ">1 km";

                tdElem = document.createElement("td");
                tdElem.style.textAlign = "center";
				if (this.controller.getCurrentSort() == 6)
					tdElem.className = " highlighted";
                txtNode = document.createTextNode(lift);
                tdElem.appendChild(txtNode);
                trElem.appendChild(tdElem);

				// Period
                tdElem = document.createElement("td");
                tdElem.style.textAlign = "center";
				if (this.controller.getCurrentSort() == 7)
					tdElem.className = " highlighted";
                txtNode = document.createTextNode(d[9]);
                tdElem.appendChild(txtNode);
                trElem.appendChild(tdElem);

                // No Pets ?
                tdElem = document.createElement("td");
                tmpNode = document.createElement("div");
                tdElem.appendChild(tmpNode);

                if(d[11] & 0x100)
                    tmpNode.className = "noP";
                else
                    tmpNode.className = "empty";
                trElem.appendChild(tdElem);

                // No smoking ?
                tdElem = document.createElement("td");
                tmpNode = document.createElement("div");
                tdElem.appendChild(tmpNode);

                if(d[11] & 0x80)
                    tmpNode.className = "noS";
                else
                    tmpNode.className = "empty";
                trElem.appendChild(tdElem);

                docFragment.appendChild(trElem);

                // Price
                tdElem = document.createElement("td");
                tdElem.style.textAlign = "right";
                if(d[25])
                {
                    // OK, we have discount, we add tooltip functions
                    tdElem.className = "discountedPrice";
				    tdElem.onmouseover = this._onShowDiscountInfo.bindAsEventListener(this,d[27],d[28]);
				    tdElem.onmouseout = this._onHideDiscountInfo.bindAsEventListener(this);
                }

                tmpNode = document.createElement("a");
//                tmpNode.onclick = this.showPricePopup.bind(this,d[0],d[1]);
                // Moved to TR tmpNode.onclick = this.selectItem.bind(this,d[0],d[1]);
                tmpNode.className = "priceLink";
				if (this.controller.getCurrentSort() == 8)
					tdElem.className += " highlighted";
                txtNode = document.createTextNode(d[10]);
                tmpNode.appendChild(txtNode);
                tdElem.appendChild(tmpNode);
                trElem.appendChild(tdElem);

                // Price img
                tdElem = document.createElement("td");
                tdElem.style.textAlign = "center";
                tmpNode = document.createElement("div");
                tmpNode.onclick = this.showPricePopup.bind(this,d[0],d[1]);
                tmpNode.className = "priceImageLink";
                tdElem.appendChild(tmpNode);
                trElem.appendChild(tdElem);

                // And select butt
                tdElem = document.createElement("td");
                tmpNode = document.createElement("div");
//                tmpNode.onclick = this.selectItem.bind(this,d[0],d[1]);
                // Moved to TR tmpNode.onclick = this.toggleInfo.bind(this,d[0],d[1]);
                tmpNode.id = 'sl' + d[22] + d[0];


                if(this.isExpanded(d[0],d[1]))
                    tmpNode.className = "expandItemLink";
                else
                    tmpNode.className = "foldItemLink";

                tdElem.appendChild(tmpNode);
                trElem.appendChild(tdElem);

                docFragment.appendChild(trElem);
                // OK, create hidden table row for details
                trElem = document.createElement("tr");
                trElem.id = 'e' + d[22] + d[0];
                trElem.style.display = "none";
                tdElem = document.createElement("td");
                tdElem.colSpan = colsUsed;
                tdElem.id = 'd' + d[22] + d[0];
                tdElem.className = "rsDetail";
                txtNode = document.createTextNode(this.translate("Loading") + "...");
                tdElem.appendChild(txtNode);
                trElem.appendChild(tdElem);
                docFragment.appendChild(trElem);
            }
            var body = document.createElement("tbody");
            body.appendChild(docFragment);
            table.appendChild(body);

            this.view.update('');
            this.view.appendChild(table);

            // OK, now lets show how we sort
            var currentSort = this.controller.getCurrentSort();
            var currentSortAsc = this.controller.getCurrentSortAsc();

            if(currentSort > 0)
            {
                v = this.sortingColumns[currentSort];

                if(v)
                {
                    v = $(v);
                    v.removeClassName("sNone");

					var vCols;
                    if(currentSortAsc)
                        v.addClassName("sAsc");
					else
    					v.addClassName("sDesc");
				 }
            }

            // OK, and see which ones that we should display
            num = data.length;
            for(i = 0; i < num;i++)
            {
                d = data[i];
                var key = d[22] + d[0];

                if(this.expandedItems[key])
                    this._showDetails(d[0],d[1],key);
            }
            break;

            case 1 :

            var r = $('resultSet');
            if(r)
            {
                r.style.opacity = "0.5";
                r.style.filter = "alpha(opacity=50)";
            }
            break;

            case 2 :
            this.view.hide();
            break

        }
//        theLog.flush('ResultSetView.refresh()');

	},
    isExpanded: function(rsIdx,siteMask)
    {
        var key = SiteTranslator.siteMaskToSiteId(siteMask) + rsIdx;
        return this.expandedItems[key];
    },
    toggleInfo: function(rsIdx,siteMask)
    {
        var key = SiteTranslator.siteMaskToSiteId(siteMask) + rsIdx;
        var isExpanded = this.expandedItems[key];

        if(isExpanded)
        {
            this.expandedItems[key] = false;

            // OK, simply hide
            this._hideDetails(key);
        }
        else
        {
            this.expandedItems[key] = true;
            this._showDetails(rsIdx,siteMask,key);
        }

    },
    showPricePopup: function(rsIdx,siteMask)
    {
        this.controller.showPricePopup(rsIdx,siteMask);
    },
    selectItem: function(rsIdx,siteMask)
    {
        this.controller.selectItem(rsIdx,siteMask);
    },
    translate: function(key)
    {
        // Should be overloaded
        alert('Translate not assign (key:' + key + ')');

        return key;
    },
    _hideDetails: function(key)
    {
        // Hide it
        var e = $('e'+key);
        if(e)
            e.hide();

        // Flip style on button
        e = $('i'+key);
        if(e)
            e.className = "itemExpand";

        e = $('sl'+key);
        if(e)
            e.className = "foldItemLink";

    },
    _showDetails: function(rsIdx,siteMask,key)
    {
        // Show it
        var e = $('e'+key);
        if(e)
        {
            e.show();

            // Flip style on button
            e = $('i'+key);
            if(e)
                e.className = "itemFold";

            e = $('sl'+key);
            if(e)
                e.className = "expandItemLink";

            html = this.controller.getDetails(rsIdx,siteMask);

            if(html)
            {
                d = $('d'+key);
                if(d)
                    d.update(html);
            }
        }
    },
    refreshDetails: function(rsIdx,siteMask,html)
    {
        var key = SiteTranslator.siteMaskToSiteId(siteMask) + rsIdx;
        d = $('d'+key);
        if(d)
            d.update(html);
    },
    selectSort: function(column)
    {
        var currentSort = this.controller.getCurrentSort();
        var currentSortAsc = this.controller.getCurrentSortAsc();

        if(column == currentSort)
        {
            // OK, toggle order
            this.controller.setSort(currentSort,!currentSortAsc);
        }
        else
        {
            // New sort
            this.controller.setSort(column,false);
        }
    },
    _onShowDiscountInfo: function(evt,discountTitle,discountIngress)
    {
      if(typeof(this.onShowDiscountInfo) != 'undefined')
          this.onShowDiscountInfo(evt,discountTitle,discountIngress);      
    },
    _onHideDiscountInfo: function(evt)
    {
      if(typeof(this.onHideDiscountInfo) != 'undefined')
          this.onHideDiscountInfo();
    },
    _onShowSubareaName: function(evt,subAreaTitle,subAreaIngress)
    {
      if(typeof(this.onShowSubarea) != 'undefined')
      {
          this.onShowSubarea(evt,subAreaTitle,subAreaIngress);      
      }
    },
    _onHideSubareaName: function(evt)
    {
      if(typeof(this.onHideSubarea) != 'undefined')
      {       
          this.onHideSubarea();
      }
    }
};

AccomodationController = Class.create();
AccomodationController.prototype =
{
    /**
     * Constructor
     */
    initialize: function(filterView,rsInfoView,rsView,rsNavigationView,submitFormElement,errorElement,lang)
    {
        // Our views
        this.rsView = rsView;
        this.filterView = filterView;
        this.rsInfoView = rsInfoView;
        this.rsNavigationView = rsNavigationView;
        this.submitFormElement = submitFormElement;
        this.errorElement = errorElement;

        // Assign view to us..
        this.filterView.setController(this);
        this.rsInfoView.setController(this);
        this.rsView.setController(this);
        this.rsNavigationView.setController(this);

        // Model elements
        this.perPage = 30;
        this.state = 0;
        this.lang = lang;
        this.rawList = null;
        this.filteredList = null;
        this.sortedList = null;
        this.displayedList = null;

        this.currentPage = 0;
        this.currentSort = 0;
        this.currentSortAsc = false;

        this.sortFunctions = $A();
        this.sortFunctions[1] = function() { return this[2] + this[0] };
        this.sortFunctions[2] = function() { return this[3] + this[0] };
        this.sortFunctions[3] = function() { return this[4] + this[0] };
        this.sortFunctions[4] = function() { return this[15] + this[0] };
        this.sortFunctions[5] = function() { return this[16] + this[0] };
        this.sortFunctions[6] = function() { return this[18] + this[0] };
        this.sortFunctions[7] = function() { return this[9] + this[0] };
        this.sortFunctions[8] = function() { return this[17] + this[0] };
        this.sortFunctions[9] = function() { return this[22] + this[0] };

        // Cache
        this.detailedItems = $H();
        this.destinationActions = $H();

        // Async update
        // ..
        this.slowMethod = null;

        // OK, message queue
        this.requests = $A();
        this.extraInfoMessage = "";

        this.filterChangedEventListeners = $A();
    },
    _setState: function(myS)
    {
        rV = (this.state != myS);

        this.state = myS;
        if(rV)
            this._refreshViews();
    },
    getState: function()
    {
        return this.state;
    },
    init: function()
    {
    },
    _refreshViews: function()
    {
//        theLog.log('State:' + this.state);
//        theLog.start();
        this.rsInfoView.refresh();
        this.rsView.refresh();
        this.filterView.refresh();
        this.rsNavigationView.refresh();
//        theLog.flush('refreshViews');
    },
    loadData: function(destinations,lang,mode,isoWeek,periodId,departuredate,numNights)
    {
        this._setState(1);
        this.dataSource = new AccomodationDataSource();
        this.dataSource.search(destinations,lang,mode,isoWeek,periodId,departuredate,numNights,{setData: this._setRawData.bind(this), setError: this._displayError.bind(this)});
    },
    _setRawData: function(rows,searchInfos,extraInfoMessage)
    {
        this.rawList = rows;
        this.searchInfos = searchInfos;
        this.extraInfoMessage = extraInfoMessage;

        // Filter
        if(rows.length == 0)
            this._setState(2);
        else
            this._requestUpdate(this.doFilter.bind(this));
    },
    doFilter: function()
    {
//        theLog.start();
        if(this.isMatch)
        {
           f = this.filterView.getFilter();

           for(i = 0; i < this.filterChangedEventListeners.length;i++)
           {
               var fnc = this.filterChangedEventListeners[i];
               fnc(f);
           }

          this.filteredList = $A();
          idx = 0;
          num = this.rawList.length;

          for(i = 0; i < num; i++)
          {
              r = this.rawList[i];

              if(this.isMatch(f,r))
                  this.filteredList[idx++] = r;
          }
        }
        else
        {
            // No matching function, everything matches
            this.filteredList = this.rawList;

        }
//        theLog.flush('filter');

        // We must also reSort
        this.doSort();
    },
    doSort: function()
    {
//        theLog.start();
        this.sortedList = this.filteredList;

        this.sortedList.propertySort(this.sortFunctions[this.currentSort]);
        if(this.currentSortAsc)
            this.sortedList.reverse();

        // We must also reset navigation
        this.currentPage = 0;
//        theLog.flush('sort');

        this.doNavigate();
    },
    doNavigate: function()
    {
//        theLog.start();
        this.displayedList = $A();
        startIdx = this.getCurrentPage()*this.perPage;
        stopIdx = Math.min(startIdx+this.perPage,this.sortedList.length);
        idx=0;

        for(i = startIdx; i < stopIdx;i++)
            this.displayedList[idx++] = this.sortedList[i];

//        theLog.flush('navigate');
    },
    getNumPages: function()
    {
        return Math.ceil(this.getNumHits()/this.perPage);
    },
    getNumHits: function()
    {
        return this.sortedList.length;
    },
    getCurrentPage: function()
    {
        return this.currentPage;
    },
    getDisplayRows: function()
    {
        return this.displayedList;
    },
    getCurrentSort: function()
    {
        return this.currentSort;
    },
    getCurrentSortAsc: function()
    {
        return this.currentSortAsc;
    },
    setCurrentPage: function(idx)
    {
        numPages = this.getNumPages();
        if(idx < 0 || idx >= numPages)
            return;
        this.currentPage = idx;
        this._requestUpdate(this.doNavigate.bind(this));
    },
    initSort: function(sortColumn,sortAsc)
    {
        this.currentSort = sortColumn;
        this.currentSortAsc = sortAsc;
    },
    setSort: function(sortColumn,sortAsc)
    {
        this.currentSort = sortColumn;
        this.currentSortAsc = sortAsc;
        this._requestUpdate(this.doSort.bind(this));
    },
    getExtraInfo: function()
    {
        return this.extraInfoMessage;
    },
    onFilterChanged: function()
    {
//        theLog.start();
        this._requestUpdate(this.doFilter.bind(this));
//        theLog.flush('onFilterChange');
    },
    _requestUpdate: function(operation)
    {
        this._setState(1);
        setTimeout(this._performSlowOperation.bind(this,operation),200);
    },
    _performSlowOperation: function(operation)
    {
        operation();
        this._setState(0);
    },
    selectItem: function(rsIdx,siteMask)
    {
        // OK, selected idx, lets find the row
        o = this.displayedList.findObject(siteMask,rsIdx);

        if(o)
        {
            var f = this.submitFormElement;

            // Update our form and submit it
            this._resetPriceInfo();
            site = SiteTranslator.siteMaskToSite(siteMask);

            f.bSite.value = site;

            // Change action ?
            action = this.destinationActions[site];
            if(action)
                f.action = action;

            f.rsIdx.value = rsIdx;
            if(o[19])
                f.bpid.value = "70104";
            else
                f.bpid.value = "70103";

            this._filterToForm(f);

            f.submit();
        }
    },
    getDetails: function(rsIdx,siteMask)
    {
        var key = SiteTranslator.siteMaskToSiteId(siteMask) + rsIdx;

        // In our cache ?
        html = this.detailedItems[key];

        if(html)
            return html;
        else
        {
            // We request it !
            this._requestDetailInfo(siteMask,rsIdx);
            return false;
        }
    },
    _requestDetailInfo: function(siteMask,rsIdx)
    {
        o = this.displayedList.findObject(siteMask,rsIdx);
        if(o)
        {
            site = SiteTranslator.siteMaskToSite(siteMask);
            new AccomodationDetailRequest(site,this.lang,rsIdx,1,{setData: this._setRawDetailInfo.bind(this)});
        }
    },
    _setRawDetailInfo: function(r,html)
    {
        // Save result
        sM = SiteTranslator.siteToSiteMask(r.site);
        sId = SiteTranslator.siteMaskToSiteId(sM);

        this.detailedItems[sId + r.rsIdx] = html;

        // OK, tell rsView that we got some data for him
        this.rsView.refreshDetails(r.rsIdx,sM,html);
    },
    showPricePopup: function(rsIdx,siteMask)
    {
        o = this.displayedList.findObject(siteMask,rsIdx);

        if(o)
        {
            poollid = o[20];
            unitlid = o[21];
            site = SiteTranslator.siteMaskToSite(o[1]);

            searchInfo = this.searchInfos[site];
            IP_show(this.title,'/app/projects/common/templates/boende/pricePopup.php?KeepThis=true&bLang='+this.lang+'&bSite='+site+'&path=/app/projects/common/&poollid='+poollid+'&unitlid='+unitlid+'&isoWeek='+searchInfo.isoWeek +'&periodMark='+searchInfo.periodId +'&viewPortHeight=500&viewPortWidth=700&TB_iframe=true&height=500&width=700');
        }
     },
     selectItemByPrice: function(site,isoWeek,periodId,fromDate,toDate,periodLength,priceId,lid, objectType, unitBookingOnPool)
     {
         // Detrmine target for form submission ..
        this._resetPriceInfo();
        var pid = "";
        if ( unitBookingOnPool == "true" )
            pid = "70104";
        else
            pid = "70103";

        var bpid = pid;

        var f = this.submitFormElement;
        f.bSite.value = site;

        // Change action ?
        action = this.destinationActions[site];
        if(action)
            f.action = action;

        f.periodId.value = periodId;
        f.isoWeek.value = isoWeek;
        f.lid.value = lid;
        f.priceId.value = priceId;
        f.fromDate.value = fromDate;
        f.toDate.value = toDate;
        f.periodLength.value = periodLength;
        f.objectType.value = objectType;
        f.priceList.value = "true";
        f.bpid.value = bpid;

        this._filterToForm(f);

        f.submit();
    },
    _resetPriceInfo: function()
    {
        f = this.submitFormElement;
        f.periodId.value = "";
        f.isoWeek.value = "";
        f.lid.value = "";
        f.priceId.value = "";
        f.fromDate.value = "";
        f.toDate.value = "";
        f.periodLength.value = "";
        f.objectType.value = "";

        f.priceList.value = "";
        f.bpid.value = "";
    },
    setDestinationAction: function(d,action)
    {
        this.destinationActions[d] = action;
    },
    submitSearch: function(isoWeek,mode,periodId,departureDate,numNights)
    {
//        alert('isoWeek:' + isoWeek + ' mode: ' + mode + ' periodId:' + periodId + ' departureDate:' + departureDate + ' numNights:' + numNights);

         // Detrmine target for form submission ..
        this._resetPriceInfo();
        var f = this.submitFormElement;

        f.periodId.value = periodId;
        f.isoWeek.value = isoWeek;
        f.mode.value = mode;
        f.departuredate.value = departureDate;
        f.numNights.value = numNights;
        f.bpid.value = 70102;

        this._filterToForm(f);

        f.submit();
    },
    _filterToForm: function(f)
    {
        // OK, save current filter values
        var filter = this.filterView.getFilter();

        f.fSite.value = filter.siteMask;
        f.fArea.value = filter.destinationMask;
        f.fSubArea.value = filter.selectedSubArea;
        f.fType.value = filter.typeMask;
        f.fBeds.value = filter.beds;
        f.fCrits.value = filter.criteriaMask;
        f.fNotCrits.value = filter.notCriteriaMask;
        f.fOnlyDiscounted.value = filter.onlyDiscounted;        

        f.fSort.value = this.currentSort;

        if(this.currentSortAsc)
            f.fSortAsc.value = 'true';
        else
            f.fSortAsc.value = 'false';

    },
    _displayError: function(site,message)
    {
        var siteMask = SiteTranslator.siteToSiteMask(site);
        var siteName = SiteTranslator.siteMaskToSiteName(siteMask);
        this.errorElement.show();
        new Insertion.Bottom(this.errorElement,'<div><b>'+ siteName + '</b>: ' + message + '</div>');
    },
    addOnFilterChangedEventListener: function(fnc)
    {
        this.filterChangedEventListeners[this.filterChangedEventListeners.length] = fnc;
    }
};
/**
 * Request classes
 *
 * All request are executed towards server on constructtion
 *
 * All request accepts an options argument as follows:
 *
 * onSuccess, callback function of the following prototype
 * func([request],[payload])
 *   request: The original request object
 *   payload: The result of method (false if there are none)
 *
 * onFailure, callback function of the following prototype
 * func(request)
 *   request: The original request object
 *
 *
 * Example:
 * issue an AddHotSpot request calling mySuccess on success ..
 * new AddHotSpotRequest(1,this.top,this.left,width,height,{onSuccess: mySuccess});
 */

/**
 * Accomodation search
 *
 * The request is issued at construction.
 *
 * if onSuccess / onFailure are assigned in options this callbacks
 * will be called accordingly.
 *
 */
AccomodationSearchRequest = Class.create();
AccomodationSearchRequest.prototype =
{
    /**
     *
     * Parameters:
     * site           The site to search on [salen/are ..]
     * lang           The isolanguage code
     * isoWeek        Period, season, week
     * periodId       The type of period searched for (1 = Whole week, 2 = kortvecka, e.t.c.)
     * departuredate  if booking dates, this will be the startdate
     * numNights      if booking dates, this is the number of nights
     *
     */
    initialize: function(site,lang,mode,isoWeek,periodId,departuredate,numNights,options)
    {
       this.options = options;
       this.site = site;
       if(options.useGlobalFilter)
           useGlobalFilter = 'yes';
       else
           useGlobalFilter = 'no';

       var p = $H({ site: site, lang: lang, mode: mode, isoWeek: isoWeek, periodId: periodId,departuredate: departuredate,numNights:numNights, useGlobalFilter: useGlobalFilter});
       try
       {
           var r = new Ajax.Request('/app/projects/common/templates/boende/searchapi.php',{method: 'get',parameters: p, onSuccess: _onSuccess.bind(this), onFailure: _onFailure.bind(this) });
       }
       catch(e)
       {
           alert('Exception');
       }
    }
};
/**
 * Fetches details for accomodation
 *
 * The request is issued at construction.
 *
 * if onSuccess / onFailure are assigned in options this callbacks
 * will be called accordingly.
 *
 */
AccomodationDetailRequest = Class.create();
AccomodationDetailRequest.prototype =
{
    /**
     *
     * Parameters:
     * site           The site to search on [salen/are ..]
     * lang           The isolanguage code
     * rsIdx          ResultSet index in session
     * rs             Which rs to use
     *
     */
    initialize: function(site,lang,rsIdx,rs,options)
    {
       this.site = site;
       this.lang = lang;
       this.rsIdx = rsIdx;
       this.rs = rs;
       this.options = options;

       var p = $H({ site: site, lang: lang, rsIdx: rsIdx, rs: rs});
       var r = new Ajax.Request('/app/projects/common/templates/boende/detailapi.php',{method: 'get',parameters: p, onSuccess: this.onSuccess.bind(this), onFailure: _onFailure.bind(this) });
    },
    onSuccess: function(transport)
    {
        if(this.options.setData)
            this.options.setData(this,transport.responseText);
    }
};

/**
 * Encapsulates a source of accomodation data (destination/portal)
 *
 */
AccomodationDataSource = Class.create();
AccomodationDataSource.prototype =
{
    /**
     */
    initialize: function()
    {
      this.extraInfoMessage = "";
    },
    /**
     * Executes a search with the supplied parameters (same as AccomodationSearchRequest)
     * if more than one destination, then multiple requests is made
     *
     * options accepts two callbacks, progress and setData. procgress is called for each destination
     *         and setData is called when a result has arrived for all destinations.
     */
    search: function(destinations,lang,mode,isoWeek,periodId,departuredate,numNights,options)
    {
        this.sitesToDo = $A();
        for(i = 0; i < destinations.length; i++)
            this.sitesToDo[i] = $H({ site: destinations[i], done: false});

        this.options = options;

        useGlobalFilter = destinations.length > 1;

        // OK, we dispatches a searches to required destinations
        for(i = 0; i < this.sitesToDo.length; i++)
        {
          new AccomodationSearchRequest(this.sitesToDo[i].site,lang,mode,isoWeek,periodId,departuredate,numNights,{onSuccess: this.onSuccess.bind(this),useGlobalFilter: useGlobalFilter});
        }
    },
    onSuccess: function(r,res)
    {
        var v = $('resultSetInfo');
        this.sitesToDo.each(function(s) { if(s.site == r.site) { s.done = true; s.rows = res.rows; s.searchInfo = res.searchInfo; } });

        if(res.extraInfoMessage)
            this.extraInfoMessage = res.extraInfoMessage;

//        theLog.flush(r.site + ' => ' + res.num);

        // OK, all done ?
        done = true;
        this.sitesToDo.each(function(s) { if(!s.done) { done = false; } });

        // Any callback for progess ?
        if(this.options.progress)
            this.options.progress(r.site,res.num);

        if(this.options.setError && res.error)
            this.options.setError(r.site,res.error);

        if(done)
        {
            // OK, we merge all our results
            r = $A();
            searchInfo = $H();
            extraInfoMessage = $H();
            this.sitesToDo.each(function(s) { if(s.rows != null) { r = r.concat(s.rows); searchInfo[s.site] = s.searchInfo; } });

            // Any callback for done ?
            if(this.options.setData)
                this.options.setData(r,searchInfo,this.extraInfoMessage);
        }
    },
    onFailure: function(r)
    {
    }
};
/**
 * Matching function for a destination search
 * returns true if row matches filter
 */
function destinationMatch(filter,row)
{
    // Beds
    if((row[5]) < filter.beds)
        return false;

    // Destination
    d = row[13] & filter.destinationMask;
    if(!d)
        return false;

    // Sub area
    if(filter.selectedSubArea > 0 && row[14] != filter.selectedSubArea)
        return false;

    // Type
    t = row[12] & filter.typeMask;

    if(!t)
        return false;

    // Criteria
    v = row[11] & filter.criteriaMask;

    if(v != filter.criteriaMask)
        return false;

    // Not criteria
    v =  (row[11] ^ filter.notCriteriaMask) & filter.notCriteriaMask;
    if(v != filter.notCriteriaMask)
        return false;
    
    // Discounted ..?
    if(filter.onlyDiscounted && !row[25])
        return false;

    return true;
}
/**
 * Matching function for a portal search
 * returns true if row matches
 */
function portalMatch(filter,row)
{
    // Site
    d = row[1] & filter.siteMask;
    if(!d)
        return false;

    // Beds
    if((row[5]) < filter.beds)
        return false;

    // Type
    t = row[12] & filter.typeMask;

    if(!t)
        return false;

    // Criteria
    v = row[11] & filter.criteriaMask;

    if(v != filter.criteriaMask)
        return false;

    // Not criteria
    v =  (row[11] ^ filter.notCriteriaMask) & filter.notCriteriaMask;
    if(v != filter.notCriteriaMask)
        return false;

    // Discounted ..?
    if(filter.onlyDiscounted && !row[25])
        return false;

    return true;
}
/**
 * Simple object for holding the current filter
 */
Filter = Class.create();
Filter.prototype =
{
    initialize: function()
    {
        this.siteMask = 0xFFFFFFFF;
        this.destinationMask = 0xFFFFFFFF;
        this.selectedSubArea = 0;
        this.typeMask = 0xFFFFFFFF;
        this.beds = 0;
        this.criteriaMask = 0x0;
        this.notCriteriaMask = 0x0;
        this.onlyDiscounted = 0x0;
    },
    toString: function()
    {
        return 'siteMask:' + this.siteMask + ', destinationMask:' + this.destinationMask + ', sa:' + this.selectedSubArea + ', tm:' + this.typeMask + ', beds:' + this.beds + ',cm:' + this.criteriaMask + ', cnm:' + this.notCriteriaMask;
    }
};

/**
 * Simple object to hold som info about a row
 */
function DetailInfo(html,visible)
{
    this.html = html;
    this.visible = visible;
}

/**
 * Simple struct for holding info about a subArea (anläggnining)
 */
function subAreaEntry(id,destmask,name)
{
    this.id = id;
    this.destmask = destmask;
    this.name = name;
}
var theLog = null;


