﻿YAHOO.namespace("CSForm");
YAHOO.CSForm.FormHandler = new function() {

    /****************** Private Properties ******************/
    var m_oYEVNT = YAHOO.util.Event, //Contains Event Fxns
        m_oYDOM = YAHOO.util.Dom, //Contains DOM Manip Fxns
        m_sReponse = null,
        m_IsBBOfferChecked = false,
        m_oFormDef = null,
        m_oKeyListener = null,
        m_oUtils = YAHOO.CSUtils.Utils;

    /****************** Private Functions ******************/
    var CheckClasses = function(obj, eleClassName1, eleClassName2, eleClassName3, eleClassName4, eleClassName5) {
        if (eleClassName1 != null && obj.className.indexOf(eleClassName1) > -1)
            return true;
        if (eleClassName2 != null && obj.className.indexOf(eleClassName2) > -1)
            return true;
        if (eleClassName3 != null && obj.className.indexOf(eleClassName3) > -1)
            return true;
        if (eleClassName4 != null && obj.className.indexOf(eleClassName4) > -1)
            return true;
        if (eleClassName5 != null && obj.className.indexOf(eleClassName5) > -1)
            return true;
        else return false;
    },

    CheckInputTypes = function(obj) {
        if (obj.tagName.toLowerCase() == "input" || obj.tagName.toLowerCase() == "textarea")
            return true;
        else return false;
    },

    RadioTblHldr = function(elmnt) {
        return elmnt.parentNode.parentNode.parentNode.parentNode;
    },

    RadioFldCover = function(elmnt) {
        return RadioTblHldr(elmnt).parentNode;
    },

    RadioGrpLbl = function(elmnt) {
        return m_oYDOM.getElementBy(function(obj) { return true; }, "label", RadioFldCover(elmnt));
    },

    IsRadioButton = function(elmnt) {
        return RadioTblHldr(elmnt).className.indexOf("frmRd") > -1;
    },

    PrettyLabel = function(label) {
        if (label) return label.replace(/[*,:]/g, "");
        return "";
    },

    RemoveErrClasses = function(elmnt) {
        m_oYDOM.removeClass(elmnt, "CSChanged");
        m_oYDOM.removeClass(elmnt, "CSError");
        m_oYDOM.removeClass(elmnt, "CSValidationSuccess");
        m_oYDOM.removeClass(elmnt, "CSValidationFailed");
    },

    GetValidatorFields = function(oObj) {
        var oValidatorSpan = m_oYDOM.getChildrenBy(oObj, function(obj) { return CheckClasses(obj, "CSValidatorTxt"); });
        if (!oValidatorSpan || oValidatorSpan.length == 0) return null;
        return oValidatorSpan[0].innerHTML.split("==");
    },

    GetColumnHeader = function(oObj) {
        var oHeader = m_oYDOM.getChildrenBy(oObj.parentNode.parentNode, function(obj) { return CheckClasses(obj, "frmTableHeaderRow"); });
        var oColumnHeaders = m_oYDOM.getChildrenBy(oHeader[0], function(obj) { return CheckClasses(obj, "frmTableHeaderCell"); });
        return PrettyLabel(oColumnHeaders[oObj.cellIndex].innerHTML);
    },

    ReplaceSwfPng = function(flashHeight, flashWidth, imageIDForPNGUpdates, pngValue, swfValue) {

        //Make the flash background image visible (and .png default)
        var oImgPNG = m_oYDOM.getChildren("MORespSWF")[0];
        if (oImgPNG != null) {
            m_oYDOM.removeClass(oImgPNG, "DfltHidden");
            m_oYDOM.setStyle(oImgPNG, "width", flashWidth + "px");
            m_oYDOM.setStyle(oImgPNG, "height", flashHeight + "px");
            m_oYDOM.setStyle(oImgPNG, "margin-top", "1em");
            oImgPNG.src = pngValue;
        }

        var oParams = { menu: "false", quality: "autohigh", wmode: "transparent", allowscriptaccess: "always" };
        swfobject.embedSWF(swfValue, "MORespSWF", flashWidth, flashHeight, "8.0.0", null, null, oParams, null);
    },

    GetAllInputFields = function(formObj) {
        var oInputElements = m_oYDOM.getElementsBy(function(obj) { return CheckClasses(obj, "frmTxt", "frmTxtIgnore", "frmDrp", "frmDrpIgnore") }, null, formObj);

        //CheckBoxes are handled differently because we have to pass the parent node rather than rely on class of the input itself
        oInputElements = oInputElements.concat(m_oYDOM.getElementsBy(function(obj) { return CheckClasses(obj.parentNode, "frmChk", "frmChkIgnore") }, "input", formObj));
        oInputElements = oInputElements.concat(m_oYDOM.getElementsBy(function(obj) { return IsRadioButton(obj) }, "input", formObj));
        return oInputElements;
    }

    DisableInputFields = function(inputElements) {
        oInputElements = GetAllInputFields(m_oFormDef);
        for (iInputIdx in oInputElements) {
            //BBOffer field will be disabled only when the offer is successful
            if (oInputElements[iInputIdx].id.indexOf("Offer") > -1 && oInputElements[iInputIdx].parentNode.className.indexOf("frmChk") == -1)
                continue;
            oInputElements[iInputIdx].disabled = true;
        }
    },

    HideSubmitButton = function() {
        var oBtn = m_oYDOM.getElementsByClassName("frmBtn")[0];
        oBtn.className = oBtn.className + " DfltHidden";
    },

    AddToggling4CheckBoxes = function(formObj) {
        var oChkToggleElementsArry = m_oYDOM.getElementsBy(function(e) { if (e.type == "checkbox" && e.parentNode.className.indexOf("Toggle") > -1) return true; else return false; }, 'input', formObj);
        var sClassName2Toggle = null;
        for (var i = 0; i < oChkToggleElementsArry.length; i++) {
            sClassName2Toggle = oChkToggleElementsArry[i].parentNode.className.split("Toggle")[1];
            if (oChkToggleElementsArry[i].checked) {
                hndlrToggleCheckBoxClicked(true, sClassName2Toggle);
            }
            m_oYEVNT.addListener(oChkToggleElementsArry[i], "click", hndlrToggleCheckBoxClicked, sClassName2Toggle);
        }
    },

    AddFocusBlurAndChangeHandlers4Elements = function(inputElements) {
        var oInput = null;
        for (iInputIdx in inputElements) {
            oInput = inputElements[iInputIdx];

            //Add onFocus handler only to textbox elements that are not in tables
            if ((oInput.className.indexOf("frmTxt") > -1 || oInput.className.indexOf("frmTxtIgnore") > -1)
                        && oInput.parentNode.parentNode.className.indexOf("frmTableCell") == -1) {
                m_oYEVNT.addListener(oInput, "focus", hndlrCSFocus, oInput, true);
            }
            if (oInput.className.indexOf("frmTxt") > -1)
                m_oYEVNT.addListener(oInput, "blur", hndlrCSBlurChange, oInput, true);
            else if (oInput.className.indexOf("frmDrp") > -1 || oInput.parentNode.className.indexOf("frmChk") > -1 || IsRadioButton(oInput))
                m_oYEVNT.addListener(oInput, "change", hndlrCSBlurChange, oInput, true);
        }
    },

    AddEventHndlrs2Redirect4InputFields = function(formDef) {
        var oInputElements = GetAllInputFields(formDef);
        for (iInputIndex in oInputElements) {
            m_oYEVNT.addListener(oInputElements[iInputIndex], "focus", hndlrRedirect2Login);
        }
    },

    AddCalenders = function(formDef) {
        var oCalParentDivs = m_oYDOM.getElementsByClassName("CSCalReq", null, formDef);
        if (oCalParentDivs == null) return;
        for (var iCalIdx = 0; iCalIdx < oCalParentDivs.length; iCalIdx++) {
            InitializeCalender(oCalParentDivs[iCalIdx]);
        }
    },

    InitializeCalender = function(calParentDiv) {
        var oInputDateTextBox = m_oYDOM.getElementsByClassName("frmTxt", null, calParentDiv)[0],
            sCalDivID = "cal" + oInputDateTextBox.id, sCalHdr = "Choose a date:";

        m_oYDOM.addClass(calParentDiv, "yui-skin-sam");

        var oLblElement = m_oYDOM.getChildrenBy(calParentDiv, function(obj) { return CheckClasses(obj, "frmLblLt", "frmLblRt", "frmLblRtIgnore", "frmLblLtIgnore") });
        if (oLblElement.length != 0) {
            try { sCalHdr = PrettyLabel(oLblElement[0].innerHTML); } catch (err) { }
        }
        //Insert a Container Div in the document
        var oCalDiv = document.createElement('div');
        oCalDiv.setAttribute('id', sCalDivID);
        m_oYDOM.insertAfter(oCalDiv, oInputDateTextBox);
        var oCal = new YAHOO.widget.Calendar(sCalDivID, { title: sCalHdr, close: true, navigator: true, mindate: new Date() });
        oCal.render();
        oCal.hide();

        //Add listner to textbox click event to show the calender
        m_oYEVNT.addListener(oInputDateTextBox, "focus", function() { this.show(); }, oCal, true);

        //Add listner to textbox change event to hide the calender
        m_oYEVNT.addListener(oInputDateTextBox, "change", function() { this.hide(); }, oCal, true);

        //Subscribe to the click event on calender to get selected date
        oCal.selectEvent.subscribe(hndlrCalenderDateSelected, oCal, true);
    },

    BuildDataSourceRequestParameter = function(oFormDef) {
        //Required '?' built into hidden span definition
        var sDataSourceParameter = null;

        //textContent for good browsers        
        try { sDataSourceParameter = m_oYDOM.getElementsByClassName("CSFormRespSpan", "span", oFormDef)[0].textContent.replace("\n", "").trim() + "&allFields=\"" + m_sReponse + "\""; }
        catch (err) { }
        //innerText for IE6
        if (!sDataSourceParameter || sDataSourceParameter.length == 0) {
            try { sDataSourceParameter = m_oYDOM.getElementsByClassName("CSFormRespSpan", "span", oFormDef)[0].innerText.replace("\n", "").trim() + "&allFields=\"" + m_sReponse + "\""; }
            catch (err) { }
        }

        var sGuidSpan = "";
        try { sGuidSpan = m_oYDOM.getElementsByClassName("CSBBInfo", "span", oFormDef)[0].textContent.replace("\n", "") }
        catch (err) { }
        if (!sGuidSpan || sGuidSpan.length == 0) {
            try { sGuidSpan = m_oYDOM.getElementsByClassName("CSBBInfo", "span", oFormDef)[0].innerText.replace("\n", "") }
            catch (err) { }
        }
        if (!sGuidSpan || sGuidSpan.length == 0) sGuidSpan = "";

        sDataSourceParameter += "&guid=\"" + sGuidSpan.trim() + "\"";
        sDataSourceParameter += "&bbOffer=";
        if (sGuidSpan.length != 0 && m_IsBBOfferChecked) sDataSourceParameter += m_oYDOM.getElementBy(function(obj) { if (obj.id.indexOf("Offer") > -1 && obj.className.indexOf("frmTxt") > -1) return true; else return false; }, "input", oFormDef).value.replace(",", "").replace("$", "").replace(".00", "");
        else sDataSourceParameter += "null";
        sDataSourceParameter += "&email=";
        sDataSourceParameter += "\"" + m_oYDOM.getElementBy(function(obj) { if (obj.id.indexOf("Email") > -1 && obj.className.indexOf("frmTxt") > -1) return true; else return false; }, "input", oFormDef).value + "\"";
        sDataSourceParameter += "&output=json";
        return sDataSourceParameter;
    },

    SaveResponse2DB = function(oFormDef) {
        m_oFormDef = oFormDef;
        var sDataSourceParameter = BuildDataSourceRequestParameter(oFormDef);
        var oCallback = {
            success: CBSuccess,
            failure: CBFailure,
            scope: null
        },
        oResponseSchema = {
            resultsList: "d.Results",
            metaFields: {
                SWFValue: "d.SWFValue",
                PNGValue: "d.PNGValue",
                FlashHeight: "d.FlashHeight",
                FlashWidth: "d.FlashWidth",
                ImageIDForPNGUpdates: "d.ImageIDForPNGUpdates"
            }
        };
        //This line is required to establish JSON Communincation between YUI Datasource and Asp.net WebService
        var oDataSource = new YAHOO.util.DataSource("/Services/CSForm.asmx/SaveFormResponses");
        oDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON; //  set the content-type to JSON
        oDataSource.connMgr.initHeader("Content-Type", "application/json; charset=utf-8", true);
        oDataSource.responseSchema = oResponseSchema;
        oDataSource.sendRequest(sDataSourceParameter, oCallback, null);
    },

    SendErrMsg2Admin = function(requestStr) {
        var sDataSourceParam = "?errorRequest=\"" + m_oUtils.EncodeString(m_oUtils.EncodeString(requestStr)) + "\"";
        sDataSourceParam += "&browser=" + "\"" + m_oUtils.EncodeString(navigator.appName) + "\"" + "&browserVersion=" + "\"" + m_oUtils.EncodeString(navigator.appVersion) + "\"";
        sDataSourceParam += "&output=json";
        oCallback = {
            success: CBErrMsgAdminEmailSuccess,
            failure: CBErrMsgAdminEmailFailure,
            scope: null
        },
        oResponseSchema = {
            resultsList: "d.Results"
        },
        oDataSource = new YAHOO.util.DataSource("/Services/CSForm.asmx/SendErrorMsg2Admin");
        oDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON; //  set the content-type to JSON
        oDataSource.connMgr.initHeader("Content-Type", "application/json; charset=utf-8", true);
        oDataSource.responseSchema = oResponseSchema;
        oDataSource.sendRequest(sDataSourceParam, oCallback, null);
    },

    /* 
    *  Called by the functions hndlrSubmitBtnClick and CSFormInit to display the label text in the input field
    *       in the field.
    */
    DisplayLabelsInInputFields = function(oFormDef) {
        //Display label text in the input field only for textboxes
        var oCoverDivs = m_oYDOM.getElementsByClassName("CSFieldCover", "div", oFormDef),
            iCoverIdx = 0;

        //Each CSFieldCover will contain at most one left label and one input
        for (iCoverIdx in oCoverDivs) {
            var oLblField = m_oYDOM.getChildrenBy(oCoverDivs[iCoverIdx], function(obj) { return CheckClasses(obj, "frmLblLt", "frmLblLtIgnore"); });
            var oInputField = m_oYDOM.getChildrenBy(oCoverDivs[iCoverIdx], function(obj) { return CheckClasses(obj, "frmTxt", "frmTxtIgnore"); });

            //Set the text only when the control doesn't have default value
            if (oLblField.length != 0
             && oInputField.length != 0
             && (!oInputField[0].defaultValue || oInputField[0].defaultValue) //C# code pre-populates default values
             && oCoverDivs[iCoverIdx].className.indexOf("CSChanged") == -1)
                oInputField[0].value = PrettyLabel(oLblField[0].innerHTML);
        }
    },

    DisplayPrettyLables4DropDowns = function(elements) {
        var oLblField = null;
        for (var iInputIdx in elements) {
            if (elements[iInputIdx].className.indexOf("frmDrp") > -1 || elements[iInputIdx].className.indexOf("frmRd") > -1) {
                oLblField = m_oYDOM.getChildrenBy(elements[iInputIdx].parentNode, function(obj) { return CheckClasses(obj, "frmLblLt", "frmLblLtIgnore"); })[0];
                if (oLblField != null && oLblField.innerHTML)
                    oLblField.innerHTML = oLblField.innerHTML.replace(/[*]/g, "");
            }
            else if (elements[iInputIdx].parentNode.className.indexOf("frmChk") > -1) {
                oLblField = m_oYDOM.getElementBy(function(obj) { return true; }, "label", elements[iInputIdx].parentNode);
                if (oLblField != null && oLblField.innerHTML)
                    oLblField.innerHTML = oLblField.innerHTML.replace(/[*]/g, "");
            }
            else if (IsRadioButton(elements[iInputIdx])) {
                oLblField = RadioGrpLbl(elements[iInputIdx])
                if (oLblField != null && oLblField.innerHTML)
                    oLblField.innerHTML = oLblField.innerHTML.replace(/[*]/g, "");
            }
        }
    },

    ResetLabels = function(inputElements) {
        var iInputIdx = null, oLblElement = null;
        for (iInputIdx in inputElements) {
            //Replace the label text
            oLblElement = m_oYDOM.getChildrenBy(inputElements[iInputIdx].parentNode, function(obj) { return CheckClasses(obj, "frmLblLt", "frmLblRt", "frmLblRtIgnore", "frmLblLtIgnore") });
            if (oLblElement.length != 0
              && PrettyLabel(oLblElement[0].innerHTML) == inputElements[iInputIdx].value) {
                try { inputElements[iInputIdx].value = ""; } catch (err) { }
            }
        }
    },

    /* 
    *  Called by the event handler hndlrCSBlurChange. It validates the input of the field with the validation expression
    *      passed as a parameter in CSValidatorTxt span element
    * 
    *  @param {object} oObj - The input field(TextBox or TextArea).
    */
    ValidateFormatSingleElement = function(oObj) {
        var oValidatorFields = GetValidatorFields(oObj.parentNode);
        if (!oValidatorFields || oValidatorFields.length == 0) return;

        if (oObj.value.match(oValidatorFields[0]) == null) {
            //Validation Failed
            oObj.parentNode.className = oObj.parentNode.className + " CSValidationFailed";
        }
        else {
            //Validation Successful
            oObj.parentNode.className = oObj.parentNode.className + " CSValidationSuccess";
        }
    },

    /* 
    *  Called by the function ValidateFields. Iterates through the collection of radio buttons and returns true if any one
    *     of them is checked.
    * 
    *  @param {object} radioBtnList - .
    */
    RadioBtnLstValue = function(radioBtnList) {
        var oRdBtns = m_oYDOM.getElementsBy(function(obj) { if (obj.type == "radio") { return true; } return false; }, "input", radioBtnList);
        for (var iBtnIdx = 0; iBtnIdx < oRdBtns.length; iBtnIdx++) {
            if (oRdBtns[iBtnIdx].checked)
                return m_oYDOM.getElementBy(function(obj) { return true; }, "label", oRdBtns[iBtnIdx].parentNode).innerHTML;
        }
        return null;
    },

    /*    
    *   Called by the event handler hndlrSubmitBtnClick when the submit button is clicked.
    *       Validates all the fields.
    *       Creates an overview or summary of all the errors.   
    *  
    *   @param {object} oAllInputFields - Array object of all input fields  
    *   @param {object} oFormDef - Array object of all input fields  
    *   @param {bool} onlyRequired - Set to restrict the length 
    */
    ValidateFields = function(oAllInputFields, oFormDef, onlyRequired) {
        //Locals
        var iFieldIdx = 0,              //Iterator for all elements
            sErrOverView = "",          //Error overview span's inner text
            sLblTxt = null,             //Label's text
            oValidatorFields = null,    //Holds pointer to the validation span
            oLblElement = null,         //Holds pointer the label for an element
            sLastTxt = null,            //Previous label (used for inline, unlabeled fields in error overview)
            sInpValue = null,           //Input value
            IsCheckbox = false,         //Is this element a Checkbox?
            IsCheckboxChked = false,    //If checkbox, is it checked?           
            IsSubmit = true,            //Tracks whether an element will be added to a successful form submission
            IsDrop = false,             //Is this element a DropDown
            IsRdBtnList = false,        //Is this element a RadioButtonList
            sParentClass = "",          //Holds validation, error, and type information
            oParent = null,             //Parent of current iteration element
            oGrandParent = null,        //Granparent of current iteration element (for checkboxes generally)
            oCurField = null,           //Current field of iteration
            IsTextBox = false,          //Is this element a Texbox?
            IsHiddenElement = false,    //If grandparent is hidden (header sections in SupaForm)
            RequiredField = false,
            iResponseLngth = 0,
            sRadioValue = null,
            sPrevRadGroup = null;

        //Clear out the submission response
        m_sReponse = "";

        //Iterate over each element, 
        //  1) Get the label make it pretty
        for (iFieldIdx in oAllInputFields) {
            //Set our field information
            oCurField = oAllInputFields[iFieldIdx];
            oParent = oCurField.parentNode; //CS* met-class information
            oGrandParent = oParent.parentNode; //Table cell for tables, else frmFieldLine
            sCurFieldClass = oCurField.className;
            sParentClass = oParent.className;
            sGrandParentClass = oGrandParent.className;
            IsCheckbox = sParentClass.indexOf("frmChk") > -1;
            IsDrop = sCurFieldClass.indexOf("frmDrp") > -1;
            IsRadio = IsRadioButton(oCurField);
            IsTextBox = sCurFieldClass.indexOf("frmTxt") > -1;
            RequiredField = sParentClass.indexOf("CSRequired") > -1;

            //Max data length pre-caution if onlyRequired is set, so we only add RequiredFields to the data string
            if (onlyRequired && !RequiredField) continue;

            //Get the labels and values, make them pretty
            if (IsCheckbox) {
                oLblElement = m_oYDOM.getElementBy(function(obj) { return true; }, "label", oParent);
                sLblTxt = PrettyLabel(oLblElement.innerHTML);
                IsCheckboxChked = oAllInputFields[iFieldIdx].checked;
            }
            else if (IsRadio) {
                sCurFieldClass = RadioTblHldr.className;
                sParentClass = RadioFldCover(oCurField).className;
                RequiredField = sParentClass.indexOf("CSRequired") > -1;
                oLblElement = RadioGrpLbl(oCurField);
                sPrevRadGroup = sLblTxt; //what happened last?
                sLblTxt = PrettyLabel(oLblElement.innerHTML);
                sRadioValue = RadioBtnLstValue(RadioTblHldr(oCurField));
            }
            else {
                oLblElement = m_oYDOM.getChildrenBy(oParent, function(obj) { return CheckClasses(obj, "frmLblLt", "frmLblRt", "frmLblRtIgnore", "frmLblLtIgnore") });
                sLblTxt = oLblElement.length == 0 ? "" : PrettyLabel(oLblElement[0].innerHTML);
                sInpValue = oAllInputFields[iFieldIdx].value;
            }

            //Only need to do one item from a radio button group
            if (IsRadio && sPrevRadGroup == sLblTxt) continue;

            if (sLblTxt == "") sLblTxt = sLastTxt;  //Usually inline fields
            else sLastTxt = sLblTxt;                //Cache this label in case the next field doesn't have one

            //Handle tables
            if (sGrandParentClass.indexOf("frmTableCell") > -1) {
                sLblTxt = PrettyLabel(GetColumnHeader(oGrandParent));
            }

            //Validation
            IsHiddenElement = oGrandParent.parentNode.className.indexOf("DfltHidden") > -1;
            if (!IsHiddenElement) {  //Don't validate hidden things

                //Required and Empty: Don't Submit
                if (RequiredField
                    && ((IsTextBox && sInpValue == "") //TextBoxes
                        || (IsDrop && sInpValue == "0") //Drop Downs
                        || (IsRadio && !sRadioValue) //Radio *jas
                        || (IsCheckbox && !IsCheckboxChked))) { //Checkboxes
                    IsSubmit = false;

                    //Error Message
                    if (sLblTxt != null && sLblTxt != "") sErrOverView += "<li>" + sLblTxt + " is required</li>";

                    //Handle meta-class
                    if (IsRadio && RadioFldCover(oCurField).className.indexOf("CSError") == -1) RadioFldCover(oCurField).className += " CSError";
                    else if (sParentClass.indexOf("CSError") == -1) oAllInputFields[iFieldIdx].parentNode.className += " CSError";
                }

                //Validate if not required or required and provided Failed: Don't submit
                else if (sParentClass.indexOf("CSValidationFailed") > -1) {
                    IsSubmit = false;

                    //Replace label
                    oAllInputFields[iFieldIdx].value = sLblTxt;

                    //Error Message
                    oValidatorFields = GetValidatorFields(oParent);
                    if (sLblTxt != null && sLblTxt != "")
                        sErrOverView += "<li>" + sLblTxt + " is invalid,<br />" + oValidatorFields[1] + "</li>";  //0th field contains field type

                    //Handle meta-class
                    if (sParentClass.indexOf("CSError") == -1) oAllInputFields[iFieldIdx].parentNode.className += " CSError";
                    oAllInputFields[iFieldIdx].parentNode.className = oAllInputFields[iFieldIdx].parentNode.className.replace("CSChanged", "");
                }
            }

            //Create a parameter string to be sent for web service
            if (!IsHiddenElement && IsSubmit) {
                if (IsCheckbox) {
                    var sChkedBoolAsString = (IsCheckboxChked) ? "True" : "False";  //.js bool.toString() as C# bool.ToString()
                    m_sReponse += m_oYDOM.getElementsByClassName("CSFormRespFieldSpan", "span", oGrandParent)[0].innerHTML.replace("\n", "") + "==" + sChkedBoolAsString + "^";
                    if (sParentClass.indexOf("ToggleFormBB") > -1 && IsCheckboxChked)
                        m_IsBBOfferChecked = true;
                }
                else if (IsRadio) {
                    if (sRadioValue)
                        m_sReponse += m_oYDOM.getElementsByClassName("CSFormRespFieldSpan", "span", RadioFldCover(oCurField))[0].innerHTML.replace("\n", "") + "==" + m_oUtils.EncodeString(m_oUtils.EncodeString(sRadioValue)) + "^";
                }
                else if (IsDrop) m_sReponse += m_oYDOM.getElementsByClassName("CSFormRespFieldSpan", "span", oParent)[0].innerHTML.replace("\n", "") + "==" + m_oUtils.EncodeString(m_oUtils.EncodeString(oAllInputFields[iFieldIdx].options[oAllInputFields[iFieldIdx].selectedIndex].text)) + "^";
                else m_sReponse += m_oYDOM.getElementsByClassName("CSFormRespFieldSpan", "span", oParent)[0].innerHTML.replace("\n", "") + "==" + m_oUtils.EncodeString(m_oUtils.EncodeString(oAllInputFields[iFieldIdx].value)) + "^";
            }
        }

        //Errors? If, so set the error message
        if (!IsSubmit) {
            var divValidationSummary = m_oYDOM.getElementsByClassName("CSValidationSummary", "div", oFormDef);
            if (divValidationSummary.length != 0) {
                //Assign the error Text to some literal to be displayed
                divValidationSummary[0].innerHTML = "<ul class=\"CSErrorOverview\">" + sErrOverView + "</ul>";
            }
        }

        iResponseLngth = m_sReponse.length;
        if (iResponseLngth < 1500) return IsSubmit;
        if (YAHOO.env.ua.ie > 0) {
            if (!onlyRequired) return ValidateFields(oAllInputFields, oFormDef, true);

            m_sReponse = m_sReponse.substring(0, 1500);
        }
        else if (iResponseLngth > 15000) {
            if (!onlyRequired) return ValidateFields(oAllInputFields, oFormDef, true);

            m_sReponse = m_sReponse.substring(0, 15000);
        }

        return IsSubmit;
    },

    /*
    *   Redirects user to the URL specified by the form
    */
    RedirectUser = function(formDef) {
        var sRedirectUrl = m_oYDOM.getElementsByClassName("CSRedirectUrl", "span", formDef)[0].innerHTML;
        if (sRedirectUrl != null && sRedirectUrl.trim().length > 1) {
            window.location = sRedirectUrl;
        }
    },

    /*
    *   Validates all the fields and submits the form if successfull
    *    
    *   @param {object}formDef - Entire form element
    *
    *   Returns true if this was successfully submitted, false on error hitting the web service (bad web service return values
    *       handled by CBFailure
    */
    SuccessfulSubmission = function(formDef) {

        var oInputElements = null, SuccessfulTransmission = true;
        try {
            oInputElements = GetAllInputFields(formDef);
            ResetLabels(oInputElements); //Reset all the labels in the text boxes

            //Stops submitting the form if the validation fails
            //  - ValidateFields(...) builds the submission string (m_sReponse)
            if (!ValidateFields(oInputElements, formDef)) {
                DisplayLabelsInInputFields(formDef);
                return true;  //technically a successful "submission" - just invalid data
            }

            //Hide button on submission (leave it when they may need to submit higher offer(s))
            if (!m_IsBBOfferChecked) { HideSubmitButton(); }

            //Bring back disabling
            DisableInputFields(oInputElements);

            //Save Responses (BB Handled in CBSuccess)
            SaveResponse2DB(formDef);
        }
        catch (err) {
            SuccessfulTransmission = false;

            //This won't be useful unless its for BB, but that will probably be broken anyway
            HideSubmitButton();

            //Send the error message to admin@drivingforceauto.com
            SendErrMsg2Admin("Error in SuccessfulSubmission: " + BuildDataSourceRequestParameter(formDef));
        }

        m_oYDOM.getElementsByClassName("CSValidationSummary", "div", formDef)[0].style.display = "none"; //Hide error summary 
        return SuccessfulTransmission;
    },

    DispToolTip = function(inputEle) {
        var oParent = inputEle.parentNode,
            oLbl = m_oYDOM.getChildrenBy(oParent, function(obj) { return CheckClasses(obj, "frmLblLt", "frmLblRt", "frmLblRtIgnore", "frmLblLtIgnore") })[0],
            sValidTxt = null;

        if (oLbl == null) return;

        //Find out coords
        var AtTop = (m_oUtils.YFromViewPort(inputEle) < 75 ? true : false);
        var iEleYOffset = m_oYDOM.getY(inputEle), yCoord = AtTop ? iEleYOffset + 26 : iEleYOffset - 56;

        sValidTxt = GetValidatorFields(oParent)[1];
        var oToolTip = new YAHOO.widget.Tooltip("ToolTip", { context: oParent, text: GetTooltipHTML(oLbl.innerHTML, sValidTxt, AtTop), visible: true, width: "auto", y: yCoord, x: m_oYDOM.getX(inputEle.id), hidedelay: 1000000, zIndex: 1000 });
        oToolTip.show();

        oToolTip.contextMouseOverEvent.subscribe(function(type, args) { return false; }); //Prevents default mouseover event
    },

    GetTooltipHTML = function(lblText, validTxt, atTop) {
        var sTTCntnt = "<div class=\"tttop\"></div><div class=\"ttmid\">" + PrettyLabel(lblText) + "<br />" + validTxt + "</div><div class=\"ttbtm\"></div>";

        if (atTop) return "<div class=\"ttbelow\">" + sTTCntnt + "</div>";
        return "<div class=\"ttabove\">" + sTTCntnt + "</div>";
    },

    CleanToolTipMarkup = function() {
        var oToolTip = m_oYDOM.get("ToolTip");
        if (oToolTip) oToolTip.parentNode.removeChild(oToolTip);
    },

    /****************************** Event Handlers *******************************/
    /* 
    * this - The Input field(TextBox or TextArea)
    * 
    *  Event handler for focus event on textboxes or textareas.
    *   Makes the input field empty if it is not changed   
    */
    hndlrCSFocus = function(e) {
        //Display tooltip
        DispToolTip(this);
        var sParentClass = this.parentNode.className;
        if (sParentClass.indexOf("CSChanged") > -1)
            return;
        this.value = "";
    },

    /* 
    * this - The Input field(TextBox or DropDown or CheckBox)
    * 
    *  Event Handler for blur event on the input fields. It validates the elements that require validation.
    *   Replaces the input field with label text or default value when the field is left empty.   
    */
    hndlrCSBlurChange = function() {

        CleanToolTipMarkup(); //Cleans previous tooltip markup

        //Quick reference bools for field type
        var IsCheckBox = (this.parentNode.className.indexOf("frmChk") > -1),
            IsDropDown = (this.className.indexOf("frmDrp") > -1),
            IsRadio = IsRadioButton(this);

        //Remove all dymanic classes
        if (IsRadio) RemoveErrClasses(RadioFldCover(this));
        else RemoveErrClasses(this.parentNode);

        //Checks: Error if it's required but not checked
        if (IsCheckBox) {
            if (this.checked) this.parentNode.className = this.parentNode.className + " CSChanged";
            else if (this.parentNode.className.indexOf("CSRequired")) this.parentNode.className = this.parentNode.className + " CSError";
            return;
        }

        //Drops: Changed if it isn't default value ("0")
        if (IsDropDown) {
            if (this.value != "0") this.parentNode.className = this.parentNode.className + " CSChanged";
            return;
        }

        if (IsRadio) {
            if (this.value != "0") RadioFldCover(this).className = RadioFldCover(this).className + " CSChanged";
            return;
        }

        //Texts locals
        var oLblElement = m_oYDOM.getChildrenBy(this.parentNode, function(obj) { return CheckClasses(obj, "frmLblLt", "frmLblRt", "frmLblRtIgnore", "frmLblLtIgnore"); }),
            sLblPrettyTxt = "";

        //Check for label
        if (oLblElement.length != 0) sLblPrettyTxt = PrettyLabel(oLblElement[0].innerHTML);

        //If empty, try to restore default, else pretty label
        if (!this.value || this.value == "") {
            if (!this.defaultValue || this.defaultValue == "") this.value = sLblPrettyTxt;
            else this.value = this.defaultValue.toString();
        }

        //Did it change?
        if (this.value != sLblPrettyTxt) {
            //Input is not a default value or label text and was not changed before. Add CSChanged class
            this.parentNode.className = this.parentNode.className + " CSChanged";
        }

        //If at this point, the box hasn't changed, leave
        if (this.parentNode.className.indexOf("CSChanged") == -1) return;

        //Perform format validation if ParentNode contains the class CSValidate
        if (this.parentNode.className.indexOf("CSValidate") > -1)
            ValidateFormatSingleElement(this);
    },

    /*         
    * Event handler for the click event on check boxes. It toggles the elements whose class matches the 
    *   CSS class of check box which is clicked.
    *  
    *  @param {object} e - Event       
    *  @param {String} sClassName2Toggle - Corresponding class name of button and form header to be toggled     
    */
    hndlrToggleCheckBoxClicked = function(e, sClassName2Toggle) {
        var oElements = m_oYDOM.getElementsByClassName(sClassName2Toggle);

        //Make the corresponding button and form section visible/invisible
        for (var i = 0; i < oElements.length; i++) {
            if (e === true || this.checked) {
                oElements[i].className = oElements[i].className.replace("DfltHidden", "");
            }
            else {
                oElements[i].className = oElements[i].className + " DfltHidden";
            }
        }
    },

    /*
    *   this - oFormDef
    *  
    *   This function only really exists to prevent Chrome from allowing bad form submission on Enter Key
    */
    hndlrEnterKeyPress = function(type, args, obj) {
        //handleSubmission(this);
        m_oYEVNT.stopEvent(args[1]);
    },

    /* 
    * this - ???
    * 
    *  Click Event Hanlder for submit button. It validates all the fileds
    *    
    *  @param {object} e - Submit Event
    */
    hndlrSubmitBtnClick = function(e, formDef) {
        m_oYEVNT.stopEvent(e);

        //Just take the user to the confirmation page and handle it the error message later
        var Success = SuccessfulSubmission(formDef);
        if (!Success) {
            RedirectUser(m_oFormDef);
        }
    },

    /*    
    * 
    *  Click Event Hanlder for input fields on the form.
    *       Redirects the user to login page with return url
    *    
    */
    hndlrRedirect2Login = function() {
        var sRetUrl = window.location.href,
            oLocation = window.location;
        window.location = "/Login.aspx?ReturnUrl=" + escape(sRetUrl.replace(oLocation.host, "").replace(oLocation.protocol, "").replace("//", ""));
    },

    /*         
    * Event handler for the date selected event on calender. Enters the selected date in textbox and hides 
    *   the calender
    *  
    *  @param {object} e - Event       
    *  @param {String} sClassName2Toggle - Corresponding class name of button and form header to be toggled     
    */
    hndlrCalenderDateSelected = function(type, args, calender) {
        var oTxtField = m_oYDOM.get(calender.id.replace("cal", "").slice(0, -2));
        oTxtField.value = args[0][0][1] + "/" + args[0][0][2] + "/" + args[0][0][0];
        m_oYDOM.addClass(oTxtField.parentNode, "CSChanged");
        ValidateFormatSingleElement(oTxtField);
        calender.hide();

        var oNextInputField = m_oYDOM.getChildrenBy(oTxtField.parentNode.nextSibling, function(obj) { return CheckClasses(obj, "frmTxt", "frmTxtIgnore", "frmDrp", "frmDrpIgnore", "frmChk"); })[0];
        oNextInputField.focus();
    },

    /********************************* Callback functions *******************************/
    /*
    *  Call back function for saving the response to DB. It is called if the response is successfully saved to DB
    *  
    *  @param {string} requestStr - Contains the request object that was sent.
    *  @param {object} oParsedResponse - Has the return data
    *  @param {object} oPayload - Optional argument which is passed along with request
    */
    CBSuccess = function(requestStr, oParsedResponse, oPayload) {
        if (m_IsBBOfferChecked) {

            //Bargain button form
            ReplaceSwfPng(oParsedResponse.meta.FlashHeight,
              oParsedResponse.meta.FlashWidth,
              oParsedResponse.meta.ImageIDForPNGUpdates,
              oParsedResponse.meta.PNGValue,
              oParsedResponse.meta.SWFValue);

            //Hide the submit button if the offer is successful
            if (oParsedResponse.meta.PNGValue.indexOf("congratulations") > -1) {
                HideSubmitButton();
            }

            m_IsBBOfferChecked = false;
            return;
        }

        RedirectUser(m_oFormDef);
    },

    /*
    *  Call back function for saving the response to DB. It is called if the response is not saved successfully to DB
    *  
    *  @param {string} requestStr - Contains the request string that was sent.
    *  @param {object} oParsedResponse - Has the return data
    *  @param {object} oPayload - Optional argument which is passed along with request
    */
    CBFailure = function(requestStr, oParsedResponse, oPayLoad) {
        //Until we have better error handling, just hide the submit button on error
        HideSubmitButton();

        //Send the error message to admin@drivingforceauto.com
        SendErrMsg2Admin(requestStr);
    },

    /*
    *  Call back function for Sending the error message to admin. 
    *  
    *  @param {string} requestStr - Contains the request object that was sent.
    *  @param {object} oParsedResponse - Has the return data
    *  @param {object} oPayload - Optional argument which is passed along with request
    */
    CBErrMsgAdminEmailSuccess = function(requestStr, oParsedResponse, oPayLoad) {
        RedirectUser();
    },

    /*
    *  Call back function for Sending the error message to admin. 
    *  
    *  @param {string} requestStr - Contains the request object that was sent.
    *  @param {object} oParsedResponse - Has the return data
    *  @param {object} oPayload - Optional argument which is passed along with request
    */
    CBErrMsgAdminEmailFailure = function(requestStr, oParsedResponse, oPayLoad) {
        RedirectUser();
    };

    return {

        /****************** Public Functions ******************/

        CSFormInit: function(formClientID) {
            var oFormDef = document.getElementById(formClientID);

            //Prevent enter key from messing anything up
            m_oKeyListener = new YAHOO.util.KeyListener(document, { keys: [13] }, { fn: hndlrEnterKeyPress, scope: oFormDef, correctScope: true });
            m_oKeyListener.enable();

            //Find all the checkboxes with class Toggle and add onClick event handlers to them
            //  The elements will contain the class Toggle only if it is a supaform
            AddToggling4CheckBoxes(oFormDef);

            //Display label text in the input fields only for text boxes
            DisplayLabelsInInputFields(oFormDef);

            //Get all input fields
            var oInputElements = GetAllInputFields(oFormDef);

            //Display Pretty labels for drop downs and checkboxes
            DisplayPrettyLables4DropDowns(oInputElements);

            AddFocusBlurAndChangeHandlers4Elements(oInputElements);

            //Add calenders
            AddCalenders(oFormDef);

            //Submit button handler
            m_oYEVNT.addListener(m_oYDOM.getElementsByClassName("frmBtn", null, oFormDef), "click", hndlrSubmitBtnClick, oFormDef);
        },

        ForceUserAuthentication: function(formClientID) {
            var oFormDef = document.getElementById(formClientID);

            //Add event Handlers for all input fields
            AddEventHndlrs2Redirect4InputFields(oFormDef);
        }
    }
} ();