// This javascript file provides the dynamic functionality of a querybox.
// @author Michael.Heydlauf
// @version 0.7

var m_timer = false;
var m_timeout = 750;
var m_lastQuery = "";
var m_sublistfilter = "off";
var m_inited = false;
var m_isIE = false;
var m_isIE7 = false;
var m_request = false;
var m_highlightID = false;
var m_shadowID = false;
var m_resultID = false;
var m_inputField = false;
var m_inputID = false;
var m_fieldcode = false;
var m_hiddenField = false;
var m_localeString = false;
var m_allowfreetext = false;
var m_resultsDiv = false;
var m_IFrameId = false;
var m_repeaterSectionName = "";
var m_repeaterIndex = 0;

//--------------------------------------------------------------------------------------------------
// Initializes the input field and sets up the dhtml divs if not already initalized
// p_fieldName the name/id assigned to the textbox to be querybox enabled (usually something like cp.peopleclick...fielddef)
// p_fieldcode the fielddef code (i.e. the fielddef code alone (without any cp.peopleclick... qualifiers)
// p_hiddenField the name/id of the hidden field (for queryboxes that do not allow free text
// p_locale the locale of the querybox area
// p_allowfreetext "true" if any text should be allowed, "false" to force a value from the list
//--------------------------------------------------------------------------------------------------
function dqbInit(p_fieldName,p_fieldcode,p_hiddenField, p_locale, p_allowfreetext, p_sublistfilter, p_repeaterSectionName, p_repeaterIndex)
{
    var retVal = true;
    if (m_inited == false || p_fieldName != m_inputID)
    {
        retVal = false;
        dqbCleanup();
        m_inited = true;
        m_inputID = p_fieldName;
        m_IFrameId = m_inputID + "Iframe";
        m_fieldcode =p_fieldcode;
        m_hiddenField =p_hiddenField;
        m_localeString = p_locale;
        m_allowfreetext =p_allowfreetext;
        m_sublistfilter = p_sublistfilter;
        m_repeaterSectionName = p_repeaterSectionName;
        m_repeaterIndex = p_repeaterIndex;
        m_highlightID = "dqbHighlight"// + m_inputID;
        m_shadowID = "dqbShadow"// + m_inputID;
        m_resultID = "dqbResult"// + m_inputID;
        m_inputField = document.getElementById(m_inputID);
        if (navigator.userAgent.indexOf("Safari") > 0)
        {
            m_inputField.addEventListener("keyup",dqbSpecialKeyHandler,false);
            m_inputField.addEventListener("blur",dqbOnBlur,false);
        }
        else if (navigator.product == "Gecko")
        {
            m_inputField.addEventListener("keypress",dqbSpecialKeyHandler,false);
            m_inputField.addEventListener("blur",dqbOnBlur,false);
        }
        else
        {
            m_inputField.attachEvent('onkeydown',dqbSpecialKeyHandler);
            m_inputField.attachEvent("onblur",dqbOnBlur,false);
            m_isIE = true;
            m_isIE7 = isIE7();
        }

        m_inputField.setAttribute("autocomplete","off");
        // add the dropdown div
        m_resultsDiv = document.createElement("DIV");
        var shadowDiv = document.createElement("DIV");
        shadowDiv.id = m_shadowID;
        m_resultsDiv.id = m_resultID;
        m_resultsDiv.style.zIndex="100";
        m_resultsDiv.style.visibility="hidden";
        m_resultsDiv.style.position="absolute";
        dqbSetResultsDivPosition();
        m_resultsDiv.appendChild(shadowDiv);
        document.body.appendChild(m_resultsDiv);
    }
    return retVal;
}

//--------------------------------------------------------------------------------------------------
// function that returns if true or false based on userAgent information for IE 7
//--------------------------------------------------------------------------------------------------
function isIE7()
{
    return (navigator.userAgent.indexOf("MSIE 7") > -1);
}

//--------------------------------------------------------------------------------------------------
// Clears the timer used to fire ajax events
//--------------------------------------------------------------------------------------------------
function dqbClearTimer()
{
    if (m_timer)
    {
        window.clearTimeout(m_timer);
        m_timer = false;
    }
}

//--------------------------------------------------------------------------------------------------
// Performs cleanup so that a new text box perform dynamic queries .. removes event handlers, removes
// dhtml div tags, etc.
//--------------------------------------------------------------------------------------------------
function dqbCleanup()
{
    dqbClearTimer();
    if (m_resultsDiv)
    {
        document.body.removeChild(m_resultsDiv);
    }

    if (m_inputField && navigator.userAgent.indexOf("Safari") > 0)
    {
        m_inputField.removeEventListener("keyup",dqbSpecialKeyHandler,false);
        m_inputField.removeEventListener("blur",dqbOnBlur,false);
    }
    else if (m_inputField && navigator.product == "Gecko")
    {
        m_inputField.removeEventListener("keypress",dqbSpecialKeyHandler,false);
        m_inputField.removeEventListener("blur",dqbOnBlur,false);
    }
    else if (m_inputField)
    {
        m_inputField.detachEvent('onkeydown',dqbSpecialKeyHandler);
        m_inputField.detachEvent("onblur",dqbOnBlur);
        m_isIE = true;
        m_isIE7 = isIE7();
    }
    m_inited = false;
}

//--------------------------------------------------------------------------------------------------
// Calculates the size of the dhtml results DIV based off of the parent textbox size
// 
// Added IE7 check so that querybox would render properly.
// Long entries were bleeding over the style.width allocated area.
//--------------------------------------------------------------------------------------------------
function dqbSetResultsDivPosition()
{
    if (m_resultsDiv)
    {
        m_resultsDiv.style.left = dqbCalculateOffset(m_inputField, "offsetLeft", 2);
        m_resultsDiv.style.top = dqbCalculateOffset(m_inputField, "offsetTop", m_inputField.offsetHeight-1);

        // in IE7, long display entries in the querybox are bleeding over (outside) the dropdown area
        if (m_isIE && !m_isIE7)
        {
            m_resultsDiv.style.width = m_inputField.offsetWidth + "px";
            m_resultsDiv.noWrap = true;
        }
    }
}

//--------------------------------------------------------------------------------------------------
// Walks a controls parent tree to calculate client offsets
// p_parentCtl the control with which to start calculating offsets
// p_offsetType "offsetLeft", "offsetTop" etc .. the name of the offset property to calcuate
// p_startingPoint an integer offset to begin our calculations with -- basically is just added to the total offset caclulated.
//--------------------------------------------------------------------------------------------------
function dqbCalculateOffset(p_parentCtl, p_offsetType, p_startingPoint)
{
    var offset = p_startingPoint;
    while (p_parentCtl)
    {
        offset += p_parentCtl[p_offsetType];
        p_parentCtl = p_parentCtl.offsetParent;
    }
    return offset + "px";
}

//--------------------------------------------------------------------------------------------------
// Hides the results DHTML div
//--------------------------------------------------------------------------------------------------
function dqbHideResults()
{
    if (m_request && m_request.readyState < 4)
    {
        m_request.abort();
        m_request = null;
    }

    var highlight = document.getElementById(m_highlightID);
    if (highlight)
    {
        highlight.removeAttribute("id");
    }

    if (document.getElementById(m_resultID))
    {
        document.getElementById(m_resultID).style.display = "none";
        var IfrRef = document.getElementById(m_IFrameId);
        IfrRef.style.display = "none";
    }
    m_lastQuery = "";
}

//--------------------------------------------------------------------------------------------------
// On down arrow key handler
//--------------------------------------------------------------------------------------------------
function dqbOnArrowDown(p_event)
{
    var highlight = false;
    highlight = document.getElementById(m_highlightID);
    if (!highlight)
    {
        highlight = document.getElementById(m_shadowID).firstChild.firstChild;
    }
    else
    {
        highlight.removeAttribute("id");
        highlight = highlight.nextSibling;
    }

    if (highlight)
    {
        highlight.setAttribute("id",m_highlightID);
    }

    if (!m_isIE)
    {
        p_event.preventDefault();
    }
}

//--------------------------------------------------------------------------------------------------
// On up arrow key handler
//--------------------------------------------------------------------------------------------------
function dqbOnArrowUp(p_event)
{
    var highlight = false;
    highlight = document.getElementById(m_highlightID);
    if (!highlight)
    {
        highlight = document.getElementById(m_resultID).firstChild.firstChild.lastChild;
    }
    else
    {
        highlight.removeAttribute("id");
        highlight = highlight.previousSibling;
    }

    if (highlight)
    {
        highlight.setAttribute("id",m_highlightID);
    }

    if (!m_isIE)
    {
        p_event.preventDefault();
    }
}

//--------------------------------------------------------------------------------------------------
// On "Enter" key handler
//--------------------------------------------------------------------------------------------------
function dqbOnEnter(p_event)
{
    var highlight = false;
    highlight = document.getElementById(m_highlightID);
    if (highlight)
    {
        dqbOnSelectValue(highlight.firstChild.innerHTML);
    }

    if (!m_isIE)
    {
        p_event.preventDefault();
    }
}

//--------------------------------------------------------------------------------------------------
// On "Esc" key handler
//--------------------------------------------------------------------------------------------------
function dqbOnEsc(p_event)
{
    dqbHideResults();
    if (!m_isIE)
    {
        p_event.preventDefault();
    }
}

//--------------------------------------------------------------------------------------------------
// Sets the window timeout
//--------------------------------------------------------------------------------------------------
function dqbSetTimeout(p_method, p_elapse)
{
    if (m_timer == false)
    {
        window.clearTimeout(m_timer);
        m_timer = window.setTimeout(p_method, p_elapse);
    }
}

//--------------------------------------------------------------------------------------------------
// On "backspace" key handler
//--------------------------------------------------------------------------------------------------
function dqbOnBackspace(p_event)
{
    dqbSetTimeout("dqbPerformQuery()", m_timeout);
}

//--------------------------------------------------------------------------------------------------
// Handler for keys we want to process specially: enter, up, down, backspace, esc.  One of our on key press
// handlers
//--------------------------------------------------------------------------------------------------
function dqbSpecialKeyHandler(p_event)
{
    var retVal = false;
    if (p_event.keyCode == 40)
    {
        dqbOnArrowDown(p_event);
    }
    else if (p_event.keyCode == 38)
    {
        dqbOnArrowUp(p_event);
    }
    else if (p_event.keyCode == 13)
    {
        dqbOnEnter(p_event);
    }
    else if (p_event.keyCode == 27)
    {
        dqbOnEsc(p_event);
    }
    else if (p_event.keyCode == 8)
    {
        dqbOnBackspace(p_event);
        retVal = true;
    }
    else if (p_event.keyCode == 9) // the tab key
    {
        // we don't have any special handling, but we
        // don't want the tab to fire another query
        retVal = true;
    }
    else
    {
        retVal = true;
        //dqbCreateQueryTimer();
        dqbSetTimeout("dqbPerformQuery()", m_timeout);
    }
    return retVal;
}

//--------------------------------------------------------------------------------------------------
// Our other keypress handler -- called each time a key is pressed and kicks off a timer to start a new search
//--------------------------------------------------------------------------------------------------
function dqbOnKeyPress(p_fieldName,p_fieldcode,p_hiddenField, p_locale,p_allowfreetext, p_sublistfilter, p_repeaterSectionName, p_repeaterIndex)
{
    var alreadyInited = dqbInit(p_fieldName,p_fieldcode,p_hiddenField, p_locale,p_allowfreetext, p_sublistfilter, p_repeaterSectionName, p_repeaterIndex);
    // this is necessary because the very first key pressed will not cause a query (because the other key press)
    // handler is not setup until init is called.
    if (alreadyInited == false)
    {
        //dqbCreateQueryTimer();
        dqbSetTimeout("dqbPerformQuery()", m_timeout);
    }
}

//--------------------------------------------------------------------------------------------------
// Ajax call to server to perform a query
//--------------------------------------------------------------------------------------------------
function dqbPerformQuery()
{
    dqbClearTimer();
    if (m_lastQuery != m_inputField.value)
    {
        m_lastQuery = m_inputField.value;
        dqbAjaxRequestProxy("querybox", "dqbOnQueryResponse");
    }
}

//--------------------------------------------------------------------------------------------------
// Finds the appropriate DIV result given a value
// value - the display value of the DIV element you want to find.
//--------------------------------------------------------------------------------------------------
function dqbFindDivFromValue(value)
{
    var thisElement = document.getElementById(m_shadowID).firstChild.firstChild;
    var done = false
    while (!done)
    {
        var thisValue = thisElement.firstChild.innerHTML

        thisValue = escapeXml(thisValue);

        if (thisValue == value)
        {
            return thisElement;
        }

        if (thisElement.nextSibling.nodeType != 1)
        {
            done = true;
        }
        thisElement = thisElement.nextSibling;
    }
    return null;
}

//--------------------------------------------------------------------------------------------------
// Called when the mouse button is clicked on a result .. handler setup in DynamicQueryBoxAjaxHandler.java
//--------------------------------------------------------------------------------------------------
function dqbOnMouseDown(value)
{
    dqbOnSelectValue(value);
}

//--------------------------------------------------------------------------------------------------
// Called when the mouse moves over the results DIV .. handler setup in DynamicQueryBoxAjaxHandler.java
//--------------------------------------------------------------------------------------------------
function dqbOnMouseOver(value)
{
    var highlight = document.getElementById(m_highlightID);
    if (!highlight)
    {
        highlight = dqbFindDivFromValue(value);
    }
    else
    {
        highlight.removeAttribute("id");
    }
    if (highlight)
    {
        highlight.setAttribute("id",m_highlightID);
    }
}

//--------------------------------------------------------------------------------------------------
// Called when the mouse moves out of the results DIV.. handler setup in DynamicQueryBoxAjaxHandler.java
//--------------------------------------------------------------------------------------------------
function dqbOnMouseOut(value)
{
    var highlight = document.getElementById(m_highlightID);
    if (highlight)
    {
        highlight.removeAttribute("id");
    }
}

//--------------------------------------------------------------------------------------------------
// Called when a value is selected
// value - the selected value
//--------------------------------------------------------------------------------------------------
function dqbOnSelectValue(value)
{
    dqbHideResults();
    var trimed = Trim(value);
    m_lastQuery = trimed;

    trimed = escapeXml(trimed);

    m_inputField.value=trimed
    // If we're doing ajax slf, we need to get the key for the selected value in order to
    // do the filtering. dqbEnforceValidValue retrieves the key for us so we can do it.
    if (m_allowfreetext == "false" && m_sublistfilter == "ajax")
    {
        dqbSetTimeout("dqbEnforceValidValue()", 200);
    }
}

//--------------------------------------------------------------------------------------------------
// Ajax call to the server to see if the current value in the textbox is a part of the list.. if it is,
// the server will return the key for that value... only used if allowfreetext is false
//--------------------------------------------------------------------------------------------------
function dqbEnforceValidValue()
{
    dqbClearTimer();
    // Make lookup synchronous because we need to wait for it to finish
    dqbAjaxRequestProxyGeneric("dlkeylookup", "dqbOnFindKeyResponse", false);
}

function showResultsDiv()
{
    var divRef = document.getElementById(m_resultID);
    divRef.style.display = "block";
    if (m_isIE)
    {
        var IfrRef = document.getElementById(m_IFrameId);
        IfrRef.style.width = divRef.offsetWidth;
        IfrRef.style.height = divRef.offsetHeight;
        IfrRef.style.top = divRef.style.top;
        IfrRef.style.left = divRef.style.left;
        IfrRef.style.zIndex = divRef.style.zIndex - 1;
        IfrRef.style.display = "block";
    }
    m_resultsDiv.style.visibility="visible";
}

//--------------------------------------------------------------------------------------------------
// Function to handle the server ajax response on a query request.  Shows the DHTML results.
//--------------------------------------------------------------------------------------------------
function dqbOnQueryResponse(p_request)
{
    if (p_request && p_request.responseXML)
    {
        var response  = p_request.responseXML.documentElement;
        // Hide the results div if we didn't get any hits in our response
        if (response && response.getElementsByTagName("DIV") != null)
        {
            document.getElementById(m_shadowID).innerHTML = p_request.responseText;
            showResultsDiv();
            // See if we already have a selected item, if not, select the first one in the list
            var highlight = document.getElementById(m_highlightID);
            if (!highlight)
            {
                var temp = document.getElementById(m_shadowID);
                if (temp && temp.firstChild)
                {
                    highlight = temp.firstChild.firstChild;
                    if (highlight)
                    {
                        highlight.setAttribute("id",m_highlightID);
                    }
                }
            }
        }
        else
        {
            //m_resultsDiv.style.visibility="hidden";
            dqbHideResults();
        }
    }
}

//--------------------------------------------------------------------------------------------------
// Function to handle the server ajax response on a "find key" request.  Only used if allowfreetext = false.
// If the server has found the request value, it will return the key for that value... we stick that key
// in the hidden field so that it may be used by the application.
//--------------------------------------------------------------------------------------------------
function dqbOnFindKeyResponse(p_request)
{
    var response  = p_request.responseXML.documentElement;

    if (p_request && p_request.readyState == 4 && response != undefined && response != null)
    {
        var key = response.getElementsByTagName("key")[0].firstChild;
        if (key == undefined || key == null || key.data == undefined || key.data == "")
        {
            m_inputField.value = "";
            document.getElementById(m_hiddenField).value = "";
        }
        else
        {
            var value = response.getElementsByTagName("value")[0].firstChild;
            document.getElementById(m_hiddenField).value = key.data;
            m_inputField.value = value.data;
            // perform the slf if necessary
            if (m_sublistfilter == "ajax")
            {
                sublistFilterFieldDefByParentValue(key.data, m_fieldcode,
                m_localeString, m_repeaterSectionName, m_repeaterIndex)
            }
        }
    }

    // In either case we're done with the dropdown list, so hide it.
    dqbHideResults();
}

//--------------------------------------------------------------------------------------------------
// Makes calls to ajax.js's issueAjaxRequest method.  This is just a convenient wrapper since our
// parameters are the same for all of our ajax calls.
//--------------------------------------------------------------------------------------------------
function dqbAjaxRequestProxy(p_ajaxIdentifier, p_callback)
{
    return dqbAjaxRequestProxyGeneric(p_ajaxIdentifier, p_callback, true);
}

function dqbAjaxRequestProxyGeneric(p_ajaxIdentifier, p_callback, p_asynch)
{
    // no point in making a query if the input field is empty
    if (m_inputField.value.length > 0)
    {
        var params = new Array();
        params["query"] = m_inputField.value;
        params["fielddef"] = m_fieldcode;
        if (m_request && m_request.readyState < 4)
        {
            m_request.abort();
            m_request = null;
        }
        m_request = issueGenericAjaxRequest(p_ajaxIdentifier, m_localeString, params, p_callback, p_asynch);
    }
    else
    {
        dqbHideResults();
    }
    return true;
}

//--------------------------------------------------------------------------------------------------
// On blur event handler.  if allowfreetext is false, we ensure that the current value is a member of
// our list.  If it is not, we blank out the text box.
//--------------------------------------------------------------------------------------------------
function dqbOnBlur(event)
{
    // See if we have a selected item in the list, if we do, populate the textbox with its contents
    var highlight = false;
    highlight = document.getElementById(m_highlightID);
    if (highlight && m_lastQuery != "")
    {
        dqbOnSelectValue(highlight.firstChild.innerHTML);
    }

    if (m_allowfreetext == "false")
    {
        document.getElementById(m_hiddenField).value = "";
        // In IE, the http request we send uses our callback eventhough we make
        // the call synchronously.  Firefox, however, does not use our callback as
        // part of the synchronous request, so we have to manually call the callback
        // method to perform the validation.
        if (m_isIE)
        {
            dqbEnforceValidValue();
        }
        else
        {
            dqbEnforceValidValue();
            dqbOnFindKeyResponse(m_request);
        }
    }
    else
    {
        dqbHideResults();
    }
}

//--------------------------------------------------------------------------------------------------
// This is a special event handler for onblur setup by the macro.  The reason for it is unfortunate.
// Since all of the javascript in this file is "hooked-up" via the onkeypress event (in the dynamicquerybox macro),
// if no key is ever pressed none of this code will execute.  This causes a problem if there was already
// text in the control when the page loads.  There will be a value in the control, but it'll never
// get validated because the user never entered a key on this page to hookup the javascript.
// Furthermore, for some reason in IE the delete key does not fire a onkeypress event.  As a result
// the user can delete the contents of the pre-populated control without it ever passing through
// the javascript validation here.  To work around this obscure bug I add this event handler that
// will only be used if the control does not get a valid keypress to hookup the rest of the javascript.
//--------------------------------------------------------------------------------------------------
function dqbSpecialOnBlur(p_fieldName,p_fieldcode,p_hiddenField, p_locale,p_allowfreetext, p_sublistfilter, p_repeaterSectionName, p_repeaterIndex)
{
    if (!m_inited)
    {
        dqbInit(p_fieldName,p_fieldcode,p_hiddenField, p_locale,p_allowfreetext, p_sublistfilter, p_repeaterSectionName, p_repeaterIndex)
        if (m_allowfreetext == "false")
        {
            document.getElementById(p_hiddenField).value = "";
            if (m_isIE)
            {
                dqbEnforceValidValue();
            }
            else
            {
                dqbEnforceValidValue();
                dqbOnFindKeyResponse(m_request);
            }
        }
    }
}

//--------------------------------------------------------------------------------------------------
// Utility functions
//--------------------------------------------------------------------------------------------------
function Trim(TRIM_VALUE)
{
    if (TRIM_VALUE.length < 1)
    {
        return"";
    }
    TRIM_VALUE = RTrim(TRIM_VALUE);
    TRIM_VALUE = LTrim(TRIM_VALUE);
    if (TRIM_VALUE=="")
    {
        return "";
    }
    else
    {
        return TRIM_VALUE;
    }
} //End Function

function RTrim(VALUE)
{
    var w_space = String.fromCharCode(32);
    var v_length = VALUE.length;
    var strTemp = "";
    if (v_length < 0)
    {
        return"";
    }
    var iTemp = v_length -1;
    while (iTemp > -1)
    {
        if (VALUE.charAt(iTemp) == w_space)
        {
        }
        else
        {
            strTemp = VALUE.substring(0,iTemp +1);
            break;
        }
        iTemp = iTemp-1;
    } //End While
    return strTemp;
} //End Function

function LTrim(VALUE)
{
    var w_space = String.fromCharCode(32);
    if (v_length < 1)
    {
        return"";
    }
    var v_length = VALUE.length;
    var strTemp = "";
    var iTemp = 0;
    while (iTemp < v_length)
    {
        if (VALUE.charAt(iTemp) == w_space)
        {
        }
        else
        {
            strTemp = VALUE.substring(iTemp,v_length);
            break;
        }
        iTemp = iTemp + 1;
    } //End While
    return strTemp;
} //End Function

function escapeXml(inputValue)
{
	inputValue = inputValue.replace(/\&amp;/g, '&');
	inputValue = inputValue.replace(/\&lt;/g, '<');
	inputValue = inputValue.replace(/\&gt;/g, '>');
	inputValue = inputValue.replace(/\&apos;/g, "'");
	inputValue = inputValue.replace(/\&quot;/g, '"');
	return inputValue;
}
