var ajaxurl = "http://www.cleanroom-technology.co.uk//system3/ajaxServer.php";

function trace(str) {
    var ul = getElemId("ulTrace");
    if (ul != null) {
        ul.innerHTML += "<li>"+str+"</li>";
    }
}
var searchInfo = new Array();
var ajaxObj = getAjaxObject();

function autoSuggest2(id, resWrapID, resListID, operation, e, fFormatter, fAction, pOther) {
    var keyCode = getKeyCode(e, 'keyup');
    if (keyCode == 40 || keyCode == 38 || keyCode == 13) {// ignore up and down arrows and return
        return false;
    }

    var searchInput = trim(getElemId(id).value);
    trace("term typed: " + searchInput);
    if (searchInput == '') {
        suggest.reset();
        return;
    }
    var sA = suggest.findSearchArea(id);
    if (sA == null) {
        sA = new searchArea(id, resWrapID, resListID, operation, fFormatter, fAction, pOther);
        suggest.addSearchArea(sA);
    }
    sA.addSearch();
    return false;
}

function getAjaxObject() {
    var XMLHttpRequestObject = false;
    if (window.XMLHttpRequest) {
        XMLHttpRequestObject = new XMLHttpRequest();
    }
    else if (window.ActiveXObject) {
        XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP");
    }
    if (!XMLHttpRequestObject) {
        alert("Your browser does not support Ajax.");
        return false;
    }
    return XMLHttpRequestObject;
}

function sendRequest(xmlHTTPObject, parameters, handleResponse, id) {
    if (xmlHTTPObject) {
        if (xmlHTTPObject.readyState == 4 || xmlHTTPObject.readyState == 0) {
            xmlHTTPObject.open("POST", ajaxurl, true);
            xmlHTTPObject.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            xmlHTTPObject.onreadystatechange = function() {handleResponse(id)};
            xmlHTTPObject.send(parameters);
        }
    }
}
function handleSuggestResponse(id) {
    if (ajaxObj.readyState == 4) {
        if (ajaxObj.status == 200) {
            try {
                var search = suggest.findRequestMarkActive(id);   //searchInfo[id];
                
                if (search == null || search == undefined) {
                    alert('no search information available for ' + id);
                    return;
                }
                if (ajaxObj.responseText == undefined) {
                    if (search.NumRetries == 3) {
                        alert('unable to get data after 3 goes');
                        return;
                    }
                    ++search.NumRetries;
                    setTimeout('handleSuggestResponse("' + id + '")', 100);
                    return;
                }
                trace("response " + id + " to " + search.searchText);
                search.Status = StateCompleted;
                // extract list of responses
                var XMLResponse = ajaxObj.responseXML.documentElement;
                // work with the xml response
                var keywordsTag = XMLResponse.getElementsByTagName('item');

                search.searchResults = new Array();
                for (var i = 0; i < keywordsTag.length; i++) {
                    var row = keywordsTag.item(i);
                    if (row.nodeType == 1)    // elements only
                    {
                        var info = new Array();
                        search.searchResults.push(info);
                        for (var itemNum = 0; itemNum < row.childNodes.length; ++itemNum) {
                            var node = row.childNodes[itemNum];
                            if (node.nodeType == 1) {
                                var item = node.firstChild.data.toString();
                                info[node.nodeName] = item;
                            }
                        }
                    }
                }
                search.showResults();
            }
            catch (e) {// on error show alert and clost box
                suggest.hideAll();
                if (trim(ajaxObj.responseText) !== "")
                    alert(e.description + "\n" + e.lineNumber + "\n" + ajaxObj.responseText);
            }
        }
    }
}

function searchArea(id, resWrapID, resListID, operation, fFormatter, fAction, pOther) {
    this.index = 0;
    this.ActiveDisplay = null;
    this.LastSearchReq = null;
    this.searches = new Array();
    this.id = id;
    this.ResWrap = getElemId(resWrapID);
    this.ResList = getElemId(resListID);
    this.Operation = operation;
    this.Formatter = fFormatter;
    this.OnSelect = fAction;
    this.Other = pOther;
    this.activeIndex = -1;

    function _resultID(index) {
        return this.id + "-" + index;
    }
    function _LowlightActive() {
        var selected = getElemId(this.resultID(this.activeIndex));
        selected.style.backgroundColor = "#F9F9F9";
        selected.style.color = "#006";
    }
    function _HighlightActive() {
        var selected = getElemId(this.resultID(this.activeIndex));
        selected.style.backgroundColor = "#555";
        selected.style.color = "#FFF";
    }

    function _HandleKey(keyCode) {
        if (this.ActiveDisplay == null)
            return true;
            
        if (keyCode == 40) // down arrow
        {
            if (this.activeIndex == -1) {
                this.activeIndex = 0;
                this.highlightActive();
            }
            else {
                if (this.activeIndex >= 0 && this.activeIndex < this.ActiveDisplay.countItems() - 1) {
                    if (this.activeIndex < this.ActiveDisplay.countItems() - 1)
                        this.lowlightActive();
                    this.activeIndex++;
                    this.highlightActive();
                }
            }
        }
        else if (keyCode == 38) //up arrow
        {
            if (this.activeIndex > 0) {
                this.lowlightActive();
                this.activeIndex--;
                this.highlightActive();
            }
        }
        else if (keyCode == 27) { // escape
            this.hide();
        }
        else if (keyCode == 13 && this.activeIndex > -1) // enter
        {
            if (this.ActiveDisplay != null)
                this.ActiveDisplay.selectResult();
            return false;
        }
        return true;
    }
    
    function _FindByIndex(index) {
        for (var i = 0; i < this.searches.length; ++i) {
            if (this.searches[i].Index == index)
                return i;
        }
        return -1;
    }
    function _FindCached(str) {
        for (var i = 0; i < this.searches.length; ++i) {
            if (str.toLowerCase() == this.searches[i].searchText.toLowerCase())
                return this.searches[i];
        }
        return null;
    }
    function _ActiveFromOffset(index) {
        this.ActiveDisplay = this.searches[index];
        return this.ActiveDisplay;
    }
    function _Add(search) {
        if (this.searches.length > 20)
            this.searches.shift();
        search.Index = this.index++;
        this.LastSearchReq = search;
        this.searches.push(search);
    }
    function _AddSearch() {
        var text = getElemId(this.id).value;
        var existing = this.findCached(text);

        if (existing != null) {
            this.LastSearchReq = existing;
            if (existing.Status == StateCompleted) {
                trace("reponse from cache to " + this.LastSearchReq.searchText);
                existing.showResults();
            }
        }
        else { // new search
            this.add(new searchDetails(text, this));
        }
    }
    function _Poll() {
        if (this.LastSearchReq == null || this.LastSearchReq.Status != StateInit)
            return;
        this.LastSearchReq.doSearch();
    }
    function _HasTargetID(id) {
        if (this.searches.length == 0)
            return false;
        else
            return this.searches[0].targetID == id;
    }
    function _Hide() {
        this.ResWrap.style.visibility = "hidden";
    }
    function _Show() {
        this.ResWrap.style.visibility = "visible";
    }

    this.resultID = _resultID;
    this.highlightActive = _HighlightActive;
    this.lowlightActive = _LowlightActive;
    this.handleKey = _HandleKey;
    this.findByIndex = _FindByIndex;
    this.findCached = _FindCached;
    this.activeFromOffset = _ActiveFromOffset;
    this.add = _Add;
    this.poll = _Poll;
    this.hasTargetID = _HasTargetID;
    this.hide = _Hide;
    this.show = _Show;
    this.addSearch = _AddSearch;
}
function autoEngine() {

    this.Requests = new Object();
    this.LastSearch = null;

    function _FindSearchArea(id) {
        if (id in this.Requests) {
            this.LastSearch = this.Requests[id];
            return this.LastSearch;
        }
        else
            return null;
    }
    function _AddSearchArea(sa) {
        this.Requests[sa.id] = sa;
        this.LastSearch = sa;
    }
    function _FindRequestMarkActive(searchid) {
        var last = searchid.lastIndexOf('_');
        var id = searchid.substr(0, last);
        var search_index = searchid.substr(last+1);
        var instance = this.Requests[id];
        var ins_index = instance.findByIndex(search_index);
        if (ins_index == -1)
            return null;
        else {
            return instance.activeFromOffset(ins_index);
        }
    }
    function _AddRequest(searchReq) {
        if (searchReq.id in this.Requests)
            this.LastSearch = this.Requests[searchReq.id];
        else 
        {
            this.Requests[searchReq.id] = new searchArea();
            this.LastSearch = this.Requests[searchReq.id];
        }
        var existing = this.LastSearch.findCached(searchReq.searchText);

        if (existing != null) {
            this.LastSearch.LastSearchReq = existing;
            if (existing.Status == StateCompleted) {existing.showResults();}
        }
        else { // new search
            this.LastSearch.add(searchReq);
//            searchReq.doSearch();
        }
    }
    function _GetActiveDisplay(id) {
        if (!(id in this.Requests))
            return null;
        var instance = this.Requests[id];
        return instance.ActiveDisplay;
    }
    function _Poll() {
        if (this.LastSearch == null)
            return;
        if (ajaxObj.readyState == 4 || ajaxObj.readyState == 0) {this.LastSearch.poll();}
    }
    function _InTarget(id) {
        for (var instance in this.Requests) {
            if (this.Requests[instance].ResWrap.id == id)
                return true;
        }
        return false;
    }
    function _HideAllExcept(item) {
        for (var instance in this.Requests) {
            if (this.Requests[instance].ResWrap != item) {this.Requests[instance].hide();}
        }
    }
    function _HideAll() {
        for (var instance in this.Requests) {this.Requests[instance].hide();}
    }
    function _Reset() {
        this.hideAll();
        this.LastSearch.LastSearchReq = null;
    }

    this.findRequestMarkActive = _FindRequestMarkActive;
    this.addRequest = _AddRequest;
    this.getActiveDisplay = _GetActiveDisplay;
    this.poll = _Poll;
    this.inTarget = _InTarget;
    this.hideAllExcept = _HideAllExcept;
    this.hideAll = _HideAll;
    this.findSearchArea = _FindSearchArea;
    this.addSearchArea = _AddSearchArea;
    this.reset = _Reset;
}

var suggest = new autoEngine();
function pollSuggest() {suggest.poll();}
setInterval(pollSuggest, 100);


var StateInit = 0;
var StateRequested = 1;
var StateCompleted = 2;
var StateAborted = 3;

function searchDetails(text, parent) {
    this.parent = parent;
    this.searchText = text;
    this.searchResults = new Array();
    this.NumRetries = 0;
    this.Status = StateInit;
    this.Index = -1;

    // utilities
    function _searchID() {
        return this.parent.id + "_" + this.Index;
    }
    function _ValueOfIndex(index, name) {
        return this.searchResults[index][name];
    }
    function _SetSelectedSearch() {
        this.parent.setInputString(this.valueOfIndex(this.activeIndex, "name"));
    }
    function _SetInputString(str) {
        var input = getElemId(this.parent.id);
        input.value = str;
        input.focus();
    }
    function _CountItems() {
        return this.searchResults.length;
    }
    function _HighlightString(str) {
        try {
            var regex = new RegExp('(' + this.searchText + ')', 'gi');
            ToDisplay = html_entity_decode(str);
            ToDisplay = ToDisplay.replace(regex, "<b>$1</b>");
            return ToDisplay
        } catch (e) {
            alert("bad something " + str);
            return str;
        }
    }
    // display

    function _ShowSearchResults() {
        if (this.parent.LastSearchReq == null) // aborted
        {
            this.parent.hide();
            return;
        }
        this.parent.activeIndex = -1;
        if (this.countItems() == 0) {
            this.parent.hide();
            return;
        }
        else
            this.parent.show();

        this.parent.ResList.innerHTML = "";
        for (var i = 0; i < this.countItems(); i++) {
            var ToDisplay;
            if (this.parent.Formatter == null) {
                ToDisplay = this.searchResults[i]["name"];
                ToDisplay = this.highlightString(ToDisplay);
                this.parent.ResList.innerHTML += "<li><a id='" + this.parent.resultID(i) + "' href=\"javascript:void(0);\" onclick=\"as_SelectResult('" + this.parent.id + "', '" + i + "');\">" + ToDisplay + "</a></li>";
            }
            else {
                ToDisplay = this.parent.Formatter(this, i);
                this.parent.ResList.innerHTML += ToDisplay;
            }
        }
    }


    function _SelectResultByIndex(index) {
        if (this.parent.OnSelect == null) {
            var row = this.searchResults[index];
            this.parent.hide();
            this.setInputString(row['name']);
        }
        else {
            this.parent.activeIndex = index;
            this.parent.OnSelect(this);
        }
    }
    function _SelectResult() {this.selectResultByIndex(this.parent.activeIndex);}

    // searching

    function _DoSearch() {
        var params = "operation=" + this.parent.Operation + "&name=" + escape(this.searchText);
        if (this.parent.Other)
            params += '&other=' + this.parent.Other;
        this.Status = StateRequested;
        trace("performing search id = " + this.s_ID() + ", term = " + this.searchText);
        sendRequest(ajaxObj, params, handleSuggestResponse, this.s_ID());
    }
    this.s_ID = _searchID;
    this.valueOfIndex = _ValueOfIndex;
    this.setSelectedSearch = _SetSelectedSearch;
    this.setInputString = _SetInputString;
    this.countItems = _CountItems;
    this.highlightString = _HighlightString;

    this.showResults = _ShowSearchResults;
    this.selectResult = _SelectResult;
    this.selectResultByIndex = _SelectResultByIndex;
    this.doSearch = _DoSearch;
}

function keyBoardNav(e, id) {

    var keyCode = getKeyCode(e, 'keydown');
    var search = suggest.findSearchArea(id);
    if (search == null)
        return true;
    return search.handleKey(keyCode);
}


function as_SelectResult(id, index) {
    var search = suggest.getActiveDisplay(id);
    if (search != null)
        search.selectResultByIndex(index);
}

function getKeyCode(e, action) {
    e = (!e) ? window.event : e;
    code = (e.charCode) ? e.charCode : ((e.keyCode) ? e.keyCode : ((e.which) ? e.which : 0));
    if (e.type == action) {
        return code;
    }
}

function getElemId(id) {
    if (document && document.getElementById(id)) {
        return document.getElementById(id);
    }
    else {
        return false;
    }
}

function trim(s) {
    return s.replace(/(^\s+)|(\s+$)/g, "");
}

function html_entity_decode(str) {
    try {
        var tarea = document.createElement('textarea');
        tarea.innerHTML = str; return tarea.value;
        tarea.parentNode.removeChild(tarea);
    }
    catch (e) {
        //for IE add <div id="htmlconverter" style="display:none;"></div> to the page
        document.getElementById("htmlconverter").innerHTML = '<textarea id="innerConverter">' + str + '</textarea>';
        var content = document.getElementById("innerConverter").value;
        document.getElementById("htmlconverter").innerHTML = "";
        return content;
    }
}

document.onclick = check;

function check(e) {
    var target = (e && e.target) || (event && event.srcElement);
    var found = null;
    while (target.parentNode != null) {
        if (suggest.inTarget(target.id)) {
            found = target;
            break;
        }
        target = target.parentNode;
    }
    suggest.hideAllExcept(found);
}
function jsWebSafe(coname) {
    var str = coname.replace("&", " and ");
    str = str.replace(" ", "_");
    str = str.replace("__", "_");
    str = str.replace("/[^a-zA-Z0-9-_\s]/", "");
    if (str.length > 100)
        str = str.substring(0, 100);
    return str;
}

