function CAjaxRequest()
{
    var $m_strUrl;
    var $m_strService;
    var $m_objHttp;
    var $m_aRelatedFields = new Array(0);
    var $m_strParser;

    this.setUrl = setUrl;
    function setUrl($strUrl)
    {
        $m_strUrl = $strUrl;
    }

    this.setService = setService;
    function setService($strService)
    {
        $m_strService = $strService;
    }

    this.setParser = setParser;
    function setParser($str)
    {
        $m_strParser = $str;
    }

    this.addRelatedField = addRelatedField;
    function addRelatedField($str)
    {
        var $n = $m_aRelatedFields.length;
        $m_aRelatedFields[0] = $str;
    }

    this.send = send;
    function send($str)
    {
        if ( getXmlHttp() )
        {
            $m_objHttp.onreadystatechange = httpCallback;

            $str = $str.replace("&", "%26");
            $str = $str.replace("=", "%3D");
            var $strUrl = $m_strUrl + '?ajaxservice=' + $m_strService + '&q=' + $str;

            // Add Related Fields
            var $nFields = $m_aRelatedFields.length;
            for ( var $n = 0; $n < $nFields; $n++ )
            {
                var $objSelect = document.getElementById($m_aRelatedFields[$n]);
                var $nCurrent = $objSelect.selectedIndex;
                $strUrl = $strUrl + '&' + $m_aRelatedFields[$n] + '=' + $objSelect.options[$nCurrent].value;
            }
            $m_objHttp.open("GET", $strUrl, true);
            $m_objHttp.send(null);
        }
    }

    function getXmlHttp()
    {
        var $fReturn = false;
        try
        {
            $m_objHttp = new ActiveXObject("Microsoft.XMLHTTP");
            $fReturn = true;
        }
        catch ($error)
        {
            $m_objHttp = new XMLHttpRequest();
            $fReturn = true;
        }
        return $fReturn;
    }

    function httpCallback()
    {
        // only if req shows "loaded"
        if ( $m_objHttp.readyState == 4)
        {
            // only if "OK"
            if ( $m_objHttp.status == 200 )
            {
                // If a parser is defined, use it or default to the generic parser
                if ( 'function' == typeof $m_strParser )
                {
                    $m_strParser($m_objHttp);
                }
                else
                {
                    this.parser($m_objHttp);
                }
            }
            else
            {
                alert("Error retrieving the XML data:\n" + $m_objHttp.statusText);
            }
        }
    }

    function parser($objHttp)
    {
        alert('default parser');
    }
}
function CAjaxSuggest()
{
    var $m_objMe;
    var $m_strTextBox;
    var $m_strHiddenInput;
    var $m_strSuggestBox;
    var $m_nCurrentSuggestion;
    var $m_aSuggestions = new Array();
    var $m_nTotalSuggestions = 0;

    this.prototype = new CAjaxRequest();
    $m_objMe = this;
    this.prototype.setParser(parser);

    this.setTextBox = setTextBox;
    function setTextBox($str)
    {
        $m_strTextBox = $str;
        setHiddenInput($str + "_id");
        setSuggestBox("suggest_" + $str);
        disableAutocomplete();
    }

    this.keydown = keydown;
    function keydown($event)
    {
        var $fReturn = true;
        var $nKeyCode = (window.event) ? event.keyCode : $event.keyCode;
        switch ($nKeyCode)
        {
            case 13:    // Enter
            {
                selectSuggestion();
                $fReturn = false;
                break;
            }
            case 38:    // Up
            {
                moveSuggestion(-1);
                $fReturn = false;
                break;
            }
            case 40:    // Down
            {
                moveSuggestion(1);
                $fReturn = false;
                break;
            }
        }
        return $fReturn;
    }

    this.keyup = keyup;
    function keyup($event)
    {
        var $nKeyCode = (window.event) ? event.keyCode : $event.keyCode;
        switch ($nKeyCode)
        {
            case 13:    // Enter

            case 38:    // Up
            case 40:    // Down
            {
                break;
            }
            default:
            {
                // Reset the value with each key stroke
                document.getElementById($m_strHiddenInput).value = '';
                resetSuggestions();
                $m_objMe.prototype.send(document.getElementById($m_strTextBox).value);
            }
        }
    }

    function setHiddenInput($str)
    {
        $m_strHiddenInput = $str;
    }

    function setSuggestBox($str)
    {
        $m_strSuggestBox = $str;
    }

    function disableAutocomplete()
    {
        var $h = document.getElementById($m_strTextBox);
        $h.setAttribute("autocomplete", "off");
    }

    function resetSuggestions()
    {
        $m_nCurrentSuggestion = -1;
        $m_aSuggestions = new Array();
        $m_nTotalSuggestions = 0;
    }

    function moveSuggestion($nDirection)
    {
        // Update the current suggestion, being aware of boundry conditions
        $m_nCurrentSuggestion = $m_nCurrentSuggestion + $nDirection;
        if ( $m_nCurrentSuggestion >= $m_nTotalSuggestions )
        {
            $m_nCurrentSuggestion = 0;
        }
        else if ( $m_nCurrentSuggestion < 0 )
        {
            $m_nCurrentSuggestion = $m_nTotalSuggestions - 1;
        }

        // Change the background color of the currently selected item
        var $aListItems = document.getElementById($m_strSuggestBox).childNodes;
        for ( var $n = 0; $n < $aListItems.length; $n++ )
        {
            var $hChild = $aListItems[$n];
            if ( $n == $m_nCurrentSuggestion )
            {
                $hChild.style.background = "#aaf";
            }
            else
            {
                $hChild.style.background = "transparent";
            }
        }
    }

    function selectSuggestion()
    {
        if ( $m_nCurrentSuggestion >= 0 )
        {
            // Find the character position of the : delimiter between the ID and the Name
            var $n = $m_aSuggestions[$m_nCurrentSuggestion].indexOf(":");

            // Assign the ID and Name to the appropriate values
            document.getElementById($m_strHiddenInput).value = $m_aSuggestions[$m_nCurrentSuggestion].substr(0,$n);
            document.getElementById($m_strTextBox).value = $m_aSuggestions[$m_nCurrentSuggestion].substr($n+1);

            // Reset the suggest box
            resetSuggestions();
            document.getElementById($m_strSuggestBox).innerHTML = "";
            document.getElementById($m_strSuggestBox).style.visibility = "hidden";
        }
    }

    this.parser = parser;
    function parser($objHttp)
    {
        var $dom = $objHttp.responseXML;
        var $nlSuggestions = $dom.getElementsByTagName("suggestion");
        if ( $nlSuggestions.length > 0 )
        {
            var $str = "";
            for ( var $n = 0; $n < $nlSuggestions.length; $n++ )
            {
                var $eleSuggestion = $nlSuggestions[$n];
                var $nId = $eleSuggestion.getElementsByTagName('id')[0].lastChild.nodeValue;
                var $strName = $eleSuggestion.getElementsByTagName('name')[0].lastChild.nodeValue;
                $m_aSuggestions[$m_nTotalSuggestions] = $nId + ":" + $strName;
                $m_nTotalSuggestions++;
                $str = $str + '<li>' + $strName + '</li>';
            }
            document.getElementById($m_strSuggestBox).innerHTML = $str;
            document.getElementById($m_strSuggestBox).style.visibility = "visible";
        }
        else
        {
            document.getElementById($m_strSuggestBox).style.visibility = "hidden";
        }
    }
}
function CDateSelector()
{
    var $m_objDate;
    var $m_aMonths = new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
    var $m_aDayss = new Array("S", "M", "T", "W", "R", "T", "S");
    var $m_strFieldId;
    var $m_strDivId;
    var $m_strObjName;

    this.setDate = setDate;
    function setDate($objDate)
    {
        if ( $objDate != null )
        {
            $m_objDate = $objDate;
        }
        else
        {
            var $strDate = eval("top.document.forms[0]." + $m_strFieldId + ".value");
            $m_objDate = createDateFromStr($strDate);
        }
    }

    this.setFieldId = setFieldId
    function setFieldId($str)
    {
        $m_strFieldId = $str;
    }

    this.setDivId = setDivId;
    function setDivId($str)
    {
        $m_strDivId = $str;
    }

    this.setObjName = setObjName;
    function setObjName($str)
    {
        $m_strObjName = $str;
    }

    this.showCalendar = showCalendar;
    function showCalendar()
    {
        var $nDay = $m_objDate.getDate();
        var $nMonth = $m_objDate.getMonth();
        var $nYear = $m_objDate.getFullYear();

        var $objThisMonth = new Date($nYear, $nMonth, 1);
        var $objNextMonth = new Date($nYear, $nMonth + 1, 1);

        // Find today
        var $objToday = new Date();
        var $nTodayDay = $objToday.getDate();
        var $nTodayMonth = $objToday.getMonth();
        var $nTodayYear = $objToday.getFullYear();

        var $objThisMonth = new Date($nYear, $nMonth, 1);
        var $objNextMonth = new Date($nYear, $nMonth + 1, 1);

        // Find today
        var $objToday = new Date();
        var $nTodayDay = $objToday.getDate();

        // Find out when this month starts and ends.
        var $nDaysThisMonth = Math.round(($objNextMonth.getTime() - $objThisMonth.getTime()) / (1000 * 60 * 60 * 24));

        var $strHtml = monthNavBar($objThisMonth);
        $strHtml += "<table class=\"dateselector\">\n";
        $strHtml += "<tr><th>S</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th></tr>\n";

        $strHtml += "<tr>";
        // Fill the first week of the month with the appropriate number of blanks.
        var $nStartDay = $objThisMonth.getDay();
        for( var $n = 1; $n <= $nStartDay; $n++ )
        {
            $strHtml += "<td>&nbsp;</td>";
        }

        // Print all the days of the month
        var $nDayOfTheWeek = $objThisMonth.getDay();
        for( var $n = 1; $n <= $nDaysThisMonth; $n++)
        {
            $nDayOfTheWeek %= 7;
            if ( $nDayOfTheWeek == 0 )
            {
                $strHtml += "</tr>\n";
                $strHtml += "<tr>";
            }

            $strHtml += "<td";
            // Need to compare Month and Year, too
            if ( $n == $nTodayDay && $nMonth == $nTodayMonth && $nYear == $nTodayYear )
            {
                $strHtml += " class=\"today\"";
            }
            $strHtml += "><a href=\"javascript:" + $m_strObjName + ".chooseDate('" + $nYear + "-" + pad($nMonth + 1) + "-" + pad($n) + "');\">" + $n + "</a></td>";
            $nDayOfTheWeek++;
        }

        // Fill the rest of the week
        for ( var $n = $nDayOfTheWeek; $n < 7; $n++ )
        {
            $strHtml += "<td>&nbsp;</td>";
        }

        $strHtml += "</tr>\n";
        $strHtml += "</table>\n";

        document.getElementById($m_strDivId).innerHTML = $strHtml;
        document.getElementById($m_strDivId).style.visibility = "visible";
    }

    function monthNavBar($objDate)
    {
        var $objLast = new Date($objDate.getFullYear(), $objDate.getMonth() - 1, 1);
        var $strLastMonth = $objLast.getFullYear() + "-" + pad($objLast.getMonth() + 1) + "-" + pad($objLast.getDate());
        var $objNext = new Date($objDate.getFullYear(), $objDate.getMonth() + 1, 1);
        var $strNextMonth = $objNext.getFullYear() + "-" + pad($objNext.getMonth() + 1) + "-" + pad($objNext.getDate());

        var $str = "<p>";
        $str += "<a href=\"javascript:" + $m_strObjName + ".moveCalendar('" + $strLastMonth + "');\">";
        $str += $m_aMonths[$objLast.getMonth()] + " " + shortYear($objLast.getFullYear()) + "</a> | ";
        $str += $m_aMonths[$objDate.getMonth()] + " " + shortYear($objDate.getFullYear()) + " | ";
        $str += "<a href=\"javascript:" + $m_strObjName + ".moveCalendar('" + $strNextMonth + "');\">";
        $str += $m_aMonths[$objNext.getMonth()] + " " + shortYear($objNext.getFullYear()) + "</a>";
        $str += "</p>\n";
        return $str;
    }

    function shortYear($n)
    {
        // Convert to string, then chop off first two characters
        $n = $n + '';
        return "'" + $n.substring(2);
    }

    this.moveCalendar = moveCalendar;
    function moveCalendar($strDate)
    {
        var $objDate = createDateFromStr($strDate);
        setDate($objDate);
        showCalendar();
    }

    function pad($n)
    {
        var $str = $n + '';
        if ( $str.length == 1 )
        {
            $str = "0" + $str;
        }
        return $str;
    }

    this.chooseDate = chooseDate;
    function chooseDate($strDate)
    {
        var $objDate = eval("top.document.forms[0]." + $m_strFieldId);
        $objDate.value = $strDate;
        document.getElementById($m_strDivId).style.visibility = "hidden";
    }

    function createDateFromStr($strDate)
    {
        var $objDate = new Date();
        var $strRegEx = /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/;
        if ( $strDate.match($strRegEx) )
        {
            var $strYear = $strDate.substring(0, 4);
            var $strMonth = $strDate.substring(5, 7);
            var $strDay = $strDate.substring(8, 10);
            $objDate = new Date($strYear, $strMonth - 1, $strDay);
        }
        return $objDate;
    }
}
