/**
 * Class for drawing search results, in a dropdown style div with arrow and mouse selection scrolling etc
 * @param       string       name you instantiate the object with (ex:  oS )
 * @param       string       id of input div, results div relies on appending '_results' to the id
 */
function Search(sObjName, sDivName)
{   
    var self              = this;
    this.sObjName         = sObjName;                
    this.sDivName         = sDivName;
    this.oInput           = document.getElementById(sDivName);   // input text object
    this.oSearch          = new Object();                        // object to hold search results data
    this.sDefault         = 'try it out yourself!';              // default search starting text.
    this.aSearchIndex     = new Array();                         // array of search match ids
    this.nActiveSearch    = false;                               // will hold the nActiveSearch member id
    this.nActiveSearchKey = false;                               // will hold the key for the value of nActiveSearch
    this.nResults         = 9;                                   // number of results to show before scrolling
    this.nSearchStart     = 0;                                   // start of search display
    this.nSearchEnd       = self.nResults;                       // end of search display also reset set here: => clearSearch();
    
    /*******************************************************
    * Set event handlers
    *******************************************************/
    
    // set onblur handler
    this.oInput.onblur = function ()
    {
        // only clear the search text onblur if it isn't the default text
        if (document.getElementById(sDivName).value != self.sDefault) setTimeout(sObjName + '.clearSearch()', 500);
    }
    
    // set onkeyup, if not arrow keys up and down
    this.oInput.onkeyup = function (event)
    {
        // set event to window.event for IE
        event = (event) ? event : window.event;
        if (event.keyCode != 38 && event.keyCode != 40) self.recipientSearch(event);
    }
    
    // set onkeydown, if arrow keys up and down
    this.oInput.onkeydown = function (event)
    {
        // clear if default text is there
        if (self.oInput.value == self.sDefault) self.oInput.value = ''; 
        // set event to window.event for IE
        event = (event) ? event : window.event;
        if (event.keyCode == 38 || event.keyCode == 40) self.recipientSearch(event);
    }    
    
    /*******************************************************
    * Standard methods...
    *******************************************************/    
    
    /**
     * Set the active search row
     * @param     string      (used to be INT but needed to prepend a 'g' or a 'm'
     *                         for groups and members since their id's are not unique
     *                         accross eachother.
     */
    this.setActiveSearch = function (nId, nKey)
    {
        var obj;
        
        if (self.nActiveSearch)
        {
            obj = document.getElementById(self.nActiveSearch + '_' + self.sDivName + '_div')
            if (obj) obj.style.backgroundColor = '#FFFFFF';
        }
        obj = document.getElementById(nId + '_' + self.sDivName + '_div')
        if (obj) obj.style.backgroundColor = '#C8DAEB';

        // document.getElementById(self.sDivName).value = self.oSearch[nId]['name'];
        
        self.nActiveSearch = nId;
        if (nKey) self.nActiveSearchKey = nKey;
    }    
    
    /**
     * Clear the search box and results display
     */
    this.clearSearch = function ()
    {
        self.clearActiveSearch();
        var obj = document.getElementById(self.sDivName + '_results');
        obj.style.visibility = 'hidden';
        obj.innerHTML = '';
        document.getElementById(self.sDivName).value = '';        
        //document.getElementById(self.sDivName).value = this.sDefault;        
    }    
    
    /**
     * Clear the search variables used for arrow navigation
     */
    this.clearActiveSearch = function ()
    {
        self.nActiveSearch    = false;
        self.nActiveSearchKey = false;
        self.nSearchStart     = 0;
        self.nSearchEnd       = self.nResults; 
    }

    /**
     * advance the search (scroll down one member)
     * If it is on mouseover we don't change the activeSearch var this is because
     * if you scroll without selecting someone else the selected person can go off 
     * the screen. So we solve this by not setting activeSearch
     * @param        boolean      mouseclick or not
     */
    this.advanceSearch = function (mouse)
    {
        self.nActiveSearchKey++;
        self.nSearchStart++;
        self.nSearchEnd++;
        self.drawSearch();      
        if (!mouse) self.setActiveSearch(self.aSearchIndex[self.nActiveSearchKey]);
    }
    
    /**
     * rewind the search (scroll up one member)
     * If it is on mouseover we don't change the activeSearch var this is because
     * if you scroll without selecting someone else the selected person can go off 
     * the screen. So we solve this by not setting activeSearch
     * @param        boolean      mouseclick or not
     */    
    this.rewindSearch = function (mouse)
    {
        self.nActiveSearchKey--;
        self.nSearchStart--;
        self.nSearchEnd--;
        self.drawSearch();                
        if (!mouse) self.setActiveSearch(self.aSearchIndex[self.nActiveSearchKey]);    
    }    

    /**
     * Run the sorting
     */
    this.setSort = function ()
    {
        self.aSearchIndex.sort(self.sort_caseinsensitive);
    }    
   
     /**
     * Call back function for javascript sort(), takes into account the sort order 
     * either ASC or DESC. See inline comments for clarification.
     */
    this.sort_caseinsensitive = function (a, b) 
    {   
        var aa = self.oSearch[a]['name'].toLowerCase();
        var bb = self.oSearch[b]['name'].toLowerCase();        
        if (aa == bb) return 0;
        else if (aa < bb) return -1;
        else return 1; 
    }  

    /********************************************************************
    * SEARCH STUFF
    *********************************************************************/
    
    /**
     * On key press either what do do. Clear input for first keypress, navigate up and down
     * with the arrow keys or on enter try to add someone.
     * @param       object       input field
     * @param       event        key press
     */
    this.recipientSearch = function (event)
    {
        // push the down arrow
        if (event.keyCode == 40)
        {
            if (self.aSearchIndex.length <= 0)
            {
                return;
            }
            // no current active search set it to the first record
            else if (self.nActiveSearchKey === false && self.aSearchIndex.length > 0)
            {
                self.nActiveSearchKey = 0;
                self.setActiveSearch(self.aSearchIndex[self.nActiveSearchKey]);
            }
            // you are on the last record so you can't advance more
            else if ((self.nActiveSearchKey < self.aSearchIndex.length) && (self.nActiveSearchKey < self.nSearchEnd) && (self.nActiveSearchKey < (self.aSearchIndex.length - 1)))
            {
                self.nActiveSearchKey++;
                self.setActiveSearch(self.aSearchIndex[self.nActiveSearchKey]);
            }
            // advance search one more space
            else if ((self.nActiveSearchKey < self.aSearchIndex.length) && (self.nActiveSearchKey == self.nSearchEnd) && (self.nSearchEnd < (self.aSearchIndex.length - 1)))
            {
                self.advanceSearch();
            }
        }
        // push the up arrow
        else if (event.keyCode == 38)
        {
            // go back one if you are on higher than the first record
            if (self.nActiveSearchKey == self.nSearchStart && self.nSearchStart > 0)
            {
                self.rewindSearch();
            }
            // if none selected select the first
            else if (self.nActiveSearchKey > 0)
            {
                self.nActiveSearchKey--;
                self.setActiveSearch(self.aSearchIndex[self.nActiveSearchKey]);
            }
        }        
        // push the enter key
        else if (event.keyCode == 13)
        {
                self.onEnter();
        }
        else
        {
            self.search(this.oInput.value);
        }
    }    
    
    /**
     * Draw the search results
     */
    this.drawSearch = function ()
    {
        aInnerHtml = new Array();
        var key;
        var i = 0;
        for (var j = 0; j < self.aSearchIndex.length; j++)
        {
            key = self.aSearchIndex[j];
            if (!self.oSearch[key]) continue;
            
            if (i < self.nSearchStart)
            {
                i++;
                continue;
            }
            
            if (self.nSearchStart > 0 && self.nSearchStart == i)
            {
                aInnerHtml.push('<div style="text-align: center" onmouseover="this.style.cursor = \'pointer\'; ' + self.sObjName + '.rewindSearch(\'true\');">');
                aInnerHtml.push('<span style="text-align: center">');
                aInnerHtml.push(sUpArrow);
                aInnerHtml.push('</span>');
                aInnerHtml.push('</div>');            
            }
            
            sClass = 'class="x-small"';
            aInnerHtml.push('<div id="' + key + '_' + self.sDivName + '_div" onmouseover="this.style.cursor = \'pointer\'; ' + self.sObjName + '.setActiveSearch(\'' + key + '\',' + j + ');" onclick="' + self.sObjName + '.onEnter();' + self.sObjName + '.clearSearch();">');
            aInnerHtml.push('<span ' + sClass + ' id="' + key + '">' + self.oSearch[key]['name'] + '</span>'); 
            aInnerHtml.push('</div>');           
            
            if (i == self.nSearchEnd && self.nSearchEnd < (self.aSearchIndex.length - 1))
            { 
                aInnerHtml.push('<div style="text-align: center" onmouseover="this.style.cursor = \'pointer\'; ' + self.sObjName + '.advanceSearch(\'true\');">');
                aInnerHtml.push('<span style="text-align: center">');
                aInnerHtml.push(sDownArrow);
                aInnerHtml.push('</span>');
                aInnerHtml.push('</div>');            
            }
            if (i == self.nSearchEnd) break;
            i++;
        }  
        
        var obj = document.getElementById(self.sDivName + '_results');  
        obj.innerHTML        = aInnerHtml.join("\n");
        obj.style.visibility = 'visible';
    }    

    /************************************************************************
    * Custom section for setting up what data you are searching
    * and what happens on selection
    ************************************************************************/
    
    /**
     * Perform the search
     * @param      string      search string
     */
    this.search = function (sInput)
    {
        var req = ajaxQuery( 'api/search.php?search=' + sInput,
            function(n, response) {
              self.processSearchData(n, response, sInput); } );
    }

    /**
     * process the search input string
     * @param       int      ajax response number
     * @param       obj      XMLresponse
     * @param       string   search input string
     */
    this.processSearchData = function (n, response, sInput)
    {
        if (!checkXML(response)) return;
        self.oSearch      = Object();
        self.aSearchIndex = Array();
        self.clearActiveSearch();
        
        var beerXML = response.getElementsByTagName('beer');
        
        var oSearches = new Array();
        for (var i = 0; i < beerXML.length; i++)
        {
            var nId = beerXML[i].getAttribute('id');
            oSearches[nId] = new Object();
            oSearches[nId]['name'] = (beerXML[i].hasChildNodes()) ? beerXML[i].firstChild.data : '';
        }
        if (!sInput) var sInput = '';
        if (sInput.length > 0)
        {
            var sTrimInput = trimString(sInput);
            // escape meta regex characters
            var sEscapeInput = sTrimInput.replace(/(\(|\)|\-|\[|\]|\<|\>|\{|\}|\.|\||\^|\$|\*|\+|\?|\&|\\)/g, '\\$1');
            
            // set up the regex for names
            var sNamePattern = '(' + sEscapeInput + ')';
            var nameReg      = new RegExp(sNamePattern, 'i');

            // run the search on the keys
            for (var key in oSearches)
            {       
                if (oSearches[key] && oSearches[key] != null)
                {
                    if (nameReg.test(oSearches[key]['name']))
                    {
                        self.oSearch[key] = new Object();
                        self.oSearch[key]['name'] = oSearches[key]['name'];
                        self.aSearchIndex.push(key);
                        // OLD USED TO COLOR THE MATCHING PART
                        // self.oSearch[key]['name'] = oSearches[key]['name'].replace(nameReg, '<span class="highlight">$1</span>');
                    }    
                }
            }
            if (self.aSearchIndex.length > 0) self.setSort();
            self.drawSearch();
        }
        else
        {
            self.clearSearch();
        }        
        
    }
    
    /**
     * Add a member to selected list if enter is pressed while searching
     * and there is only one match
     */
    this.onEnter = function ()
    { 
        load_beer(self.nActiveSearch);
        load_reviews(self.nActiveSearch);
        self.clearSearch();
    }      
   
}
  