//
// Generic form select, filter, display results Javascript
//
// This file Copyright 2010 Andrew M. Bishop
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//


//
// Object creation - fill the list of selector options or press select button.
//

function form_init()
{
 // Fill in the missing information

 if(typeof(selector.init)!='function')
    selector.init=selectorInit;
 if(typeof(selector.fill)!='function')
    selector.fill=selectorFill;
 if(typeof(selector.update)!='function')
    selector.update=selectorUpdate;
 if(typeof(selector.selected)!='function')
    selector.selected=selectorSelected;

 for(var f=0;f<filters.length;f++)
   {
    if(filters[f].autolist!=undefined)
      {
       filters[f].init=filterAutoListInit;
       filters[f].update=filterAutoListUpdate;
       filters[f].fill=filterAutoListFill;
       filters[f].prepare=filterAutoListPrepare;
       filters[f].check=filterAutoListCheck;
      }

    if(filters[f].checkbox!=undefined)
      {
       filters[f].init=filterCheckboxInit;
       filters[f].prepare=filters[f].checkbox.prepare;
       filters[f].check=filters[f].checkbox.check;
      }

    if(typeof(filters[f].init)!='function')
       filters[f].init=filterTrue;
    if(typeof(filters[f].update)!='function')
       filters[f].update=filterTrue;
    if(typeof(filters[f].fill)!='function')
       filters[f].fill=filterTrue;
    if(typeof(filters[f].prepare)!='function')
       filters[f].prepare=filterTrue;
    if(typeof(filters[f].check)!='function')
       filters[f].check=filterTrue;
   }

 for(var s=0;s<sorters.length;s++)
    if(typeof(sorters[s].init)!='function')
       sorters[s].init=sorterRadioInit;

 if(typeof(results.init)!='function')
    results.init=resultsInit;
 if(typeof(results.filter)!='function')
    results.filter=resultsFilter;
 if(typeof(results.fill)!='function')
    results.fill=resultsFill;

 // Initialise the selector

 selector.init();

 // Initialise the filters

 for(var f=0;f<filters.length;f++)
    filters[f].init();

 // Initialise the sorter

 for(var s=0;s<sorters.length;s++)
    sorters[s].init();
 
 // Initialise the results

 results.init();

 // Fill in the selector list

 selector.fill();
}


//
// Function called when a selector is selected.
//

function selectFromSelectorList()
{
 if(selector.doc_select!=undefined)
    selector.doc_select.disabled=0;
}


//
// Get the data matching the selected option.
//

function getSelected()
{
 var url;

 // Initialise the forms

 for(var f=0;f<filters.length;f++)
    filters[f].init();

 results.init();

 // Select the data

 if(selector.fillurl)
   {
    var selected=selector.list[selector.doc_list.selectedIndex];

    url=selector.selecturl(selected);
   }
 else
   {
    if(typeof(selector.selecturl)=='function')
       url=selector.selecturl();
    else
       url=selector.selecturl;
   }

 // Use AJAX to get the information

 getServerArray(url,selector,gotSelected);

 pleaseWait("Fetching list of " + results.plural);
}


//
// Got the selected data
//

function gotSelected()
{
 selector.selected();

 updateFilters();
}


//
// Update the filters with the information.
//

function updateFilters()
{
 pleaseWait("Updating filter list(s)");

 window.setTimeout(updateFilters2,1);
}

function updateFilters2()
{
 for(var f=0;f<filters.length;f++)
    filters[f].update();

 window.setTimeout(updateFilters3,1);
}

function updateFilters3()
{
 for(var f=0;f<filters.length;f++)
    filters[f].fill(selector);

 // Act as if a new filter had been selected

 window.setTimeout(selectFromFilterList,1);
}


//
// Function called when a filter is selected.
//

function selectFromFilterList()
{
 // Initialise the forms

 results.init();

 results.select(-1);

 pleaseWait("Clearing " + results.plural);

 window.setTimeout(selectFromFilterList2,1);
}

function selectFromFilterList2()
{
 // Call the callback

 if(typeof(results.clear)=='function')
    results.clear();

 pleaseWait("Filtering " + results.plural);

 window.setTimeout(selectFromFilterList3,1);
}

function selectFromFilterList3()
{
 // Find the selected filters

 for(var f=0;f<filters.length;f++)
    filters[f].prepare();

 // Select the results

 results.filter(selector);

 // Act as if a new sorter had been selected

 selectFromSorterList();
}


//
// Function called when a filter is selected.
//

function selectFromSorterList()
{
 pleaseWait("Sorting " + results.plural);

 window.setTimeout(selectFromSorterList2,1);
}

function selectFromSorterList2()
{
 var sort=sorterChooseFunction(sorters);

 results.list.sort(sort);

 // Add the data to the list

 results.fill();

 if(typeof(results.update)=='function')
   {
    pleaseWait("Updating " + results.plural);

    window.setTimeout(selectFromSorterList3,1);
   }
 else
    pleaseWait(null);
}

function selectFromSorterList3()
{
 results.update();

 pleaseWait(null);
}


//
// Function called when a result is selected.
//

function selectFromResultList()
{
 results.select(results.doc_list.selectedIndex);
}


//
// -------------------- SELECTOR FUNCTIONS --------------------
//

//
// Initialise a selector
//

function selectorInit()
{
 this.doc_list=document.getElementById("selector_list");

 if(this.doc_list!=undefined)
   {
    this.doc_list.disabled=1;
    this.doc_list.options.length=0;
    this.doc_list.onchange=selectFromSelectorList;
   }

 this.doc_count=document.getElementById("selector_count");

 if(this.doc_count!=undefined)
    this.doc_count.innerHTML = "No data".italics();

 this.doc_select=document.getElementById("selector_select");

 if(this.doc_select!=undefined)
    this.doc_select.disabled=1;
}


//
// Fill in the selector list
//

function selectorFill()
{
 if(this.fillurl!=undefined)
   {
    var url;

    if(typeof(this.fillurl)=='function')
       url=this.fillurl();
    else
       url=this.fillurl;

    // Use AJAX to get the information

    getServerList(url,this,this.update);

    pleaseWait("Fetching list of " + this.plural);
   }
 else
    getSelected();
}


//
// Success in getting selector data.
//

function selectorUpdate()
{
 if(this.list.length==0)
   {
    // Fill in the list

    this.doc_list.options.length=0;

    if(this.doc_count!=undefined)
       this.doc_count.innerHTML = ("0 " + this.plural).italics();

    // Disable the list and select button

    this.doc_list.disabled=1;
   }
 else
   {
    // Fill in the list

    this.doc_list.options.length=0;

    for(var l=0;l<this.list.length;l++)
       this.doc_list.options[this.doc_list.options.length] = new Option(this.list[l],this.list[l]);

    if(this.doc_count!=undefined)
       this.doc_count.innerHTML = this.list.length + " " + (this.list.length==1 ? this.singular : this.plural);

    // Enable the list but disable the select button

    this.doc_list.disabled=0;
   }

 if(this.doc_select!=undefined)
    this.doc_select.disabled=1;

 pleaseWait(null);
}


//
// A selector has been selected
//

function selectorSelected()
{
}


//
// -------------------- FILTER FUNCTIONS --------------------
//

//
// Dummy function that returns true
//

function filterTrue()
{
 return(true);
}


//
// Initialise an auto-list filter
//

function filterAutoListInit()
{
 this.doc_count=document.getElementById("filter" + this.number + "_count");

 if(this.doc_count!=undefined)
    this.doc_count.innerHTML = "No data".italics();

 this.doc_list =document.getElementById("filter" + this.number + "_list");

 if(this.doc_list!=undefined)
   {
    this.doc_list.disabled=1;
    this.doc_list.options.length=0;
    this.doc_list.onchange=selectFromFilterList;
   }
}


//
// Initialise a checkbox custom filter
//

function filterCheckboxInit()
{
 this.doc_checkbox=document.getElementById("filter" + this.number + "_checkbox");

 this.doc_checkbox.onchange=selectFromFilterList;
}


//
// Update an auto-list filter
//

function filterAutoListUpdate()
{
 this.doc_list.disabled=1;

 this.doc_list.options.length=0;

 this.doc_list.options[0] = new Option("--- Updating List ---","");
}


//
// Fill an auto-list filter
//

function filterAutoListFill()
{
 this.list=[];

 for(var d=0;d<selector.data.length;d++)
   {
    var datum=selector.data[d][this.autolist.name];

    var l=0;

    for(;l<this.list.length;l++)
      {
       if(this.list[l] == datum)
          break;
      }

    if(l==this.list.length)
       this.list.push(datum);
   }

 if(typeof(this.sort)=='function')
    this.list.sort(this.sort);
 else
    this.list.sort(sortByDefault);

 // Add the data to the list

 this.doc_list.options.length=0;

 if(this.autolist.any)
   {
    this.doc_list.options[0] = new Option("== Any " + this.autolist.singular + " ==","*");
    this.doc_list.options[0].selected = true;
   }

 for(var l=0;l<this.list.length;l++)
    if(this.list[l]=="")
       this.doc_list.options[this.doc_list.options.length] = new Option("-- none specified --",this.list[l]);
    else
       this.doc_list.options[this.doc_list.options.length] = new Option(this.list[l],this.list[l]);

 if(this.doc_count!=undefined)
    this.doc_count.innerHTML = this.list.length + " " + (this.list.length==1 ? this.autolist.singular : this.autolist.plural);

 // Enable the list

 this.doc_list.disabled=0;
}


//
// Prepare to use the auto-list filter
//

function filterAutoListPrepare()
{
 this.selected=[];

 for(var s=0;s<this.doc_list.options.length;s++)
    if(this.doc_list.options[s].selected)
       this.selected.push(s);
}


//
// Check a datum against the auto-list filter
//

function filterAutoListCheck(datum)
{
 for(var s=0;s<this.selected.length;s++)
    if(this.autolist.any && this.selected[s]==0)
       return(true);
    else if(this.doc_list.options[this.selected[s]].value==datum[this.autolist.name])
       return(true);

 return(false);
}


//
// -------------------- SORTER FUNCTIONS --------------------
//

//
// Initialise the sorter
//

function sorterRadioInit()
{
 this.doc_radio=document.getElementById("sorter" + this.number + "_radio");

 if(this.doc_radio!=undefined)
    this.doc_radio.onchange=selectFromSorterList;
}


//
// Choose the sort function
//

function sorterChooseFunction(sorters)
{
 if(sorters.length==1)
    return(sorters[0].sort);

 for(var s=0;s<sorters.length;s++)
    if(sorters[s].doc_radio!=undefined && sorters[s].doc_radio.checked)
       return(sorters[s].sort);

 return(sortByDefault);
}

//
// Generic sort function
//

function sortByDefault(value1,value2)
{
 if(value1 < value2)
    return(-1);
 else if(value1 > value2)
    return(1);
 else
    return(0);
}


//
// Generic numeric sort function
//

function sortByDefaultNumeric(value1,value2)
{
 if(Number(value1) < Number(value2))
    return(-1);
 else if(Number(value1) > Number(value2))
    return(1);
 else
    return(0);
}


//
// -------------------- RESULTS FUNCTIONS --------------------
//

//
// Initialise the results
//

function resultsInit()
{
 this.doc_list=document.getElementById("results_list");

 if(this.doc_list!=undefined)
   {
    this.doc_list.disabled=1;
    this.doc_list.options.length=0;
    this.doc_list.onchange=selectFromResultList;
   }

 this.doc_count=document.getElementById("results_count");

 if(this.doc_count!=undefined)
    this.doc_count.innerHTML = "No data".italics();

 this.doc_info=document.getElementById("result_info");

 if(this.doc_info!=undefined)
    this.doc_info.innerHTML="";
}


//
// Select the results
//

function resultsFilter(selector)
{
 this.list=[];

 for(var d=0;d<selector.data.length;d++)
   {
    var datum=selector.data[d];
    var select=true;

    for(var f=0;f<filters.length && select;f++)
       select=select && filters[f].check(datum);

    if(select)
       this.list.push(selector.data[d]);
   }
}


//
// Fill the results list
//

function resultsFill()
{
 this.doc_list.options.length=0;

 for(var l=0;l<this.list.length;l++)
    if(this.list[l][this.name]=="")
       this.doc_list.options[this.doc_list.options.length] = new Option("-- no " + this.name + " --",l);
    else
       this.doc_list.options[this.doc_list.options.length] = new Option(this.list[l][this.name],l);

 if(this.doc_count!=undefined)
    this.doc_count.innerHTML = "Found " + this.list.length + " " + (this.list.length==1 ? this.singular : this.plural);

 // Enable the list

 this.doc_list.disabled=0;
}


//
// -------------------- POPUP DIV FUNCTIONS --------------------
//


//
// Indicate onscreen that something is happening
//

var please_wait_popup=null;
var please_wait_content=null;

function pleaseWait(string)
{
 if(please_wait_popup!=null && string==null)
   {
    please_wait_popup.style.display = "none";
    please_wait_popup.style.top = "-4000px";
    please_wait_popup.style.left = "-4000px";
   }

 if(string!=null)
   {
    if(please_wait_popup==null)
      {
       please_wait_popup = document.createElement('div');

       please_wait_popup.innerHTML = "<span>Please Wait".bold() + "</span><br>";

       please_wait_popup.style.display = "none";

       please_wait_popup.style.position = "absolute";
       please_wait_popup.style.top = "-4000px";
       please_wait_popup.style.left = "-4000px";
       please_wait_popup.style.zIndex = "100";

       please_wait_popup.style.textAlign = "center";
       please_wait_popup.style.backgroundColor = "yellow";
       please_wait_popup.style.padding = "10px";
       please_wait_popup.style.border = "solid 2px";

       document.body.appendChild(please_wait_popup);

       please_wait_content = document.createElement('span');

       please_wait_content.innerHTML = "";

       please_wait_popup.appendChild(please_wait_content);
      }

    please_wait_content.innerHTML = string;

    please_wait_popup.style.display = "";

    var window_width,window_height;

    if(window.innerWidth!=undefined)
      {
       window_height = window.innerHeight;
       window_width  = window.innerWidth;
      }
    else if(document.documentElement!=undefined && typeof(document.documentElement.clientWidth)=='number')
      {
       window_height = document.documentElement.clientHeight;
       window_width  = document.documentElement.clientWidth;
      }
    else
      {
       window_height = document.body.clientHeight;
       window_width  = document.body.clientWidth;
      }

    please_wait_popup.style.top  = ( (window_height - please_wait_popup.clientHeight) / 2 ) + "px";
    please_wait_popup.style.left = ( (window_width  - please_wait_popup.clientWidth ) / 2 ) + "px";
   }
}


//
// -------------------- AJAX FUNCTIONS --------------------
//


//
// Get a simple list of data from the server.
//

function getServerList(url,caller,callback)
{
 caller.callback=callback;

 // Use AJAX to get the data

 OpenLayers.loadURL(url,null,caller,getListSuccess,getFailure);
}


//
// Success in getting list.
//

function getListSuccess(response)
{
 var lines=response.responseText.split('\n');

 this.list=[];

 for(var line=0;line<lines.length;line++)
   {
    if(lines[line] != "")
       this.list[this.list.length]=lines[line];
   }

 if(typeof(this.callback)=='function')
    this.callback();
}


//
// Get an array of data from the server.
//

function getServerArray(url,caller,callback)
{
 caller.callback=callback;

 // Use AJAX to get the data

 OpenLayers.loadURL(url,null,caller,getArraySuccess,getFailure);
}


//
// Success in getting array data.
//

function getArraySuccess(response)
{
 var lines=response.responseText.split('\n');

 this.names=[];
 this.data=[];

 for(var line=0;line<lines.length;line++)
   {
    var words=lines[line].split('\t');

    if(line==0)
      {
       for(var word in words)
          this.names[word]=words[word];
      }
    else if(words[1]!=undefined)
      {
       this.data[this.data.length]={};

       for(var word in words)
          this.data[this.data.length-1][this.names[word]]=words[word];
      }
   }

 if(typeof(this.callback)=='function')
    this.callback();
}


//
// Failure in getting data.
//

function getFailure(response)
{
 window.alert("Failed to get valid response from server!\nError message was:\n" + response.statusText);

 pleaseWait(null);
}

