// Beg Get Elements By Class Name
/*
    Developed by Robert Nyman, http://www.robertnyman.com
    Code/licensing: http://code.google.com/p/getelementsbyclassname/
*/

var getElementsByClassName = function (className, tag, elm){
    if (document.getElementsByClassName) {
        getElementsByClassName = function (className, tag, elm) {
            elm = elm || document;
            var elements = elm.getElementsByClassName(className),
                nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
                returnElements = [],
                current;
            for(var i=0, il=elements.length; i<il; i+=1){
                current = elements[i];
                if(!nodeName || nodeName.test(current.nodeName)) {
                    returnElements.push(current);
                }
            }
            return returnElements;
        };
    }
    else if (document.evaluate) {
        getElementsByClassName = function (className, tag, elm) {
            tag = tag || "*";
            elm = elm || document;
            var classes = className.split(" "),
                classesToCheck = "",
                xhtmlNamespace = "http://www.w3.org/1999/xhtml",
                namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
                returnElements = [],
                elements,
                node;
            for(var j=0, jl=classes.length; j<jl; j+=1){
                classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
            }
            try	{
                elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
            }
            catch (e) {
                elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
            }
            while ((node = elements.iterateNext())) {
                returnElements.push(node);
            }
            return returnElements;
        };
    }
    else {
        getElementsByClassName = function (className, tag, elm) {
            tag = tag || "*";
            elm = elm || document;
            var classes = className.split(" "),
                classesToCheck = [],
                elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
                current,
                returnElements = [],
                match;
            for(var k=0, kl=classes.length; k<kl; k+=1){
                classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
            }
            for(var l=0, ll=elements.length; l<ll; l+=1){
                current = elements[l];
                match = false;
                for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
                    match = classesToCheck[m].test(current.className);
                    if (!match) {
                        break;
                    }
                }
                if (match) {
                    returnElements.push(current);
                }
            }
            return returnElements;
        };
    }
    return getElementsByClassName(className, tag, elm);
};
// End Get Elements By Class Name

// Wraps a the YUI AutoComplete

// Global shortcuts for the YUI
_DomD = YAHOO.util.Dom;
_Dom = _DomD.get;

if( document.implementation.hasFeature("XPath", "3.0") ){
    if( typeof XMLDocument == "undefined" ){ XMLDocument = Document; }
  XMLDocument.prototype.selectNodes = function(cXPathString, xNode){
    if( !xNode ) { xNode = this; } 
        var oNSResolver = this.createNSResolver(this.documentElement);
        var aItems = this.evaluate(cXPathString, xNode, oNSResolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
        var aResult = [];
        for( var i = 0; i < aItems.snapshotLength; i++){aResult[i] =  aItems.snapshotItem(i);	}
        return aResult;
    };
    XMLDocument.prototype.selectSingleNode = function(cXPathString, xNode){
        if( !xNode ) { xNode = this; } 
        var xItems = this.selectNodes(cXPathString, xNode);
        if( xItems.length > 0 ){return xItems[0];	}
        else{return null;	}
    };
    Element.prototype.selectNodes = function(cXPathString){
        if(this.ownerDocument.selectNodes){	return this.ownerDocument.selectNodes(cXPathString, this);}
        else{throw "For XML Elements Only";}
    };
    Element.prototype.selectSingleNode = function(cXPathString){	
        if(this.ownerDocument.selectSingleNode){return this.ownerDocument.selectSingleNode(cXPathString, this);	}
        else{throw "For XML Elements Only";}
    };
}

if (typeof TGN == 'undefined') { var TGN = {}; TGN.Search = {}; TGN.SearchWidget = {}; TGN.Search.BrowseDate = {}; }
if (typeof TGN.SearchWidget == 'undefined') { TGN.SearchWidget = {}; }
if (typeof TGN.Search == 'undefined') { TGN.Search = {}; TGN.Search.BrowseDate = {}; }
if (typeof TGN.Search.BrowseDate == 'undefined') { TGN.Search.BrowseDate = {}; }
if (typeof TGN.Ancestry == 'undefined') { TGN.Ancestry = {}; }
if (typeof TGN.Ancestry.Search == 'undefined') { TGN.Ancestry.Search = {}; }
if (typeof TGN.Ancestry.Search.DateCalculator == 'undefined') { TGN.Ancestry.Search.DateCalculator = {}; }
if (typeof TGN.Ancestry.Search.LinkModule == 'undefined') { TGN.Ancestry.Search.LinkModule = {}; }
if (typeof TGN.Ancestry.Search.SimpleSearch == 'undefined') { TGN.Ancestry.Search.SimpleSearch = {}; }

if (typeof dbid == 'undefined' && typeof TGN.SResults != 'undefined')
{
    if (typeof TGN.SResults.Browse != 'undefined')
    {
        if (typeof TGN.SResults.Browse.dbid != 'undefined')
        {
            dbid = TGN.SResults.Browse.dbid;
        }
    }
}

//This Array contains i18n strings populated server-side for the users culture
if(typeof TGN.I18N == 'undefined'){ TGN.I18N = {}; }
//static failsafe method for obtaining defined strings
TGN.I18N.getTrans = 
    function(key){
        if(TGN.I18N[key] === null || TGN.I18N[key] == 'undefined'){
            return "$" + key;
        }
        else {return TGN.I18N[key];}
    };

TGN.SearchWidget.AddString = function (key, val) 
{
    TGN.I18N[key] = val;
};

TGN.SearchWidget.NameChanged = 0;
TGN.SearchWidget.TreeLoadingPanel = null;
TGN.SearchWidget.PersonAC = {};
TGN.SearchWidget.PersonAC.populateForm = null;
TGN.SearchWidget.PersonACHandles = {};
TGN.SearchWidget.PersonAutoComplete =
    function (CtrlName, lNameContainer, formFieldArray, guid, cache, tid, tName, scriptUri, useJSONP) {

        this.NameTextBox = CtrlName; // + "_TextBox";
        this.NameContainer = lNameContainer;
        var scriptUrl = "a=MFN.Shared.Search&f=MFN.Shared.Search.WebControls.PersonAutoComplete|DoCallback&guid=" + guid;

        if (!scriptUri) {
            scriptUri = "/search/AjaxBaseHandler.ashx";
        }

        if (useJSONP) {
            this.aCDS = new YAHOO.util.ScriptNodeDataSource(scriptUri + '?' + scriptUrl + "&tid=" + tid);
            this.aCDS.queryQuestionMark = false;
            this.aCDS.responseSchema = {
                // Field order doesn't matter and not all data is required to have a field
                resultsList: "ResultSet.Result",
                fields: ["Name", "YearRange", "tid", "pid"]
            };
            this.aCDS.doBeforeParseData = function (request, fullResponse, callback) {
                return fullResponse;
            };
            this.aCDS.scriptCallbackParam = "callback";

        } else {
            this.aCDS = new YAHOO.widget.DS_XHR(scriptUri, ["ResultSet.Result", "Name", "YearRange", "tid", "pid"]);
            this.aCDS.scriptQueryAppend = scriptUrl + "&tid=" + tid;
            this.aCDS.responseType = YAHOO.widget.DS_XHR.TYPE_JSON;
            this.aCDS.connTimeout = 4000;
            this.aCDS.queryMatchSubset = true;
        }

        this.YUI_AC = new YAHOO.widget.AutoComplete(this.NameTextBox, this.NameContainer, this.aCDS);
        this.YUI_AC.animVert = false;
        this.YUI_AC.minQueryLength = 3;
        this.YUI_AC.maxResultsDisplayed = 12;
        this.YUI_AC.queryDelay = 0.5;
        this.YUI_AC.useShadow = true;
        this.YUI_AC.useIFrame = true;
        this.YUI_AC.autoHighlight = false;

        this.setTid = function (newTid) {
            this.YUI_AC.dataSource.liveData = this.YUI_AC.dataSource.liveData.replace(/(&tid=)\d+/, "$1" + newTid);
            this.YUI_AC.dataSource.flushCache();
            var nTB = _Dom(this.NameTextBox);
            if (nTB != null) {
                this.YUI_AC.sendQuery(nTB.value);
                nTB.focus();
            }
        };

        this.fnFormatter = function (ResultSet, query) {
            var returnV = "<div class='treeName'>";
            returnV += ResultSet[0] + "</div><div class='treeYears'>" + ResultSet[1] + "</div>";
            return returnV;
        };
        this.YUI_AC.formatResult = this.fnFormatter;

        var populateFormSuccess = function (person, formArray) {
            if (TGN.SearchWidget.TreeLoadingPanel != null) {
                TGN.SearchWidget.TreeLoadingPanel.destroy();
                TGN.SearchWidget.TreeLoadingPanel = null;
            }
            if (TGN.SM.TreeLoadingFader != null)
                TGN.SM.TreeLoadingFader.stop();

            var theGExactCB = _Dom(formArray.GlobalExactCB);
            if (theGExactCB != null && theGExactCB.checked)
                TGN.SM.Clear(formArray.FormId, "", null, false);
            else
                TGN.SM.Clear(formArray.FormId);

            for (FieldName in formArray.KVPairs) {
                var fId = _Dom(FieldName);
                if (fId != null) {
                    if (fId.tagName != "SPAN")
                        fId.value = person[formArray.KVPairs[FieldName]];
                    else {
                        if (fId.innerHTML != 'undefined')
                            fId.innerHTML = person[formArray.KVPairs[FieldName]];
                        else if (TGN.SM.GetText(fId) != null)
                            TGN.SM.SetText(fId, person[formArray.KVPairs[FieldName]]);
                    }
                }
            }
            for (FuncName in formArray.Callbacks) {
                var tCallb = formArray.Callbacks[FuncName];
                tCallb.callback(tCallb.domId, person[tCallb.fType], tCallb.args);
            }

            TGN.SearchWidget.NameChanged = 0;
        };

        var populateFormFailure = function (httpStatus) {
            if (status == 500) {
                if (TGN.SearchWidget.TreeLoadingPanel != null) {
                    TGN.SearchWidget.TreeLoadingPanel.setBody("<div class='g_alert'><strong>" + TGN.I18N.getTrans("treeLoadingErrorH") + "</strong><br/>" + TGN.I18N.getTrans("treeLoadingErrorB") + "</div>");
                    setTimeout('TGN.SearchWidget.TreeLoadingPanel.destroy()', 5000);
                }
                if (TGN.SM.TreeLoadingFader != null)
                    TGN.SM.TreeLoadingFader.stop();
            }
        };

        var PopulateForm =
        {
            success: function (o) {
                populateFormSuccess(eval('(' + o.responseText + ')'), o.argument);
            },
            failure: function (o) {
                populateFormFailure(o.status);
            },
            argument: formFieldArray
        };

        this.fnItemSelectEvent = function (oSelf, eArr, oData) {
            TGN.SM.RegSubmitCancelled = true;
            var url = scriptUri + '?a=MFN.Shared.Search&f=MFN.Shared.Search.WebControls.PersonAutoComplete|GetPersonCallback&guid=';
            url += guid;
            url += "&tid=" + eArr[2][2];
            url += "&pid=" + eArr[2][3];

            //find the enclosing form
            if (eArr[1] != null) {
                var cEl = eArr[1];
                while (cEl != null && cEl != document) {
                    //if(cEl.tagName.toUpperCase() == "FORM"){
                    if (cEl.className.indexOf("search-form") >= 0 || cEl.className.indexOf("search-refined") >= 0) {
                        TGN.SM.ShowTreeLoading(cEl.id, cache);
                        break;
                    }
                    cEl = cEl.parentNode;
                }
            }

            if (useJSONP) {
                TGN.SearchWidget.PersonAC.populateForm = function (person) {
                    populateFormSuccess(person, formFieldArray);
                };
                YAHOO.util.Get.script(url + "&callback=TGN.SearchWidget.PersonAC.populateForm", {
                    onSuccess: function () { },
                    onFailure: function () {
                        populateFormFailure(500);
                    }
                });
            }
            else
                YAHOO.util.Connect.asyncRequest('GET', url, PopulateForm);
        };
        this.YUI_AC.itemSelectEvent.subscribe(this.fnItemSelectEvent);

        this.fnUnmatchedEvent = function (oSelf, sQuery) {
            var gsfn = _Dom(CtrlName + "_gsfn");
            if (gsfn !== null) gsfn.value = ""; //make sure field is cleared
            var gsln = _Dom(CtrlName + "_gsln");
            if (gsln !== null) gsln.value = ""; //make sure field is cleared
        };
        this.YUI_AC.unmatchedItemSelectEvent.subscribe(this.fnUnmatchedEvent);
    };

// All versions of IE was causing the entire browser to lock up (max, min, dev toolbars, etc)
// This was due to the select box being injected into a YUI DOM object. This is a hack to toggle the display on and off, which fixes the item.
var iEElmFix;
toggleSelectIEFix = function (elm) {
    if (navigator.appName == "Microsoft Internet Explorer") {
        elm.style.display = "none";
        iEElmFix = elm;
        setTimeout(function () { iEElmFix.style.display = "block"; }, 1);
    }
}

TGN.SearchWidget.PersonAC.populateTreeList = null;
// Sets up the section for multiple trees when using the name auto complete.
TGN.SearchWidget.GetTreeList = function (theDiv, guid, tid, personP, scriptUri, useJSONP) {
    var scriptUrl = 'a=MFN.Shared.Search&f=MFN.Shared.Search.WebControls.PersonAutoComplete|GetAllTrees&guid=' + guid;

    if (!scriptUri) {
        scriptUri = "/search/AjaxBaseHandler.ashx";
    }

    var populateTreeListSuccess = function (trees) {
        if (trees != null) {
            var theSize = 0;
            for (var tree in trees)
                theSize += 1;

            if (theSize > 5)
                theSize = 5;

            var sBox = "<select style='width:225px' size='" + theSize + "' onclick='toggleSelectIEFix(this);'";
            sBox += "onchange=\"TGN.SearchWidget.SetPrefTree('" + personP + "',this)\" >";

            for (var tree in trees) {
                sBox += "<option value='" + trees[tree];
                if (trees[tree] == tid)
                    sBox += "' selected >";
                else
                    sBox += "'>";
                sBox += tree + "</option>";
            }

            sBox = sBox + "</select>";

            if (sBox != "<select>") {
                var tCh = _Dom(theDiv);
                if (tCh != null)
                    tCh.innerHTML = sBox;
            }
        }
    }

    var AddTreePicker = {
        success: function (o) {
            populateTreeListSuccess(eval('(' + o.responseText + ')'));
        },
        failure: function (o) { }
    };

    var url = scriptUri + '?' + scriptUrl;

    if (useJSONP) {
        TGN.SearchWidget.PersonAC.populateTreeList = populateTreeListSuccess;
        YAHOO.util.Get.script(url + "&callback=TGN.SearchWidget.PersonAC.populateTreeList");
    }
    else
        YAHOO.util.Connect.asyncRequest('GET', url, AddTreePicker);
};

// Used for the select list setting the treeid
TGN.SearchWidget.SetPrefTree = function(personP, sBox) {
    TGN.SearchWidget.PersonACHandles[personP].setTid(sBox.options[sBox.selectedIndex].value);
    //personP.setTid(sBox.options[sBox.selectedIndex].value);
};

// Initializes the place type ahead for use on a field
TGN.SearchWidget.InitializePlaceAutoComplete = function (PlaceTextBox, PlaceContainer, GpidHidden, lcid, GpidHierHidden, doMultiGpid, dbid, eventType, placeInfoSubmit, exactCBDomElement, scriptUri, usePlaceByPrefix, cultureId) {

    var theField = document.getElementById(PlaceTextBox);

    if (theField.getAttribute('placeinit') == 'true') {
        return;
    } else {
        theField.setAttribute('placeinit', 'true');
    }

    this.placeWidget = new TGN.SearchWidget.PlaceAutoComplete(PlaceTextBox, PlaceContainer, GpidHidden, lcid, GpidHierHidden, doMultiGpid, dbid, eventType, placeInfoSubmit, exactCBDomElement, scriptUri, usePlaceByPrefix, cultureId);

    // This code makes the type ahead work in Firefox/Chrome/IE/Safari when a field is first clicked in.
    theField.focus();
    theField.blur();
    setTimeout("document.getElementById('" + theField.id + "').focus();", 100);

};

TGN.SearchWidget.PlaceAutoComplete =
    function (PlaceTextBox, PlaceContainer, GpidHidden, lcid, GpidHierHidden, doMultiGpid, dbid, eventType, placeInfoSubmit, exactCBDomElement, scriptUri, usePlaceByPrefix, cultureId) {

        if (GpidHierHidden == null || GpidHierHidden == 'undefined' || GpidHierHidden == '')
            GpidHierHidden = null;

        if (placeInfoSubmit == null || placeInfoSubmit == 'undefined' || placeInfoSubmit == '')
            placeInfoSubmit = null;

        if (usePlaceByPrefix) {

            // If scriptUri is not passed in
            if (!scriptUri) {
                scriptUri = 'http://placepfx.ancestry.com/s/';
            }

            var scriptUrl = "";

            if (!cultureId) {
                cultureId = "";
            }

            scriptUrl += "&maxCount=15&cultureid=" + cultureId; /* PLACE BY PREFIX*/

            this.aCDS = new YAHOO.util.ScriptNodeDataSource(scriptUri + '?' + scriptUrl);
            this.aCDS.queryQuestionMark = false;
            this.aCDS.responseSchema = {
                // Field order doesn't matter and not all data is required to have a field
                fields: ["HName", "Id", "GpidH", "HitC", "LevelId", "IdHierarchy"]
            };
            this.aCDS.doBeforeParseData = function (request, fullResponse, callback) {
                for (var i = 0; i < fullResponse.length; i++) {
                    if (fullResponse[i].IdHierarchy) {
                        fullResponse[i].IdHierarchy = '|' + fullResponse[i].IdHierarchy.join('|') + '|';
                    }
                }
                return fullResponse;
            };

            this.aCDS.scriptQueryParam = "prefix"; /* PLACE BY PREFIX:*/
            this.aCDS.scriptCallbackParam = "callback";
        } else {

            // If scriptUri is not passed in
            if (!scriptUri) {
                scriptUri = '/search/AjaxBaseHandler.ashx';
            }

            var scriptUrl = "a=MFN.Shared.Search&f=MFN.Shared.Search.WebControls.PlaceTypeAheadHandler|ProcessRequest&Use302Redirect=1&lcid=" + lcid; /*PLACE BY PREFIX*/

            // OLD TypePlaceTypeAhead support: The following are not currently supported in the place by prefix service.
            // we should determine whether or not we need them to be or whether they are here to support
            // dead requirements.
            if (GpidHierHidden != null) { scriptUrl += "&GetGH=1"; }
            if (placeInfoSubmit != null) { scriptUrl += "&GetPI=1"; }
            if (doMultiGpid != 'undefined' && doMultiGpid) { scriptUrl += "&MGpid=1"; }
            if (dbid != 'undefined' && dbid != -1) { scriptUrl += "&dbid=" + dbid; }
            if (eventType != 'undefined' && eventType != 0) { scriptUrl += "&eventT=" + eventType; }

            this.aCDS = new YAHOO.widget.DS_XHR(scriptUri, ["ResultSet.Result", "PlaceText", "Gpid", "GpidH", "HitC", "Level", "PHInfo"]);

            this.aCDS.scriptQueryAppend = scriptUrl;
            this.aCDS.responseType = YAHOO.widget.DS_XHR.TYPE_JSON;
            this.aCDS.connTimeout = 4000;
        }

        this.YUI_AC = new YAHOO.widget.AutoComplete(PlaceTextBox, PlaceContainer, this.aCDS);
        this.YUI_AC.minQueryLength = 3;
        this.YUI_AC.maxResultsDisplayed = 15;
        this.YUI_AC.animVert = false;
        this.YUI_AC.queryDelay = 0.2;
        this.YUI_AC.useShadow = true;
        this.YUI_AC.useIFrame = true;
        this.YUI_AC.autoHighlight = false;
        this.fnFormatter = function (ResultSet, query) {
            var rV = '';
            if (ResultSet[3]) {
                if (ResultSet[3] != '0') {
                    rV = " <span class='hitC'>" + ResultSet[0] + "  (" + ResultSet[3] + ")</span><span class='hitCAlt'>";
                    if (ResultSet[0].length > 18) {
                        rV += ResultSet[0].substring(0, 18) + "...";
                    }
                    else rV += ResultSet[0];
                    rV += " (" + ResultSet[3] + ")</span>";
                }
                else {
                    rV = "<span class='zeroH'>" + ResultSet[0] + " (" + ResultSet[3] + ")</span><span class='zeroHAlt'>";
                    if (ResultSet[0].length > 18) {
                        rV += ResultSet[0].substring(0, 18) + "...";
                    }
                    else rV += ResultSet[0];

                    rV += ' (0)';
                    rV += '</span>';
                }
            }
            else rV = ResultSet[0];
            return rV;
        };
        this.YUI_AC.formatResult = this.fnFormatter;

        this.fnItemSelectEvent = function (oSelf, elItem, oData) {
            TGN.SM.RegSubmitCancelled = true;
            var gPid = _Dom(GpidHidden);
            if (gPid != null) {
                gPid.value = elItem[2][1]; //set the gpid field
            }
            if (placeInfoSubmit != null) {
                var pInfoH = _Dom(placeInfoSubmit);

                // TODO: oldWay will be removed when we release life event container final features on 11/17/2010
                var oldWay = false;
                if (placeInfoSubmit.toLowerCase().indexOf("pinfo") == -1) {
                    oldWay = true;
                    pInfoH = _Dom(placeInfoSubmit + "_PInfo");
                }

                if (elItem[2].length > 5) {
                    var levelId = elItem[2][4];
                    var pInfo = elItem[2][5]; //elItem[2][5];
                    pInfoH.value = levelId + "-" + pInfo;

                    // TODO: oldWay will be removed when we release life event container final features on 11/17/2010
                    if (oldWay) {
                        TGN.SM.LocGpidSet(placeInfoSubmit, levelId, pInfo, exactCBDomElement);
                    } else {
                        TGN.SM.LocGpidSet(GpidHidden, levelId, pInfo, exactCBDomElement);
                    }
                }
            }

            if (GpidHierHidden != null) {
                var gPidH = _Dom(GpidHierHidden);
                if (gPidH != null) gPidH.value = elItem[2].length > 2 ? elItem[2][2] : ""; //set the gpidHier field
            }

            try {
                var plTxt = _Dom(PlaceTextBox);
                var range = plTxt.createTextRange();
                range.move("character", 0);
                range.select();
            } catch (err) {

            }
        };
        this.YUI_AC.itemSelectEvent.subscribe(this.fnItemSelectEvent);

        this.fnUnmatchedEvent = function (oSelf, sQuery) {
            var gPid = _Dom(GpidHidden);
            if (gPid !== null) gPid.value = ""; //make sure field is cleared
            if (GpidHierHidden != null) {
                var gPidH = _Dom(GpidHierHidden);
                if (gPidH !== null) gPidH.value = ""; //make sure field is cleared
            }
            if (placeInfoSubmit != null) {
                var pInfoH = _Dom(placeInfoSubmit);
                pInfoH.value = "";
                TGN.SM.LocGpidRefused(placeInfoSubmit, exactCBDomElement);
            }

        };
        this.YUI_AC.unmatchedItemSelectEvent.subscribe(this.fnUnmatchedEvent);
    };
    
//SearchModule Instance methods, these methods require context, as there may be more than one SearchModule on a given page.
//DOMName is the name of page.
if(typeof TGN.SM == 'undefined') { 
    TGN.SM = {}; 
}

TGN.SM.Inst =
    function (moduleDiv, clientId, formId, showAdvOpts) {
        var i = 0;
        var l = 0;
        this.initShowAdv = showAdvOpts;
        this.showAdv = showAdvOpts;
        TGN.SM.InstContainer[moduleDiv] = this; //this makes it so you can call it without the instance handle
        this.moduleDiv = moduleDiv;
        this.clientId = clientId;
        this.XCBArray = new Array();

        this.ShowAdvActions = new Array();
        this.RegisterShowAdvAction = function (f, args) {
            this.ShowAdvActions.push({ f: f, args: args });
        };

        this.ToggleAdv = function (qString) {
            this.showAdv = !this.showAdv; //toggle the advanced flag
            if (qString == null) qString = '';
            var alltags;
            var oField;
            var smDiv = _Dom(moduleDiv);
            var i;

            if (this.showAdv) {
                for (i = 0; i < this.ShowAdvActions.length; i++) {
                    this.ShowAdvActions[i].f.apply(this, this.ShowAdvActions[i].args);
                }
            }

            this.StartExactAllToggle();

            //populate the advanced/standard fields based on the currently displayed version
            var fullNF = _Dom(clientId + "_Name");
            var gsfn_hid = _Dom(clientId + "_Name_gsfn");
            var gsln_hid = _Dom(clientId + "_Name_gsln");
            if (gsfn_hid != null && gsln_hid != null && fullNF != null) {
                if (this.showAdv) {
                    fullNF = fullNF.value;
                    if (gsfn_hid.value == "" && gsln_hid.value == "") {
                        if (fullNF != null) {
                            gsfn_hid.value = fullNF.substring(0, fullNF.lastIndexOf(" "));
                            gsln_hid.value = fullNF.substring(fullNF.lastIndexOf(" ") + 1);
                        }
                    }
                }
                else {
                    fullNF.value = gsfn_hid.value;
                    if (gsln_hid.value != "") {
                        fullNF.value += " " + gsln_hid.value;
                    }
                }
            }

            if (smDiv != null) {//do all the show/hide stuff
                if (this.showAdv) {
                    smDiv.className = smDiv.className + " advanced";
                }
                else {
                    smDiv.className = smDiv.className.replace(" advanced", "");
                }

                this.ToggleInputs();
                this.ToggleAdvTags();

            }
            var theHidden = _Dom(clientId + "_msAV");
            if (theHidden != null) { //change the advanced search flag
                if (this.showAdv) theHidden.value = "1";
                else theHidden.value = "0";
            }

            //This forces IE6 to repaint the open modules, IE6 doesn't reposition absolute divs(Place and Person widgets) in the flow properly when the total height of its container changes.
            if (YAHOO.env.ua.ie > 5 && YAHOO.env.ua.ie < 7) {
                alltags = YAHOO.util.Dom.getElementsByClassName("mod open");
                for (i = 0, l = alltags.length; i < l; i++) {
                    var cB = new TGN.SM.AdvElem(alltags[i]);
                    setTimeout(cB.go, 1);
                }
            }

        };

        this.LoadExactCheckBoxes = function (firstLoad) {
            var gExctb = _Dom(this.clientId + "_xcb");
            this.AdvCBToggle(gExctb, firstLoad);
        };

        this.StartExactAllToggle = function () {
            var gExctb = _Dom(this.clientId + "_xcb");

            if (gExctb != null && gExctb.checked) {
                gExctb.checked = !gExctb.checked;
                this.AdvCBToggle(gExctb);
            }
        };

        this.ToggleInputs = function () {
            var smDiv = _Dom(this.moduleDiv);
            alltags = smDiv.getElementsByTagName("INPUT");
            if (this.showAdv) {
                for (i = 0, l = alltags.length; i < l; i++) {
                    if (alltags[i].className.indexOf("SM_regOpt") > -1) {
                        oField = _Dom(alltags[i].id + "-x");
                        if (oField !== null) {
                            var oyear = alltags[i].value.match(/\d{4}/);
                            if (oyear !== null && oyear != "") {
                                oField.value = oyear;
                            }
                        }
                    }
                }
            }
            else {
                for (i = 0, l = alltags.length; i < l; i++) {
                    if (alltags[i].className.indexOf("SM_advOpt") > -1) {
                        var idName = alltags[i].id.substring(0, alltags[i].id.length - 2); //strip the ending -x and look
                        oField = _Dom(idName);
                        if (oField != null && oField.value == "") {
                            oField.value = alltags[i].value;
                        }
                    }
                }
            }
        };

        // What happens when advanced/simple form is toggled
        this.ToggleAdvTags = function () {

            // Simple search form class to change for simple and advanced
            // TODO: Remove simple search code if it ends up not being a success			
            var simpleSearchDiv = document.getElementById('simpleSearchForm_Main');

            var allOtherTags = getElementsByClassName("advtog");
            var cn;
            if (this.showAdv) {
                for (i = 0, l = allOtherTags.length; i < l; i++) {
                    cn = allOtherTags[i].className;
                    if (cn.indexOf("advNo") > -1) {
                        allOtherTags[i].style.display = 'none';
                    }

                    if (cn.indexOf("advYes") > -1) {
                        allOtherTags[i].style.display = '';
                    }
                }
                if (null != simpleSearchDiv && 'undefined' != simpleSearchDiv) {
                    simpleSearchDiv.setAttribute('class', 'simpleSearchFormDisabled');
                    simpleSearchDiv.className = 'simpleSearchFormDisabled';
                }
            }
            else {
                for (i = 0, l = allOtherTags.length; i < l; i++) {
                    cn = allOtherTags[i].className;
                    if (cn.indexOf("advNo") > -1) {
                        allOtherTags[i].style.display = '';
                    }

                    if (cn.indexOf("advYes") > -1) {
                        allOtherTags[i].style.display = 'none';
                    }
                }
                if (null != simpleSearchDiv && 'undefined' != simpleSearchDiv) {
                    simpleSearchDiv.setAttribute('class', 'simpleSearchForm');
                    simpleSearchDiv.className = 'simpleSearchForm';
                }
            }
        };

        // Toggles exact checkboxes
        // 2nd parameter is a monthField that should be marked as exact if the theCB is checked
        // 3rd parameter is a dayField that should be marked as exact if the theDB is checked
        this.ExactCBToggle = function (theCB, monthField, dayField) {
            var gExct = _Dom(this.clientId + "_xcb");
            var theHidden = _Dom(clientId + "_msAV");
            var fieldMonth;
            var fieldDay;

            // Check month and day field
            if ('undefined' != typeof monthField && null != monthField) {
                fieldMonth = document.getElementById(monthField);
                if ('undefined' != typeof fieldMonth && null != fieldMonth) {
                    if (theCB.checked == true) {
                        fieldMonth.value = "1";
                    } else {
                        fieldMonth.value = "";
                    }
                }
            }
            if ('undefined' != typeof dayField && null != dayField) {
                fieldDay = document.getElementById(dayField);
                if ('undefined' != typeof fieldDay && null != fieldDay) {
                    if (theCB.checked == true) {
                        fieldDay.value = "1";
                    } else {
                        fieldDay.value = "";
                    }
                }
            }

            if (theCB.checked == true) {
                if (this.p_CheckCB(theCB, true)) {
                    gExct.checked = theCB.checked;
                    theHidden.value = "2";
                }
                else {
                    gExct.checked = false;
                    theHidden.value = "1";
                }
            }
            else {
                gExct.checked = false;
                theHidden.value = "1";
            }
        };

        this.p_CheckCB = function (theCB, toCheckBool) {
            var gExct = _Dom(this.clientId + "_xcb");
            var form = _Dom(this.moduleDiv);
            if (form != null) {
                var alltags = form.getElementsByTagName("INPUT");
                for (var i = 0, l = alltags.length; i < l; i++) {
                    if (alltags[i].type == "checkbox") {
                        if (alltags[i] == theCB || alltags[i] == gExct) continue;
                        if (alltags[i].checked != toCheckBool) return false;
                    }
                    // NOTE: this broke with the rollout of advanced name and place filters.  
                    // Fix this again by checking for radio buttons here with class of SM_exactOnlyChoice, 
                    // and adding a call to this function as part of these radio buttons' onclick events.
                }
            }
            return true;
        };

        // This is the function that happens when you click the 'Exact Only' Checkbox in the upper left of a search form.
        this.AdvCBToggle = function (theCB, firstLoad) {

            if ('undefined' == firstLoad || null == firstLoad) {
                firstLoad = false;
            }

            if (theCB == null) theCB = _Dom(this.clientId + "_xcb");

            if (firstLoad && !theCB.checked) {
                return;
            }


            var form = _Dom(this.moduleDiv);
            if (form != null) {
                var alltags = form.getElementsByTagName("INPUT");
                for (var i = 0, l = alltags.length; i < l; i++) {
                    var theTag = alltags[i];
                    var theAttribute = theTag.getAttribute('type');

                    // Skip radio buttons, text boxes if this is the first page load
                    if (firstLoad && (theAttribute == 'radio' || theAttribute == 'text')) {
                        continue;
                    }

                    if (theCB.checked && theTag.className.indexOf("SM_exactOnlyChoice") > -1) {
                        TGN.SM.SetExactOnly(theTag);
                    }
                    else if (!theCB.checked && theTag.className.indexOf("SM_nonExactChoice") > -1) {
                        TGN.SM.SetExactOnly(theTag);
                    }
                    else if (theTag.type == "checkbox" && (theTag.name.indexOf("_x") + 2) == theTag.name.length) {
                        if (!firstLoad) {
                            theTag.checked = theCB.checked;
                        }
                    }
                    else if (theTag.type == "hidden" && (theTag.name.indexOf("_x") + 2) == theTag.name.length) {
                        theTag.value = theCB.checked ? "1" : "";
                    }
                    else if (theTag.type == "hidden" && (theTag.name == 'MSAV')) {
                        theTag.value = theCB.checked ? "2" : "1";
                    }
                }
            }
        };

        this.CheckBucket = function (theCB, bVal) {
            var subHidden = _Dom(this.clientId + "-catBucketSubmit");
            //Check the four check boxes and make sure at least one is checked
            var subHiddenVal = "";
            var hBuck = _Dom(this.clientId + "-catBucket-r");
            if (typeof hBuck != 'undefined' && hBuck.checked) {
                subHiddenVal += "r";
            }
            hBuck = _Dom(this.clientId + "-catBucket-s");
            if (typeof hBuck != 'undefined' && hBuck.checked) {
                subHiddenVal += "s";
            }
            hBuck = _Dom(this.clientId + "-catBucket-t");
            if (typeof hBuck != 'undefined' && hBuck.checked) {
                subHiddenVal += "t";
            }
            hBuck = _Dom(this.clientId + "-catBucket-p");
            if (typeof hBuck != 'undefined' && hBuck.checked) {
                subHiddenVal += "p";
            }

            if (subHiddenVal == "") {
                alert(TGN.I18N.getTrans("catBuckErr"));
                subHidden.value = bVal;
                theCB.checked = true;
            }
            else {
                subHidden.value = subHiddenVal;
            }
        };
    };

TGN.SM.InstContainer = new Array();
TGN.SM.InstMgr = function(moduleDiv, clientId)
{
    var hasInst = TGN.SM.InstContainer[moduleDiv];
    if(hasInst == null) {
        hasInst = new TGN.SM.Inst(moduleDiv, clientId, '', true);
    }
    return hasInst;
};

TGN.SM.AdvElem = function(el){
    this.go = function(){
        el.className = "mod";
        el.className = "mod open";
    };
};
    
//array of configuration details for TG.SM static methods that is populated from server side code on init
if(typeof TGN.SM.CONFIG == 'undefined') TGN.SM.CONFIG = new Array(); 
TGN.SM.GetConfig = function(key) {return TGN.SM.CONFIG[key];};
    
//STATIC methods of SM .. No context needed for these
    TGN.SM.SyncExactCB = function(theCB,hidden){
        var theHidden = _Dom(hidden);
        if(theHidden != null) {
            if(theCB.checked) theHidden.value = '1';
            else theHidden.value = '';
        }
    };
    TGN.SM.HideShow = function(id) {
        var module = _Dom(id);
        var x = module.className.indexOf(' open');
        if(x > 0)
            module.className = module.className.substring(0, x);
        else
            module.className = module.className + ' open';
    };
    TGN.SM.TogSumCat = function(theDiv) {
        tEl = _Dom(theDiv);
        if(tEl != null){
            var x = tEl.className.indexOf(' closed');
            if(x > 0)
                tEl.className = tEl.className.substring(0, x);
            else
                tEl.className = tEl.className + ' closed';
        }
    };
    TGN.SM.showMoreLocation = function(maxRes, tName, zIndex){
        var newLoc = 0;
        var maxFilled = 0;
        for(var i = 1; i <= maxRes; i++){
            var newD = _Dom(tName + i + '_Div');
            if(newD != null) {
                if(newLoc == 0 && newD.innerHTML == ''){
                    newLoc = i;	
                    maxFilled = i;
                    zIndex -= (newLoc-1) * 2;
                }
                else if(newD.innerHTML != ''){
                    if(newD.style.display == 'none'){
                        newD.style.display = 'block';
                        return;
                    }
                    maxFilled = i;
                }
                else break;
            }	
        }
        if( (maxFilled+1) > maxRes) {
            var AddAnother = _Dom("resAddAnother");
            if(AddAnother != null) 
                AddAnother.style.display = 'none';
        }

        if(newLoc == 0) return;

        newD = _Dom(tName + newLoc + '_Div');
        if(newD != null){

            newD.innerHTML += "<style type='text/css'> #"+tName+newLoc+"_AutoComplete .yui-ac-content{ z-index:" + 
                zIndex + ";} #"+tName+newLoc + "_AutoComplete .yui-ac-shadow { z-index:"+(zIndex-1)+"; } #"+tName+newLoc+"_AutoComplete { z-index:"+zIndex+" } </style> " + 
                "<input type='hidden' class='clear' id='"+tName+newLoc+"_Gpid' name='msrpn"+newLoc+"' value='' />" + 
                "<div class='PlaceBox_CN'><div id='"+tName+newLoc+"_AutoComplete'><input type='text' id='"+tName+newLoc + 
                "_ftp' name='msrpn"+newLoc+"__ftp' value='' class='field' />" + 
                "<div id='"+tName+newLoc+"_ACContainer'></div> </div></div>";
            
            newD.style.display = 'block';

            (function() {
                this.placeWidget = new TGN.SearchWidget.PlaceAutoComplete(tName+newLoc+"_ftp",tName+newLoc+ "_ACContainer",tName+newLoc+"_Gpid","1033","");
            })();

            //IE has a hard time paring style declarations in innerHTML.  Add needed zIndex after insert here.
            if (YAHOO.env.ua.ie > 5 && YAHOO.env.ua.ie <= 8) {
                var t2 = _Dom(tName + newLoc + "_AutoComplete");
                if(t2 != null) t2.style.zIndex = zIndex;
                var elArray = YAHOO.util.Dom.getElementsByClassName('yui-ac-content',null,tName+newLoc+'_AutoComplete');
                if(elArray != null && elArray.length > 0) {
                    elArray[0].style.zIndex = zIndex;
                }
                //IE is also weak minded when it comes to adding elements to the dom.. help it along
                YAHOO.util.Dom.getElementsByClassName('PlaceBox_CN','div',null,function(el) {el.className=el.className + " clear"; } );
            }
            if(typeof TGN.KeyWatcher != 'undefined') {
                var nRes = _Dom(tName + newLoc + "_ftp");
                if(nRes != null) {
                    TGN.KeyWatcher.addListener(nRes);
                }
            }
        }
    };
    TGN.SM.popGenderR = function(id,value,args){
        if(value == "m") value = "f";
        else if (value == "f") value = "m";
        TGN.SM.popGender(id,value,args);
    };
    TGN.SM.popGender = function(id, value, args){
        var dd = _Dom(id);
        //The gender dd submits the opposite of the real value as we do a 
        //not exclude filter on this value instead.  So we must reverse the stated value.
        if(value == "m") value = "f";
        else if (value == "f") value = "m";
        if(dd != null) {
            for(var iI=0, l=dd.options.length; iI < l; iI++){
                if( dd.options[iI].value == value) {
                    dd.selectedIndex = iI;
                    if(args[0] != null) {
                        modD = _Dom(args[0]);
                        if(modD != null) {
                            if(modD.innerHTML != 'undefined') { modD.innerHTML = dd.options[iI].text; }
                            else if(TGN.SM.GetText(modD) != null) { TGN.SM.SetText(modD, dd.options[iI].text); }
                        }
                    }
                    break;
                }
            }
        }
    };

    // Family member container population from person picker
    TGN.SM.popFMC = function (id, value, args) {
        var FMC = TGN.SM.InstContainer[id + '_search-form'].FMC;
        if ('undefined' != FMC && null != FMC) {
            FMC.Clear();
            for (ndx in value) {
                FMC.AddRow(value[ndx].relationship, value[ndx].givenName, value[ndx].surname, "", "");
            }
        }
    };
    
    // Life Event container population from person picker
    TGN.SM.popLEC = function (id, value, args) {
    
        var LEC = TGN.SM.InstContainer[id + '_search-form'].LEC;
        if ('undefined' != LEC && null != LEC) {
            LEC.PopulatePersonPicker(value);
        }
        LEC.ParentForm().ToggleAdvTags();
        
        /* BEG: Populating Estimated Birth Year With Person Picker  */
        // Also check to see if there is an estimated birth year field from the simple form. If it is there, populate it.
        var estBirthYear = document.getElementById(id + '_estyear');
        if (null != estBirthYear && 'undefined' != estBirthYear) {
            for (ndx in value) {
                try {
                    if (value[ndx]['event'] == 'b') {
                        estBirthYear.value = value[ndx]['dateinfo']['y'];
                        break;
                    }
                } catch (err) {
                    var it = 0;
                }
            }
        }
        /* END: Populating Estimated Birth Year With Person Picker  */
    };

    TGN.SM.cFormEl = function(name,value) {
        var kv = document.createElement("input");
        kv.setAttribute("type", "hidden");
        kv.setAttribute("name", name);
        kv.setAttribute("value", value);
        return kv;		
    };
    TGN.SM.PersonKeyPress = function(e){
        if(e.keyCode != 13 && e.keyCode != 9 && !(e.keyCode >= 37 && e.keyCode <= 40) && !(e.keyCode >= 16 && e.keyCode <= 19) ) { 
            TGN.SearchWidget.NameChanged += 1;
        }
    };
    TGN.SM.CloseSSO = function(explicit) {
        if(explicit || TGN.SM.CloseTimer != null) { //should indicate that the mouse is still over hover
            var hContent = _Dom("startsearchoverDD");
            if(hContent != null && hContent.className.indexOf("indivHide") == -1) 
                hContent.className += ' indivHide';
            YAHOO.util.Event.removeListener("ssoClose",'blur');
        }
    };
    TGN.SM.CloseTimer = null;
    TGN.SM.CloseSSOM = function(){ TGN.SM.CloseTimer = setTimeout(function(){TGN.SM.CloseSSO(false);},3000);	};
    TGN.SM.SSOMOver = function(){ if(TGN.SM.CloseTimer != null) {clearTimeout(TGN.SM.CloseTimer); TGN.SM.CloseTimer = null; } };
    TGN.SM.InitSSOLink = function() {
        var hContent = _Dom("startsearchoverDD");
        hContent.style.position = 'absolute';
        hContent.style.zIndex = 50;

        function AddHoverEffect(el) { el.className += ' yuimenuitem-selected'; }
        function AddHoverOut(el) { el.className = el.className.replace(' yuimenuitem-selected', ''); }
        YAHOO.util.Dom.getElementsBy(function(){return true;},'li',hContent,function(el){ YAHOO.util.Event.addListener(el,'mouseover',function(){AddHoverEffect(el);}); YAHOO.util.Event.addListener(el,'mouseout',function(){AddHoverOut(el);});} );
        
        /*
        //Disappearing facet bug.
        //After the left column controls were all wrapped in a containing div id=leftcolumn, this hack no longer was needed
        if (YAHOO.env.ua.ie > 5 && YAHOO.env.ua.ie <= 7) {
            var cat = _Dom("categories");
            if(cat != null) { cat.style.zIndex = -1; }
        }
        */

        function onclicker(domElem) { 
            return (function() {

                if(domElem.className.indexOf("indivHide") >= 0) {
                    domElem.className = domElem.className.replace(' indivHide', '');
                    YAHOO.util.Dom.setX(domElem, YAHOO.util.Dom.getX("ssoLink")-5);
                    YAHOO.util.Dom.setY(domElem, YAHOO.util.Dom.getY("ssoLink")+10);
                    var closer = _Dom("ssoClose");
                    if (closer != null) closer.focus();	
                    YAHOO.util.Event.addListener("ssoClose", 'blur', function(){TGN.SM.CloseSSO(false);});
                }
                
            });
        }
        var doOnclicker = onclicker(hContent);//wrap dom element in closer
        YAHOO.util.Event.addListener("ssoLink", "click", doOnclicker);

    };
    TGN.SM.ClearedValues = null;
    TGN.SM.ClearAndSave = function(id) {
        var i = 0;
        if(TGN.SM.ClearedValues == null) {
            TGN.SM.ClearedValues = new Array();
        }
        else {
            TGN.SM.Clear(id, "");//don't need to save it again. just clear um
            return;
        }

        var clearValue = "";
        var form = _Dom(id);
        if(form != null) {
            var alltags = form.getElementsByTagName("INPUT");
            for(i=0, l=alltags.length; i < l; i++){  
                if(alltags[i].className.indexOf("SMNoClear") > -1) {
                    continue;	
                }

                if(alltags[i].type == "checkbox") {
                    if(alltags[i].id.indexOf("catBucket") < 0) {
                        TGN.SM.ClearedValues[alltags[i].id] = alltags[i].checked;
                        alltags[i].checked = false;
                    }
                }
                else if(alltags[i].type == "text" && alltags[i].className.indexOf("field") >= 0 ) {
                    TGN.SM.ClearedValues[alltags[i].id] = alltags[i].value;
                    alltags[i].value = clearValue;
                }
                else if(alltags[i].type == "hidden")
                {
                    if(alltags[i].className.indexOf("clear") >= 0) {
                        TGN.SM.ClearedValues[alltags[i].id] = alltags[i].value;
                        alltags[i].value = "";
                    }
                }
            }

            alltags = form.getElementsByTagName("SELECT");
            for(i=0, l=alltags.length; i < l; i++){
                if (alltags[i].name=='cp' || alltags[i].className.indexOf("SMNoClear") != -1)
                    continue;

                TGN.SM.ClearedValues[alltags[i].id] = alltags[i].selectedIndex;
                alltags[i].selectedIndex = 0;
            }	
        }
    };
    TGN.SM.RestoreClear = function(id) {
        var i = 0;
        var l = 0;
        var form = _Dom(id);
        if(TGN.SM.ClearedValues == null) return;
        var vArr = TGN.SM.ClearedValues;
        if(form != null) {
            var alltags = form.getElementsByTagName("INPUT");
            for(i=0, l=alltags.length; i < l; i++){  
                if(alltags[i].type == "checkbox" && vArr[alltags[i].id] != 'undefined') {
                    if(typeof TGN.SM.ClearedValues[alltags[i].id] != 'undefined') {
                        alltags[i].checked = TGN.SM.ClearedValues[alltags[i].id];
                    }
                }
                else if(alltags[i].type == "text" && vArr[alltags[i].id] != 'undefined' && alltags[i].className.indexOf("field") >= 0 ) 
                {
                    if(typeof TGN.SM.ClearedValues[alltags[i].id] != 'undefined') {
                        alltags[i].value = TGN.SM.ClearedValues[alltags[i].id];	
                    }
                }
                else if(alltags[i].type == "hidden" && vArr[alltags[i].id] != 'undefined')
                {
                    if(alltags[i].className.indexOf("clear") >= 0) {
                        alltags[i].value =  TGN.SM.ClearedValues[alltags[i].id];
                    }
                }
            }

            alltags = form.getElementsByTagName("SELECT");
            for(i=0, l=alltags.length; i < l; i++){
                if (alltags[i].name=='cp' || vArr[alltags[i].id] != 'undefined')
                    continue;

                alltags[i].selectedIndex = TGN.SM.ClearedValues[alltags[i].id];
            }	
        }
    };
    TGN.SM.Clear = function(id, clearValue, showConfirm, togExtCB) {
        var i = 0;
        var l = 0;
        if (clearValue == null) clearValue = ""; //default is to clear the fields with empty
        if (togExtCB == null) togExtCB = true;
        var form = _Dom(id);
        if (form != null) {
            if (showConfirm == null || confirm(showConfirm)) {
                var alltags = form.getElementsByTagName("INPUT");
                for (i = 0, l = alltags.length; i < l; i++) {
                    if (alltags[i].className.indexOf("SMNoClear") > -1) { // skip anything marked to not clear
                        continue;
                    }
                    if (alltags[i].type == "checkbox" && togExtCB) { // clear checkboxes if not catBucket ones
                        if (alltags[i].id.indexOf("catBucket") < 0) {
                            alltags[i].checked = false;
                        }
                    }
                    else if (alltags[i].type == "text" && alltags[i].className.indexOf("field") >= 0) { // clear all text fields
                        alltags[i].value = clearValue;
                    }
                    else if (alltags[i].type == "hidden") { // for hidden inputs, only clear if explicitly marked
                        if (alltags[i].className.indexOf("clear") >= 0) {
                            alltags[i].value = "";
                        }

                        if (alltags[i].name == 'MSAV' && alltags[i].value == "2") {
                            alltags[i].value = "1";
                        }
                    }
                    else if (alltags[i].type == "radio") { // for radio buttons, if there is one option marked as the "default" state when the exact checkbox is unchecked, clear to that state
                        if (alltags[i].className.indexOf("SM_nonExactChoice") >= 0) {
                            TGN.SM.SetExactOnly(alltags[i]);
                        }
                    }
                }

                alltags = form.getElementsByTagName("SELECT");
                for (i = 0, l = alltags.length; i < l; i++) {
                    if (alltags[i].name == 'cp' || alltags[i].className.indexOf('SMNoClear') != -1) {
                        continue;
                    }
                    alltags[i].selectedIndex = 0;
                }
            }
        }
    };
    TGN.SM.FloatDDCur = null;
    /* Methods to support a floating dd control */
    TGN.SM.ToggleFloatDD = function (floatId) {
        var floatDD = document.getElementById(floatId);
        if (typeof floatDD != 'undefined') {
            if (floatDD.style.display == 'block') {
                floatDD.style.display = 'none';
            }
            else {
                if (TGN.SM.FloatDDCur != null)
                    TGN.SM.FloatDDCur.style.display = 'none';
                floatDD.style.display = 'block';
                TGN.SM.FloatDDCur = floatDD;
            }
        }
    };
    
    TGN.SM.FloatDDMouseOutStops = {};
    TGN.SM.MOutFloatDD = function(e, theDiv)
    {
        if(TGN.SM.FloatDDMouseOutStops[theDiv.id]) return;
        if (e.type != 'mouseout' && e.type != 'mouseover') 
        {
            return;
        }
            
        var topElm=e.relatedTarget?e.relatedTarget:e.type=='mouseout'?e.toElement:e.fromElement;
        while(topElm&&topElm!=theDiv){
            topElm=topElm.parentNode;
        }

        if(topElm==theDiv){return;}

        TGN.SM.CloseFloatDD(theDiv);
    };

    TGN.SM.CloseFloatDD = function(theDiv)
    {
        theDiv.style.display = 'none';
    };

    TGN.SM.ClearExactOnlyCheckBox = function(templateId) {
        var templateExactCB = _Dom(templateId + "_xcb");
        var theHidden = _Dom(templateId + "_msAV"); //this is the hidden MSAV parameter.

        if ('undefined' != typeof templateExactCB && null != templateExactCB) {
            templateExactCB.checked = false;
            if (theHidden.value == "2") {
                theHidden.value = "1";
            }
        }
    };

    TGN.SM.LocFilterSet = function(theRadio, widgetId, fieldId, ftpExactDomId, templateId) {
        var extLabel = document.getElementById(widgetId + "_DDLabel");
        if(extLabel != null) {
            var theLabel = "pw" + theRadio.value;
            if(theRadio.value == "") {
                theLabel = "pwDefaultSettings";
                
                // If the default radio is checked, uncheck the "exact matches only" checkbox for the whole template
                TGN.SM.ClearExactOnlyCheckBox(templateId);	           
            }
            extLabel.innerHTML = TGN.I18N.getTrans(theLabel);
        }

        if(typeof ftpExactDomId != 'undefined') 
        {
            var ftpExt = document.getElementById(ftpExactDomId);
            if(ftpExt != null) {
                if(theRadio.value == "XO") {
                    ftpExt.value = "1";
                }
                else {
                    ftpExt.value = "";
                }
            }
        }


        var theDiv = document.getElementById(widgetId + "_Filter");
        TGN.SM.CloseFloatDD(theDiv);
    };

    TGN.SM.NameFilters = {}; // Remember which checkboxes and radio buttons have been set (peeking at the DOM with unpredictable widget IDs is hard)
    TGN.SM.NameFilterSet = function (theRadio, theCheckbox, widgetId, inputIdSuffix, isLastName, templateId, submitName) {
        // *************** THIS IS A HACK - TAKE THIS OUT ONCE WE HAVE REMOVED THE CORRESPONDING $ COLLISION - SEE STORY # 99847 ********************
        for (prop in TGN.SM.NameFilters) {
            if (TGN.SM.NameFilters.hasOwnProperty(prop) && TGN.SM.NameFilters[prop].selector) {
                TGN.SM.NameFilters[prop] = _Dom(TGN.SM.NameFilters[prop].selector);
            }
        }
        // *************** THIS IS A HACK - TAKE THIS OUT ONCE WE HAVE REMOVED THE CORRESPONDING $ COLLISION - SEE STORY # 99847 ********************

        var keyPrefix = (isLastName ? "L_" : "F_");
        // Remember the state of checkboxes and radio buttons
        if (theCheckbox != null) {
            TGN.SM.NameFilters[keyPrefix + "check_" + widgetId + "_" + inputIdSuffix] = theCheckbox;
        }
        if (theRadio != null) {
            TGN.SM.NameFilters[keyPrefix + "selectedRadio_" + widgetId] = theRadio;
            TGN.SM.NameFilters[keyPrefix + "radio_" + widgetId + "_" + inputIdSuffix] = theRadio;
        }
        // If a radio button was clicked, and now the default radio is checked, uncheck all checkboxes, and uncheck the "exact matches only" checkbox for the whole template
        if (theRadio != null && inputIdSuffix == "defRadio") {
            for (var key in TGN.SM.NameFilters) {
                if ("undefined" != typeof key && null != key && key.substring(0, 2) == keyPrefix && key.substring(2, 7) == "check") {
                    TGN.SM.NameFilters[key].checked = false;
                }
            }
            TGN.SM.ClearExactOnlyCheckBox(templateId);
        }
        // If a checkbox was checked, uncheck the default radio and check the exact radio
        if (theCheckbox != null) {
            if ("undefined" == typeof TGN.SM.NameFilters[keyPrefix + "selectedRadio_" + widgetId] ||
                TGN.SM.NameFilters[keyPrefix + "selectedRadio_" + widgetId].id == widgetId + "_defRadio") {
                var exactRadio = _Dom(widgetId + "_XO");
                exactRadio.checked = true;
                TGN.SM.NameFilters[keyPrefix + "selectedRadio_" + widgetId] = exactRadio;
            }
        }

        var extLabel = document.getElementById(widgetId + "_DDLabel");
        if (extLabel != null) {
            // Get the entire filter description based on all selected widgets
            if ("undefined" != typeof TGN.SM.NameFilters[keyPrefix + "selectedRadio_" + widgetId] &&
                TGN.SM.NameFilters[keyPrefix + "selectedRadio_" + widgetId].id == widgetId + "_XO") {
                var theLabel = TGN.I18N.getTrans("nwXO");
                for (key in TGN.SM.NameFilters) {
                    if ("undefined" != typeof key && null != key && key.substring(0, 2) == keyPrefix && key.substring(2, 7) == "check" && TGN.SM.NameFilters[key].checked == true) {
                        var lastUnderscore = key.lastIndexOf("_");
                        var checkInputIdSuffix = key.substring(lastUnderscore + 1);
                        theLabel += ", " + TGN.I18N.getTrans("nw" + checkInputIdSuffix);
                    }
                }
                extLabel.innerHTML = theLabel;
            }
            else {
                extLabel.innerHTML = TGN.I18N.getTrans("nwDefaultSettings");
            }
        }

        // Calculate the submit value based on all selected widgets
        var submitVal = "";
        if ("undefined" != typeof TGN.SM.NameFilters[keyPrefix + "selectedRadio_" + widgetId] &&
            TGN.SM.NameFilters[keyPrefix + "selectedRadio_" + widgetId].id == widgetId + "_XO") {
            submitVal = "XO";
            for (key in TGN.SM.NameFilters) {
                if ("undefined" != typeof key && null != key && key.substring(0, 2) == keyPrefix && key.substring(2, 7) == "check" && TGN.SM.NameFilters[key].checked == true) {
                    lastUnderscore = key.lastIndexOf("_");
                    checkInputIdSuffix = key.substring(lastUnderscore + 1);
                    if (submitVal == "XO") {
                        submitVal = ""; // We don't want both XO and other filter options on at the same time--just an artifact of how we build the queries, where a single XO will override all other filter options
                    }
                    if (submitVal.length > 0) {
                        submitVal += "_";
                    }
                    submitVal += checkInputIdSuffix;
                }
            }
        }
        // Set the hidden input value on the form to the submit value
        var hiddenInput = _Dom(widgetId + "_hidden");
        hiddenInput.value = submitVal;
    };

    // This function is called by AdvCBToggle to set "exact" or "default" radio button selections based on toggle states of exact
    TGN.SM.SetExactOnly = function(widget) {
        widget.checked = true;
        try {
            if (typeof widget.onclick == 'function') {
                widget.onclick.call(widget);
            }
            else {
                eval(widget.onclick); // This is probably for IE6, which is not supported in the new UI, but I'll leave it here anyway.
            }
        }
        catch (e) { }
    };
     
    TGN.SM.LocGpidRefused = function(locId, exactCB) {
        TGN.SM.LocGpidSet(locId, 0, null, exactCB);
    };

    TGN.SM.SetupFilterUI = function (gHandle, levelId, pInfo) {

        //light up the valid options based on the level of the selected gpid
        if (levelId > 7 && pInfo.indexOf("|5027|") == -1 && pInfo.indexOf("|3243|") == -1) { //County .. No counties in AU/CA
            TGN.SM.WidgetOn(gHandle + "_PCO");
        }
        else {
            TGN.SM.WidgetOff(gHandle + "_PCO");
        }

        if (levelId >= 7 && pInfo.indexOf("|5027|") == -1 && pInfo.indexOf("|3243|") == -1) { //County
            radioW = _Dom(gHandle + "_PACO"); //No counties in AU/CA
            if (radioW != null) radioW.style.display = "";
        }
        else {
            radioW = _Dom(gHandle + "_PACO");
            if (radioW != null) radioW.style.display = "none";
        }

        if (levelId >= 5 && pInfo.indexOf("|3257|") == -1 && pInfo.indexOf("|3250|") == -1) { //don't show states for UK/Ireland
            radioW = _Dom(gHandle + "_PAS");
            if (radioW != null) radioW.style.display = "";
        }
        else {
            radioW = _Dom(gHandle + "_PAS");
            if (radioW != null) radioW.style.display = "none";
        }

        if (levelId > 5 && pInfo.indexOf("|3257|") == -1 && pInfo.indexOf("|3250|") == -1) { //don't show states for UK/Ireland
            radioW = _Dom(gHandle + "_PS");
            if (radioW != null) radioW.style.display = "";
        }
        else {
            radioW = _Dom(gHandle + "_PS");
            if (radioW != null) radioW.style.display = "none";
        }

        //light up country
        radioW = _Dom(gHandle + "_PC");
        if (levelId > 3) {
            if (radioW != null) radioW.style.display = "";
            //light up the restrict to just this.. message
            radioW = _Dom(gHandle + "_RestrictThis");
            if (radioW != null) radioW.style.display = "";
        }
        else {
            if (radioW != null) radioW.style.display = "none";
            radioW = _Dom(gHandle + "_RestrictThis");
            if (radioW != null) radioW.style.display = "none";
        }

    };

    TGN.SM.LocGpidSet = function(gHandle, levelId, pInfo, exactCB)
    {
        var radioW = null;
        //reset the filter to 'use default'
        var isExactChecked = false;
        if(typeof exactCB != 'undefined') {
            var eCB = document.getElementById(exactCB);
            if(eCB != null) 
            {
                if(eCB.checked) { isExactChecked = true; }
            }
        }
        var extLabel;
        if(isExactChecked) {
            radioW = _Dom(gHandle + "_XO_input");
            if(radioW != null) 
            {
                radioW.checked = true;
                extLabel = document.getElementById(gHandle + "_DDLabel");
                if(extLabel != null) extLabel.innerHTML = TGN.I18N.getTrans("pwXO");
            }
        }
        else 
        {
            radioW = _Dom(gHandle + "_defRadio");
            if(radioW != null) {
                radioW.checked = true;
                extLabel = document.getElementById(gHandle + "_DDLabel");
                if(extLabel != null) extLabel.innerHTML = TGN.I18N.getTrans("pwDefaultSettings");
            }
        }

        //light up the valid options based on the level of the selected gpid
        if(levelId > 7 && pInfo.indexOf("|5027|") == -1 && pInfo.indexOf("|3243|") == -1) { //County .. No counties in AU/CA
            TGN.SM.WidgetOn(gHandle + "_PCO");
        }
        else {
            TGN.SM.WidgetOff(gHandle + "_PCO");
        }

        if(levelId >= 7 && pInfo.indexOf("|5027|") == -1 && pInfo.indexOf("|3243|") == -1 ) { //County
            radioW = _Dom(gHandle + "_PACO"); //No counties in AU/CA
            if(radioW != null) radioW.style.display = "";
        }
        else {
            radioW = _Dom(gHandle + "_PACO");
            if(radioW != null) radioW.style.display = "none";
        }
        
        if (levelId >= 5 && pInfo.indexOf("|3257|") == -1 && pInfo.indexOf("|3250|") == -1) { //don't show states for UK/Ireland
            radioW = _Dom(gHandle + "_PAS");
            if(radioW != null) radioW.style.display = "";
        }
        else {
            radioW = _Dom(gHandle + "_PAS");
            if(radioW != null) radioW.style.display = "none";
        }

        if (levelId > 5 && pInfo.indexOf("|3257|") == -1 && pInfo.indexOf("|3250|") == -1) { //don't show states for UK/Ireland
            radioW = _Dom(gHandle + "_PS");
            if(radioW != null) radioW.style.display = "";
        }
        else {
            radioW = _Dom(gHandle + "_PS");
            if(radioW != null) radioW.style.display = "none";
        }

        //light up country
        radioW = _Dom(gHandle + "_PC");
        if(levelId > 3) { 
            if(radioW != null) radioW.style.display = "";
            //light up the restrict to just this.. message
            radioW = _Dom(gHandle + "_RestrictThis");
            if(radioW != null) radioW.style.display = "";
        }
        else {
            if(radioW != null) radioW.style.display = "none";
            radioW = _Dom(gHandle + "_RestrictThis");
            if(radioW != null) radioW.style.display = "none";
        }
                
    };
    TGN.SM.WidgetOn = function(domId) {
        radioW = _Dom(domId);
        if(radioW != null) radioW.style.display = "";
    };
    TGN.SM.WidgetOff = function(domId) {
        radioW = _Dom(domId);
        if (radioW != null) radioW.style.display = "none";
    };
    TGN.SM.ShowHelp = function(domain, helpTopic) {
        if (screen) { leftPos = screen.width - 425; }
        var helpWin = window.open('http://' + domain + '/Search/Help/SearchForm.aspx?topic=' + helpTopic, 'stHelp', 'toolbar=0,location=0,status=0,menubar=0,scrollbars=yes,resizable=1,top=5,left=10,width=600,height=625');
        if (helpWin) { helpWin.focus(); }
    };
    TGN.SM.PopupWindow = function(url) {
        window.open(url, "PopHelp", "toolbar=0,menubar=0,location=0,status=0,scrollbars=1,width=600,height=400");
    };

    TGN.SM.TrackTemplate = function(isNew, isAdv) {
        var omniT=s_gi(s_account);
        var adv = "Simple";
        if(isAdv)
        {
            adv = "Advanced";
        }

        var level = "unknown";
        if (typeof TGN != 'undefined' && typeof TGN.Ancestry != 'undefined' && typeof TGN.Ancestry.Search != 'undefined' && typeof TGN.Ancestry.Search.SearchInfo != 'undefined') {
            if(typeof TGN.Ancestry.Search.SearchInfo.pageType != 'undefined') {
                level = TGN.Ancestry.Search.SearchInfo.pageType;
            }
        }

        var pName = "Search:RForm:"+level+":"+adv;
        if(isNew) {
            pName = "Search:RForm:"+level+":"+adv;
        }

        s_pageName = pName;
        /*jsl:ignore*/
        void(omniT.t());
        /*jsl:end*/
        
    };
    TGN.SM.ToggleSearchCat = function(qString,isGlobal) {
        TGN.SM.HideNewSearch();
        TGN.SM.ShowNewSearch(qString, isGlobal, false, true);
    };
    TGN.SM.GetColPriorityDDVal = function(cpddName)
    {
        var cpdd = document.getElementsByName(cpddName)[0];
        var cpddidx = cpdd.selectedIndex;
        var cpddval = cpdd.options[cpddidx].value;
        return cpddval;
    };
    TGN.SM.TogSboCB = function(theCB,modId,locSB,cpddName)
    {
        var hiddenSbo = _Dom("hiddenSbo" + modId);
        hiddenSbo.value = theCB.checked?'0':'1';

        var colPCB = _Dom(modId + '_TogColPCB');
        var colPHidden = _Dom(modId + "_ColPExact");
        
        // Set the CP to the CP that matches the local search block cp.
        var cpdd = document.getElementsByName(cpddName)[0];
        var i = 0;
        for (i = 0; i < cpdd.options.length; i++)
        {
            if (cpdd.options[i].value == locSB)
            {
                cpdd.selectedIndex = i;
                break;
            }
        }

        if(colPCB != null && colPHidden != null) 
        {
            colPCB.checked = theCB.checked;
            if(theCB.checked) {
                colPHidden.value = '1';
            }
            else {
                colPHidden.value = '0';
            }
        }
        TGN.SM.SetupColPriorityCheckboxBasedOnCP(cpdd,modId);
    };
    TGN.SM.TogColPriority = function(theCB, modId, locSB, cpddName)
    {
        var hiddenEl = _Dom(modId + "_ColPExact");
        var hSBO = document.getElementById("hiddenSbo"+modId);
        var sbocb = document.getElementById("sboCB"+modId);
        var cpddval = TGN.SM.GetColPriorityDDVal(cpddName);
        
        if(theCB.checked) {
            hiddenEl.value = "1";
            if(hSBO != null && sbocb != null && locSB == cpddval) {
                hSBO.value = "0";
                sbocb.checked = true;
            }
        }
        else {
            hiddenEl.value = "0";
            if(hSBO != null && sbocb != null && locSB == cpddval) {
                hSBO.value = "1";
                sbocb.checked = false;
            }
        }
    };
    TGN.SM.ColPriorityChanged = function(theDD,modId,locSB)
    {
        TGN.SM.SetupColPriorityCheckboxBasedOnCP(theDD,modId);
        TGN.SM.SetupSBOCheckboxBasedOnCP(theDD,modId,locSB);
    };
    TGN.SM.SetupColPriorityCheckboxBasedOnCP = function(theDD,modId)
    {
        var ddidx = theDD.selectedIndex;
        var ddval = theDD.options[ddidx].value;
        var togColDiv = _Dom(modId + "_TogColDiv");
        var togColCB = _Dom(modId + "_TogColPCB");
        switch (ddval) {
            case "100":
            case "101":
            case "102":
                // Add HideDiv to the end of the classname if it's not already there.
                var hideDivClass = "HideDiv";
                if (togColDiv.className.indexOf(hideDivClass) == -1) {
                    togColDiv.className = togColDiv.className + " " + hideDivClass;
                }
                break;
            default:
                // remove HideDiv from the classname.
                var split = togColDiv.className.split(" ");
                if (split.length > 1 && split[1] == "HideDiv"){
                    togColDiv.className = split.splice(0, split.length-1).join(" ");
                }
                break;
        }
    };	
    TGN.SM.SetupSBOCheckboxBasedOnCP = function(theDD,modId,locSB)
    {
        var ddidx = theDD.selectedIndex;
        var ddval = theDD.options[ddidx].value;
        var hiddenCPEx = _Dom(modId + "_ColPExact");
        var hSBO = document.getElementById("hiddenSbo"+modId);
        var sbocb = document.getElementById("sboCB"+modId);
        if (hSBO != null && hSBO != 'undefined' && sbocb != null && sbocb != 'undefined')
        {
            if (locSB == ddval)
            {
                if (hiddenCPEx.value == "1")
                {
                    hSBO.value = "1";
                    sbocb.checked = true;
                }
            }
            else
            {
                hSBO.value = "0";
                sbocb.checked = false;
            }
        }
    };
    TGN.SM.SubmitFormReturnVoid = function(id, btn, txt, adv, isTop) {
        TGN.SM.SubmitForm(id, btn, txt, adv, isTop);
    };
    TGN.SM.SubmitFormReturnFalse = function(id, btn, txt, adv, isTop) {
        TGN.SM.SubmitForm(id, btn, txt, adv, isTop);
        return false;
    };
    TGN.SM.SubmitForm = function(id, btn, txt, adv, isTop) {
        if (typeof isTop == 'undefined') {
            var b = _Dom(btn);
            b.focus();
        }
        //allows a chance for any outstanding events to complete before inspecting the form for submission - team 42143
        setTimeout("TGN.SM.SubmitFormNow('" + id + "','" + btn + "','" + txt + "','" + adv + "')", 1);
    };
    
    // Checks a family member container field name to see if it is a spouse, child, or sibilng
    TGN.SM.FamilyMemberFieldCheck = function(name) {
        var b = 0; var e = 5;
        if (name.substr(b, e) === "mssng" || name.substr(b, e) === "mssns" || 
            name.substr(b, e) === "mscng" || name.substr(b, e) === "mscns" ||
            name.substr(b, e) === "msbng" || name.substr(b, e) === "msbns") {
            return true;
        }
        
        return false;
    };
    
    TGN.SM.SubmitFormNow = function(id, btn, txt, adv) {
        var i = 0;
        var l = 0;
        //Search Buttons
        var b = _Dom(btn);
        b.className = b.className + ' disabled';
        var topBtn = _Dom("top_" + btn);
        if (topBtn != null) {
            topBtn.className = topBtn.className + ' disabled';
        }

        //Search Button Text
        _Dom(txt).innerHTML = TGN.I18N.getTrans("Searching"); //'Searching...';
        var tSearchTxt = _Dom("top_" + txt);
        if (tSearchTxt != null) {
            tSearchTxt.innerHTML = TGN.I18N.getTrans("Searching"); //'Searching...';
        }

        var form = _Dom(id);
        //Validation code added here

        var advHidden = _Dom(adv);
        var isAdv = false;
        var advClass = "SM_advOpt";
        if (advHidden != null && (advHidden.value == "1" || advHidden.value == "2")) {
            advClass = "SM_regOpt";
            isAdv = true;
        }

        //create form and only add those elements that should be
        //submitted to it.  (Lose empty values and hidden input elements)
        var subForm = document.createElement("form");
        subForm.setAttribute("method", "GET");
        subForm.setAttribute("action", form.action);
        alltags = form.getElementsByTagName("INPUT");
        var kv;
        
        // Create an array for spouse, child, and sibling family member container elements - to be added at the end of the query string
        var fieldsToMove = new Array();
        var moveSpouse = new Array();
        var moveChild = new Array();
        var moveSibling = new Array();		
        var fieldsToMoveCount = 0;
        var fieldsToMoveSpouseCount = 0;
        var fieldsToMoveChildCount = 0;
        var fieldsToMoveSiblingCount = 0;
        
        for (i = 0, l = alltags.length; i < l; i++) {
            var theField = alltags[i];
        
            if (theField.className.indexOf(advClass) > -1 || theField.name == null || theField.value == null || theField.name == '' || theField.value == '' || theField.style.display == 'none') {
                continue;
            }
            
            if (theField.type == "checkbox" || theField.type == "radio") {
                if (theField.checked) {
                    kv = TGN.SM.cFormEl(theField.name, theField.value);
                    kv.checked = theField.checked;
                    
                    if (TGN.SM.FamilyMemberFieldCheck(theField.name)) {
                        fieldsToMove[fieldsToMoveCount] = kv; fieldsToMoveCount ++;
                    } else {
                        subForm.appendChild(kv);
                    }
                }
            }
            
            else if (theField.type == "hidden") {
                //clears the hidden exact cb values when query isn't an advanced query
                if (!isAdv && (theField.name.indexOf("_x") + 2) == theField.name.length) {
                    if (theField.className.indexOf("SM_DND") <= -1)
                        continue;
                }
                kv = TGN.SM.cFormEl(theField.name, theField.value);
                subForm.appendChild(kv);
            }
            else {
                //Needed for IE7
                if (!isAdv && (theField.name == 'gsfn' || theField.name == 'gsln') && TGN.SearchWidget.NameChanged > 0) {
                    continue;
                }
                
                kv = TGN.SM.cFormEl(theField.name, theField.value);
                
                if (TGN.SM.FamilyMemberFieldCheck(theField.name)) {
                    fieldsToMove[fieldsToMoveCount] = kv; fieldsToMoveCount ++;
                } else {
                    subForm.appendChild(kv);
                }
            }
        }

        alltags = form.getElementsByTagName("select");
        
        for (i = 0, l = alltags.length; i < l; i++) {
            theField = alltags[i];
            
            if (theField.className.indexOf(advClass) > -1) {
                continue;
            } else if (theField.value != '') {
                kv = TGN.SM.cFormEl(theField.name, theField.value);
                subForm.appendChild(kv);
            }
        }
        
        // Append any moved family member container elements to the subform. Since all the other elements have been moved, these will come at the end of those
        // and achieve the result we want of spouse, child, and sibling elements being appending at the end of the query string
        for (fmi = 0; fmi < fieldsToMove.length; fmi ++) {
            kv = fieldsToMove[fmi];
            if (kv.name.substr(0, 5) === "mssng" || kv.name.substr(0, 5) === "mssns") {
                moveSpouse[fieldsToMoveSpouseCount] = kv; fieldsToMoveSpouseCount ++;
            }
            if (kv.name.substr(0, 5) === "mscng" || kv.name.substr(0, 5) === "mscns") {
                moveChild[fieldsToMoveChildCount] = kv; fieldsToMoveChildCount ++;
            }
            if (kv.name.substr(0, 5) === "msbng" || kv.name.substr(0, 5) === "msbns") {
                moveSibling[fieldsToMoveSiblingCount] = kv; fieldsToMoveSiblingCount ++;
            }
        }
        
        // Loop through the three relationship arrays now and append those elements to the form
        for (i = 0; i < moveSpouse.length; i ++) {
            kv = moveSpouse[i];
            subForm.appendChild(kv);
        }
        
        for (i = 0; i < moveChild.length; i ++) {
            kv = moveChild[i];
            subForm.appendChild(kv);
        }
        
        for (i = 0; i < moveSibling.length; i ++) {
            kv = moveSibling[i];
            subForm.appendChild(kv);
        }
        
        // Append the rest of the form elements
        document.body.appendChild(subForm);
        subForm.submit();
        return false;
    };

    TGN.SM.RegSubmitCancelled = false;
    TGN.SM.RegSubmit = function(formId, submitFunc) 
    {
        var tElm = document.getElementById(formId);
        if(tElm != null) {

            var subMeth = function(e) {
                if(typeof e != 'undefined') {
                    if (e.keyCode == 13 && !TGN.SM.RegSubmitCancelled) {
                        submitFunc();
                    }
                    TGN.SM.RegSubmitCancelled = false;
                }
            };

            for(var i = 0; i < tElm.length; i++) {
                if(tElm[i].type == "text") {
                    YAHOO.util.Event.addListener(tElm[i], 'keydown', subMeth);
                }
            }
        }
    };
    TGN.SM.ShowWaitMessage = function(msg){
        if (typeof TGN.SM.WaitPanel == 'undefined' || TGN.SM.WaitPanel == null){
            var div = document.createElement('div');
            div.setAttribute('id','waitPanel');
            document.body.appendChild(div);

            TGN.SM.WaitPanel = new YAHOO.widget.Panel('waitPanel',{
                close: false,
                draggable: false,
                modal: true,
                visible: true,
                width: 200,
                underlay:'none',
                zIndex:101});
            TGN.SM.WaitPanel.setBody(msg);
            TGN.SM.WaitPanel.render(document.body);
        }
        TGN.SM.PositionAndShow(TGN.SM.WaitPanel);
    };
    TGN.SM.TreeLoadingFader = null;
    TGN.SM.ShowTreeLoading = function(id,cache){
        if(typeof TGN.SM.TreeWaitPanel == 'undefined' || TGN.SM.TreeWaitPanel == null){
            var sTemp = _Dom(id);
            if(sTemp != null){
                TGN.SM.TreeLoadingFader = new YAHOO.util.Anim(id, {opacity: {to:0.1}},3,YAHOO.util.Easing.easeOut);
                TGN.SM.TreeLoadingFader.onComplete.subscribe(function() { 
                    sTemp.style.opacity = 1; 
                    if(sTemp.style.filter != null) sTemp.style.filter = '';
                });
                TGN.SM.TreeLoadingFader.animate();

                var div = document.createElement('div');
                div.setAttribute('id','treeWaitPanel');
                div.style.zIndex = '1001';
                sTemp.style.zIndex = '1001';
                sTemp.appendChild(div);
                YAHOO.util.Dom.setXY(div,YAHOO.util.Dom.getXY(sTemp));

                TGN.SearchWidget.TreeLoadingPanel = new YAHOO.widget.Panel('treeWaitPanel',
                      {constrainttoviewport: true, close:false, underlay:'none', visible:true, draggable:false, iframe:true} );
                TGN.SearchWidget.TreeLoadingPanel.setBody("<div style=\"z-index:1001;background-color:#ffffff;color:#000000;\"><img src='" + cache + "/css/search/i/Loading32.gif' /><span class='loadingMsg'>" + TGN.I18N.getTrans("loadingMsg") + "</span></div>");
                TGN.SearchWidget.TreeLoadingPanel.render();
            }
        }
    };
    TGN.SM.HideWaitMessage = function(){
        if (typeof TGN.SM.WaitPanel != 'undefined' && TGN.SM.WaitPanel != null){
            TGN.SM.WaitPanel.hide();
        }
    };
    TGN.SM.ShowMore = function(id, linkId){
        var div = _Dom(id);
        var link = _Dom(linkId);
        if(div != null)
        {
            div.style.display = 'block';
        }
        if(link != null) link.style.display = 'none';
    };
    TGN.SM.ShowSearchPanel = function(){
        TGN.SM.PositionAndShow(TGN.SM.NewSearchPanel);
        TGN.SM.HideWaitMessage();
        TGN.SM.FocusFirstInput('newT_search-form');
    };
    TGN.SM.PositionAndShow = function(p){
        var x = _DomD.getDocumentScrollLeft() + ((_DomD.getViewportWidth() - p.element.offsetWidth) / 2);
        if (x < 10)
            x=10;
        var y = _DomD.getDocumentScrollTop() + 50;
        p.cfg.setProperty("zIndex", 201);
        p.cfg.setProperty("x", x);
        p.cfg.setProperty("y", y);
        p.show();
    };
    TGN.SM.SetACZ = function(div,TopZ) {
        if (YAHOO.env.ua.ie > 5 && YAHOO.env.ua.ie <= 7) {
            var locA = YAHOO.util.Dom.getElementsByClassName('yui-ac','div',div);
            if(document.styleSheets && document.styleSheets.length > 0) {
                var styleNode = document.styleSheets[0];
                if(typeof(styleNode.addRule) == "object") {
                    for(var i = 0; i < locA.length; i++) {
                        if(locA[i].id != null && locA[i].id != ""){
                                styleNode.addRule("#"+locA[i].id, "z-index:"+TopZ);
                                styleNode.addRule("#"+locA[i].id+ " .yui-ac-content", "z-index:"+TopZ--);
                                styleNode.addRule("#"+locA[i].id+ " .yui-ac-shadow", "z-index:"+TopZ--);
                        }
                    }
                }
            }
        }
    };
    TGN.SM.HandleSuccess = function(o){
        if (typeof TGN.SM.NewSearchPanel == 'undefined' || TGN.SM.NewSearchPanel == null){
            if(o.responseText != 'undefined'){
                var div = document.createElement('div');
                div.setAttribute('id','newSearch');
                //IE likes to have the element appended to the DOM first before executing
                //scripts that are added via innerHTML assignment.  Everyone doesn't like.
                if (YAHOO.env.ua.ie > 5 && YAHOO.env.ua.ie <= 7) {
                    document.body.appendChild(div);
                    div.innerHTML += o.responseText;
                    //IE doesn't parse css declarations consistantly
                    //	TGN.SM.SetACZ(div,150);
                } 
                else {
                    div.innerHTML += o.responseText;
                    document.body.appendChild(div);
                }
                TGN.SM.NewSearchPanel = new YAHOO.widget.Panel('newT_search-form',{
                    close: true,
                    draggable: true,
                    modal: true,
                    visible: true,
                    width: 450,
                    underlay:'none',
                    effect:{effect:YAHOO.widget.ContainerEffect.FADE,duration:0.1}});

                TGN.SM.NewSearchPanel.cfg.getProperty("strings").close = " ";
                //need to do it here becuase visible=true does not fire a show event	
                
                if(typeof TGN.KeyWatcher != 'undefined') {
                    TGN.KeyWatcher.disable();
                    TGN.KeyWatcher.lockState();
                }
                TGN.SM.NewSearchPanel.hideEvent.subscribe(function() {
                    if(typeof TGN.KeyWatcher != 'undefined') {
                        TGN.KeyWatcher.unlockState();
                        TGN.KeyWatcher.enable();
                    }
                });	   
                TGN.SM.NewSearchPanel.showEvent.subscribe(function() {
                    if(typeof TGN.KeyWatcher != 'undefined') {
                        TGN.KeyWatcher.disable();
                        TGN.KeyWatcher.lockState();
                    }
                });

                TGN.SM.NewSearchPanel.element.className+=' modal';
                var p = _Dom('newT_search-form');
                p.className = p.className.replace(' yui-panel', '');
                TGN.SM.NewSearchPanel.render(document.body);

                _Dom('newT_mod-search').innerHTML += "<span class='lnk-cancel'>&nbsp;" + TGN.I18N.getTrans("or") + "&nbsp;<a href='javascript:TGN.SM.HideNewSearch();'>" + TGN.I18N.getTrans("newSearchCancel") + "</a></span>";
                if(o.argument[0] == 'clear'){
                    TGN.SM.Clear('newT_search-form');
                }

                TGN.SM.ShowSearchPanel();

                if (YAHOO.env.ua.ie <= 7) {
                    var closerF = function(divN, clZ) { return function() { TGN.SM.SetACZ(divN,clZ); }; };
                    setTimeout(closerF(TGN.SM.NewSearchPanel.element,150), 1);
                }
            }
        }
        else{
            TGN.SM.ShowSearchPanel();
        }
    };
    TGN.SM.HandleFailure = function(o){
        document.location.href = '/';
    };
    TGN.SM.ShowNewSearch = function(qString, isGlobalLevel, alwaysRefreshFlg, keepFormPop){
        if(typeof isGlobalLevel == 'undefined') isGlobalLevel = true;

        // Added new var to force refresh of overlay everytime.
        if(typeof alwaysRefreshFlg == 'undefined') alwaysRefreshFlg = false;

        if(qString == null) qString = '';

        if(typeof TGN.SM.NewSAdvT == 'undefined') TGN.SM.NewSAdvT = 0;
        var rTemplate = TGN.SM.NewSAdvT;
        if(isGlobalLevel) { 
            TGN.SM.NewSAdvT= 1;
        }
        else TGN.SM.NewSAdvT = 2;

        // In case, always refresh flg is set, and newSearchPanel exists, change rTemplate to force destroying of newSearchPanel.
        if (alwaysRefreshFlg && typeof TGN.SM.NewSearchPanel != 'undefined')
            rTemplate	 = TGN.SM.NewSAdvT + 1;

        if(rTemplate != 0 && rTemplate != TGN.SM.NewSAdvT){
            //clean up the last template out of the DOM
            TGN.SM.NewSearchPanel.destroy();
            if(TGN.SM.WaitPanel != null) TGN.SM.WaitPanel.destroy();
            TGN.SM.NewSearchPanel = null;
            TGN.SM.WaitPanel = null;
        }
        if (typeof TGN.SM.NewSearchPanel == 'undefined' || TGN.SM.NewSAdvT != rTemplate || alwaysRefreshFlg){
            if (YAHOO.env.ua.ie > 5 && YAHOO.env.ua.ie <= 7) TGN.SM.ShowWaitMessage(TGN.I18N.getTrans("Loading"));

            var clear = 'clear';
            if(typeof keepFormPop != 'undefined' && keepFormPop)
                clear = 'keep';

            setTimeout("YAHOO.util.Connect.asyncRequest('GET', '/Mercury/Pages/AJAX/DefaultSearchTemplate.aspx"+qString.replace(/'/g, "&#39;")+"', {success: TGN.SM.HandleSuccess, argument:['" + clear + "'], failure: TGN.SM.HandleFailure})",1);
        }
        else {
            TGN.SM.ShowSearchPanel();
        }
    };
    TGN.SM.HideNewSearch = function(){
        if (typeof TGN.SM.NewSearchPanel != 'undefined')
            TGN.SM.NewSearchPanel.hide();
        TGN.SM.HideWaitMessage();
    };

/* Refine Search Rewrite */
    TGN.SM.HideRefineSearch = function(){
        if(typeof TGN.SM.RefineSearchPanel != 'undefined'){
            TGN.SM.RefineSearchPanel.hide();
        }
        TGN.SM.HideWaitMessage();
    };
    TGN.SM.InitRefineSearch = function() {
        TGN.SM.RefineSearchPanel = new YAHOO.widget.Panel('refineT_search-form',{
            close: true,
            draggable: true,
            modal: true,
            visible: false,
            width: 600,
            underlay:'none'});

        TGN.SM.RefineSearchPanel.cfg.getProperty("strings").close = " ";
        TGN.SM.RefineSearchPanel.hideEvent.subscribe(function() {
            if(typeof TGN.KeyWatcher != 'undefined') {
                TGN.KeyWatcher.unlockState();
                TGN.KeyWatcher.enable();
            }
        });	   
        TGN.SM.RefineSearchPanel.showEvent.subscribe(function() {
            if(typeof TGN.KeyWatcher != 'undefined') {
                TGN.KeyWatcher.disable();
                TGN.KeyWatcher.lockState();
            }
        });

        TGN.SM.RefineSearchPanel.element.className+=' modal';
        var p = _Dom('refineT_search-form');
        p.className = p.className.replace(' yui-panel', '');
        
        TGN.SM.RefineSearchPanel.render(document.body);
    };
    TGN.SM.LoadModTemplate = function(o) {
        var div = _Dom('ModTemplateStore');
        if(div != null) {
            if(o.responseText != 'undefined'){

                if (YAHOO.env.ua.ie > 5 && YAHOO.env.ua.ie <= 7) {
                    div.innerHTML += o.responseText;
                    //Directly apply zindex styles after they have been fully parsed into the dom.
                    //Inline style declarations are ignored by the tard browsers 
                    //TGN.SM.SetACZ(div,150);
                }
                else {
                    var ffdiv = document.createElement('div');
                    ffdiv.innerHTML += o.responseText;
                    div.appendChild(ffdiv);
                }

                if(typeof TGN.KeyWatcher != 'undefined') {
                    TGN.KeyWatcher.addListeners();
                }

                if(o.argument[0] == 'refine') {
                    TGN.SM.InitRefineSearch();
                    TGN.SM.PositionAndShow(TGN.SM.RefineSearchPanel, o.argument[1]+'_search-form');
                    TGN.SM.ShowMore('more_'+o.argument[1],'moreLink_'+o.argument[1]);
                }
                else {
                    var it = 0;
                    //TGN.SM.InitRefineSearch();
                    //TGN.SM.PositionAndShow(TGN.SM.NewSearchPanel, o.argument[1]+'_search-form');
                }
                if(o.argument[2] == true){
                    TGN.SM.ClearAndSave(o.argument[1]+"_search-form");
                }

                if (YAHOO.env.ua.ie == 7) {
                    var closerF = function(divN, clZ) { return function() { TGN.SM.SetACZ(divN,clZ); }; };
                    setTimeout(closerF(TGN.SM.RefineSearchPanel.element,150), 1);
                }
            }
        }
    };
    TGN.SM.ShowRefineLock = true;
    TGN.SM.ShowRefineSearchT = function(clearIt){
        if(clearIt) {
            TGN.SM.ShowRefineSearchImpl('true');
        }
        else {
            TGN.SM.ShowRefineSearchImpl('false');
        }
    };
    TGN.SM.ShowRefineSearch = function(evt, keypress){
        var clearP = 'false';
        if(typeof keypress != 'undefined' && keypress[1].keyCode == 78) {
            clearP = 'true';	
        }
        TGN.SM.ShowRefineSearchImpl(clearP);
    };
    TGN.SM.ShowRefineSearchImpl = function(clearP, showMore) {
        if (!TGN.SM.ShowRefineLock) return;
        else { TGN.SM.ShowRefineLock = false; }

        if (typeof TGN.KeyWatcher != 'undefined') {
            TGN.KeyWatcher.disable();
        }

        var advHidden = _Dom("refineT_msAV");
        var isAdv = false;
        if (advHidden != null && (advHidden.value == "1" || advHidden.value == "2")) {
            isAdv = true;
        }
        //don't want to slow the show template for sake of tracking, do this after
        setTimeout(function() { TGN.SM.TrackTemplate(clearP, isAdv); }, 10);

        //check for Template cached on page. 
        var qString = document.location.search;
        var Tcache = _Dom("ModTemplateStore");
        if (Tcache != null) {
            if (typeof TGN.SM.RefineSearchPanel != 'undefined') {

                TGN.SM.PositionAndShow(TGN.SM.RefineSearchPanel);

                // This will show more by default if showMore not provided (to support backward compatibility for calls to this function that already exist)
                if (typeof showMore == 'undefined' || showMore == 'true') {
                    TGN.SM.ShowMore('more_refineT', 'moreLink_refineT');
                }

                if (clearP == 'true') {
                    TGN.SM.ClearAndSave('refineT_search-form');
                    //TGN.SM.Clear('refineT_search-form');
                }
                else {
                    TGN.SM.RestoreClear('refineT_search-form');
                }
            }
            else {
                setTimeout("YAHOO.util.Connect.asyncRequest('GET', '/Mercury/Pages/AJAX/DefaultSearchTemplate.aspx" + qString.replace(/'/g, "&#39;") + "&tDomId=refineT', {success: TGN.SM.LoadModTemplate, argument:['refine','refineT'," + clearP + "], failure: TGN.SM.HandleFailure})", 1);
            }
        }
        if (typeof TGN.KeyWatcher != 'undefined') {
            TGN.KeyWatcher.enable();
        }

        TGN.SM.ShowRefineLock = true;
    };

    TGN.SM.getStyle = function(el,prop){
        return null;
    };
    if (document.body.currentStyle)
        TGN.SM.getStyle = function(el,prop){
            return el.currentStyle[prop];
        };
    else if (window.getComputedStyle)
        TGN.SM.getStyle = function(el,prop){
            return document.defaultView.getComputedStyle(el,null).getPropertyValue(prop);
        };
    TGN.SM.FocusFirstInput = function(root){
        try {
            var el = _Dom(root).getElementsByTagName('input');
            var t=null;
            for (var i = 0, l = el.length; i < l; i++) {
                t=el[i].type;
                if (!el[i].disabled && !el[i].readOnly && ('text'==t || 'password'==t)) {
                    if(TGN.SM.isDisplayed(el[i])){
                        var fEl = _Dom(el[i].id);
                        if(fEl.value != null && fEl.value == ""){
                            setTimeout(function(){if(fEl.value == '')try{fEl.focus();}catch(e){}},1);
                        }
                        break;

                    }
                }
            }
        } catch (e) { }
    };
    TGN.SM.isDisplayed = function(el) {
        var frm=el.form;
        while(el!= frm) {
            if(TGN.SM.getStyle(el,"display")=="none" || TGN.SM.getStyle(el,"visibility")=="hidden")
                return false;
            else
                el=el.parentNode;
        }
        return true;
    };
//SM Static Methods done

TGN.SM.NameHintShown = false;
TGN.SM.NameHintListener = function(e, tb ,daClient)
{
    if(TGN.SM.NameHintShown) {
        return;
    }
    if(tb.value != null && tb.value.length >= 4) 
    {
        TGN.SM.NameHintShown = true;
        var hintd = _Dom(daClient + "_gSrchTipsName");
        var hintsec = _Dom(daClient + "_gSearchTips");
        if (hintsec != null && typeof hintsec != 'undefined' && hintd != null && typeof hintd != 'undefined') 
        {
            hintd.style.display = "inline";
            hintsec.style.display = "inline";
        }
        YAHOO.util.Event.removeListener(tb, 'keyup', this);
    }
};
TGN.SM.NameHintCleared = false;
TGN.SM.DateHintListener = function(tb, mId)
{
    TGN.SM.NameHintShown = true; //disable the name hint

    var hintsec = null;
    if( !TGN.SM.NameHintCleared ) {
        TGN.SM.NameHintCleared = true;
        var hintd = _Dom(mId + "_gSrchTipsName");
        hintsec = _Dom(mId + "_gSearchTips");
        if (null != hintd && 'undefined' != hintd) {
            hintd.style.display = "none";
        }
        if (null != hintsec && 'undefined' != hintsec) {
            hintsec.style.display = "none";
        }
    }

    if(tb.value != null && tb.value.length >= 4) {
        var oyear = tb.value.match(/\d{4}/);
        if(oyear !== null && oyear != ""){
            hintsec = _Dom(mId + "_gSearchTips");
            var dateSec = _Dom(mId + "_gSrchTipsDate");
            if (hintsec != null && hintsec != 'undefined' && dateSec != null && dateSec != 'undefined') 
            {
                if(oyear > 1929) {
                    dateSec.style.display = "inline";
                    hintsec.style.display = "inline";
                }
                else if (oyear <= 1929) {
                    dateSec.style.display = "none";
                    hintsec.style.display = "none";
                }
            }
        }
    }
};

TGN.SM.ClearDateHint = function (mId) {
    var hintsec = _Dom(mId + '_gSearchTips');
    var datesec = _Dom(mId + '_gSrchTipsDate');

    if (hintsec != null && hintsec != 'undefined' && datesec != null && datesec != 'undefined') {
        datesec.style.display = "none";
        hintsec.style.display = "none";
    }
};

TGN.SM.GetHitReason = function(type){
    switch(type)
    {
    case "exact":
        return " matched exactly.";
        break;
    case "wildcard":
        return " matched a specified wildcard.";
        break;
    case "normalized":
        return " matched because of a normalized name match or a place authority lookup match.";
        break;
    case "initial":
        return " matched because the first letter of a specified name matches this initial.";
        break;
    case "soundex":
        return " matched based on Soundex which matches mispelled names or names that sound similar when pronounced (e.g. Smith, Smyth, and Smythe all sound alike).";
        break;
    case "proximity":
        return " matched because it was close to a date or location specified.";
        break;
    case "range":
        return " matched because it was within a range of dates, numbers, or text strings.";
        break;
    case "county":
        return " matched because the location specified does not correspond exactly but is contained within the same county.";
        break;
    case "state":
        return " matched because the location specified does not correspond exactly but is contained within the same state.";
        break;
    case "country":
        return " matched because the location specified does not correspond exactly but is contained within the same country.";
        break;
    default:
        break;
    }
    return "";
};
TGN.SM.GetHitShortReason = function(type){
    switch(type)
    {
    case "exact":
        return " matched exactly.";
        break;
    case "wildcard":
        return " matched a wildcard.";
        break;
    case "normalized":
        return " matched a normalized name or place.";
        break;
    case "initial":
        return " matched first letter of a name.";
        break;
    case "soundex":
        return " matched based on Soundex.";
        break;
    case "proximity":
        return " matched by proximity.";
        break;
    case "range":
        return " matched range of dates, numbers, or text strings.";
        break;
    case "county":
        return " matched because location is contained within the same county.";
        break;
    case "state":
        return " matched because location but is contained within the same state.";
        break;
    case "country":
        return " matched because location is contained within the same country.";
        break;
    default:
        break;
    }
    return "";
};
TGN.SM.HideRecordHits = function(){
    if (null != TGN.SM.HitDetailPanel){
        TGN.SM.HitDetailPanel.hide();
        TGN.SM.HitDetailPanel.destroy();
        TGN.SM.HitDetailPanel = null;
    }
};
TGN.SM.IndivRecCallback = {
// Callback object with success and failure members defined inline.
    success: function(o) {
        //success handler code
        var rXml = o.responseXML;
        var lbl, val;
        if(rXml != undefined){
            var fields = rXml.selectNodes("/response/record/field");
            for (var i = 0, l = fields.length; i < l; i++)
            {
                lbl = TGN.SM.GetText(fields[i].childNodes[0]);
                if (lbl != "DBTitle" && lbl != "ImageID")
                {
                    val = TGN.SM.GetText(fields[i].childNodes[1]);
                }
            }
        }

    },
    failure: function(o) {},
    argument: []
};
TGN.SM.ShowRecordHits = function(){
        var div = document.createElement('div');
        div.setAttribute('id','HitDetail');
        document.body.appendChild(div);
        var hitWid = 450;
        var hr='<table  border="0" cellpadding="0" cellspacing="0" class="srchTerms">';
        var ob = document.getElementById('searchDescCategory');
        if (null != ob)
            hr+='<tr><td>' + 'Category:' + '</td><td>' + TGN.SM.GetText(ob) + '</td></tr>';
        var ids = ['Name','Birth','Death','FamilyMembers','Migration','MilitaryService','Marriage','Other'];
        for (j in ids)
        {
            ob = document.getElementById('refine_'+ids[j]+'_mod');
            if (undefined != ob)
            {
                var lbls = ob.getElementsByTagName('strong');
                var spans = ob.getElementsByTagName('span');
                if (spans.length > 0)
                {
                    var txt = TGN.SM.GetText(spans[0]);
                    if (txt != null && txt.length > 0)
                        hr+='<tr><td>' + TGN.SM.GetText(lbls[0]) + '</td><td>' + txt + '</td></tr>';
                }
            }
        }
        hr += '</table>';

        var record = _DomD.getAncestorByClassName(this, 'record');
        if (null != record)
        {
            var hov = _DomD.getElementsByClassName('srchFoundDB', 'span', record);
            if (hov.length > 0)
            {
                var hovHtml = hov[0].parentNode.innerHTML;
                var start = hovHtml.indexOf("showIndiv2(");
                if (start != -1)
                {
                    start += 11;
                    var end = hovHtml.indexOf(")", start);
                    if (end != -1)
                    {
                        // params[0] = theEvent
                        // params[1] =  theDB
                        // params[2] =  theRec
                        // params[3] =  headerTxt
                        // params[4] =  subDb
                        // params[5] =  iid
                        // params[6] =  rc
                        // params[7] =  xtraQSParam
                        // params[9] =  noHover
                        var params = hovHtml.slice(start, end).replace(/'/g, "").split(",");
                        var ajUrl = "/Mercury/Pages/Ajax/IndivRec.aspx?IndivAjax=1&recid="+params[2]+"&db="+params[1]+"&output=xml&Use302Redirect=t";

                        if(params[4]) ajUrl += "&noSub=1";
                        if( params[9] ) ajUrl += "&NonHover=1";

                        if(params[5] != null && params[6] != null)
                            ajUrl += "&iid=" + params[5] + "&rc="+ params[6];

                        if( params[7] != null) ajUrl += "&" + params[7];
                        var transaction = YAHOO.util.Connect.asyncRequest('GET', ajUrl, TGN.SM.IndivRecCallback, null);  		

                    }
                }
            }
            hr += '<div id="results"><div id="results-main"><table  border="0" cellpadding="0" cellspacing="0" class="s_gsResults">' + record.innerHTML + '</table></div></div><div id="hitIndiv"></div><br />';
            hitWid = record.offsetWidth + 52;
        }
        hr += TGN.SM.HitReason(this);
        hr += '<br /><a class="closeBtn btn btn-cta" href="javascript:TGN.SM.HideRecordHits()"><span>Close</span></a>';
        TGN.SM.HitDetailPanel = new YAHOO.widget.Panel('HitDetail',
        {
            close: true,
            draggable: true,
            modal: true,
            visible: true,
            width: hitWid,
            underlay:'none',
            effect:{effect:YAHOO.widget.ContainerEffect.FADE,duration:0.5}
        } );
        TGN.SM.HitDetailPanel.setHeader("<h3>Why Am I Seeing This Record?</h3>");
        TGN.SM.HitDetailPanel.setBody(hr);
        TGN.SM.HitDetailPanel.render(document.body);
        
        TGN.SM.PositionAndShow(TGN.SM.HitDetailPanel);

};
TGN.SM.HitReason = function(star){
    var hr="";
    var reasons=star.getElementsByTagName("hlt");
    if (reasons.length != 0){
        hr="This record is dispayed as a match for your search because the following items matched exactly or were considered similar to the terms you specified:<ul>";
        for(var r=0, l=reasons.length; r < l; r++){
            var att = reasons[r].attributes;
            hr+="<li>\"<strong>"+att['match'].nodeValue+"</strong>\" was found "+att['count'].nodeValue+" times in this record and "+TGN.SM.GetHitReason(att['type'].nodeValue)+" Total score: "+att['score'].nodeValue+"</li>";
        }
        hr += "</ul>The overall score calculated for this record was " + star.getAttribute('score');
    }
    return hr;
};


TGN.SM.HitReasonTip = function(star){
    var hr="";
    var hlts=star.getElementsByTagName("hlt");
    if (hlts != null && hlts.length > 0){
        var reasons = [];
        for (var j = 0, l = hlts.length; j < l; j++)
        {
            var itype = 99;
            switch(hlts[j].getAttribute('type'))
            {
            case "exact":
                itype = 1;
                break;
            case "wildcard":
                itype = 2;
                break;
            case "normalized":
                itype = 3;
                break;
            case "initial":
                itype = 4;
                break;
            case "soundex":
                itype = 5;
                break;
            case "proximity":
                itype = 6;
                break;
            case "range":
                itype = 7;
                break;
            case "county":
                itype = 8;
                break;
            case "state":
                itype = 9;
                break;
            case "country":
                itype = 10;
                break;
            default:
                itype = 99;
                break;
            }
            hlts[j].setAttribute('itype', itype);
            reasons.push(hlts[j]);
        }
        reasons.sort(function(a,b){
            var at=a.getAttribute('itype');
            var bt=b.getAttribute('itype');
            if (at == bt)
                return b.getAttribute('score') - a.getAttribute('score');
                
            return at - bt;
            });
        var lastType = "";
        hr += "<ul>";
        for(var r in reasons){
            var att = reasons[r].attributes;
            var t = att['type'].nodeValue;
            var m = "\"<strong>"+att['match'].nodeValue+"</strong>\"";
            var c = att['count'].nodeValue != null ? 1*att['count'].nodeValue : 0;
            if (c > 1)
                m += " (" + c + " occurrences)";
            if (lastType == t)
            {
                var n = r*1;
                if (n == reasons.length - 1 || t != reasons[n + 1].getAttribute('type'))
                    hr+=" and " + m;
                else
                    hr+=", " + m;
            }
            else
            {
                if (r == 0)
                    hr += "<li>" + m;
                else
                    hr += TGN.SM.GetHitShortReason(lastType)+ "</li><li>" + m;
                lastType = t;
            }
        }
        hr += TGN.SM.GetHitShortReason(lastType) + "</li></ul><br />Click for detailed reasons.";
    }
    return hr;
};
TGN.SM.HitHighlightInit = function(){
    var records = YAHOO.util.Dom.getElementsByClassName("record", "tr", _Dom("results-main"));
    var spanId=0, starId=0;
    var fieldTips=new Array();
    var recordTips=new Array();
    for (var r in records){
        var spans = records[r].getElementsByTagName("span");
        for (var s=0, l = spans.length; s < l; s++){
            if (spans[s].className.indexOf("stars") > -1){
                var star = spans[s];
                star.id = "star"+starId++;
                star.onclick=TGN.SM.ShowRecordHits;
                var reason=TGN.SM.HitReasonTip(star);
                if (reason.length > 0){
                    star.title=reason;
                    recordTips.push(star.id);
                }
            }
            if (spans[s].className.indexOf("srchMatch") > -1/* || spans[s].className.indexOf("srchHit") > -1*/)
            {
                spans[s].id = 'srchMatch' + spanId++;
                var hit = TGN.SM.GetText(spans[s]);
                //score – integer between 0 and 1000
//				var score = 0;
//				if (spans[s].getAttribute('score') != null)
//					Math.round((spans[s].getAttribute('score')*100)/1000);
//				//type – string indicating an exact match to a search term or an expanded match as below:
                var type = spans[s].getAttribute('type');
                if (type != null)
                    spans[s].title = "<strong>" + hit + "</strong>" + TGN.SM.GetHitShortReason(type); //+ "  " + score + "%";
                fieldTips.push(spans[s].id);
            }
        }
    }
    if (fieldTips.length !=0){
        var fieldTT=new YAHOO.widget.Tooltip('matchFieldTips',{appendtodocumentbody:true,context:fieldTips,width:'300px',autodismissdelay:10000,effect:{effect:YAHOO.widget.ContainerEffect.FADE,duration:0.2}});
        fieldTT.element.className+=' alert';
        //fieldTT.setHeader('<h5>How Did This Match?</h5>');
    }
    if (recordTips.length !=0){
        var recordTT=new YAHOO.widget.Tooltip('whyMatchTip',{appendtodocumentbody:true,context:recordTips,width:'300px',autodismissdelay:15000,effect:{effect:YAHOO.widget.ContainerEffect.FADE,duration:0.2}});
        recordTT.element.className+=' alert';
        recordTT.setHeader('<h5>Why Am I Seeing This Record?</h5>');
    }
};
TGN.SM.GetText = function(el)
{
    if (el.innerText != undefined)
        return el.innerText;
    if (el.textContent != undefined)
        return el.textContent;
    if (el.innerHtml != undefined)
        return el.innerHtml;
    return null;
};
TGN.SM.SetText = function(el, txt)
{
    if (el.innerText != undefined)
        el.innerText = txt;
    if (el.textContent != undefined)
        el.textContent = txt;
};

// Adds a key watcher so the refine template typing 'n' or 'r' doesn't trigger while in a field
TGN.SM.SetKeyWatcher = function (el) {
    if (typeof TGN.KeyWatcher != 'undefined') {
        if (el.getAttribute("kw") != "true") {
            if (null != el && 'undefined' != el) { TGN.KeyWatcher.addListener(el); }
            el.setAttribute("kw", "true");
        }
    }
};

//YAHOO.util.Event.on(window, 'load', TGN.SM.HitHighlightInit);
//

/***************************************/
/* BEG Merge browseDate.js information */
/***************************************/

TGN.Search.BrowseDate.Calendar = function (Month,Year)
{
    var output = '';
    output += '<div id="browse_body"><table width="408" id="calendar"><tr align="center" valign="top">';
    output += '<td height="30" colspan="7"><nobr><select class="calendar" id="Month" name="Month" onchange="TGN.Search.BrowseDate.changeMonth();">';
    var monthIndex = 0;
    for (im = 0; im < availMonths[Year].length; im++) 
    {
        if (availMonths[Year][im] == Month)
        {
            output += '<option value="' + availMonths[Year][im] + '" SELECTED>' + monthNames[availMonths[Year][im]-1] + '<\/option>';
            monthIndex = im;
        }
        else
            output += '<option value="' + availMonths[Year][im] + '">' + monthNames[availMonths[Year][im]-1] + '<\/option>';  
    }
    output += '<\/select>&nbsp;&nbsp;<select class="calendar" ID="Year" NAME="Year" onChange="TGN.Search.BrowseDate.changeYear();">';
    for(iy = 0; iy < years.length; iy++)
    {
        if (years[iy] == Year)
            output += '<option value="' + years[iy] + '" SELECTED>' + years[iy] + '<\/option>';
        else
            output += '<option value="' + years[iy] + '">'          + years[iy] + '<\/option>';
    }
    output += '<\/select></nobr><\/td><\/tr>';
    firstDay = new Date(Year,Month-1,1);
    startDay = firstDay.getDay();
    if (((Year % 4 == 0) && (Year % 100 != 0)) || (Year % 400 == 0))
        browseDateDays[1] = 29;
    else
        browseDateDays[1] = 28;
    output += '<tr id="days">';
    for (i=0; i<7; i++)
        output += '<td>' + dow[i] +'<\/td>';
    output += '<\/tr><tr class="week">';
    var column = 0;
    for (i=0; i<startDay; i++, column++)
        output += '<td class="blank">&nbsp;<\/td>';
    for (i=1; i<=browseDateDays[Month-1]; i++, column++) 
    {
        if(availDays[Year][monthIndex] & (1 << (i-1)))
            output += '<td><a href="javascript:TGN.Search.BrowseDate.submitDay(\'' + dbid + '\',' + i + ',' + Month + ',' + Year + ')">' + i + '<\/a><\/td>';
        else
            output += '<td class="blank">' + i + '<\/td>';
        if (column == 6 && i != browseDateDays[Month-1]) 
        {
            output += '<\/tr><tr class="week">';
            column = -1;  
        } 
    }
    if (column > 0) 
    {
        for (i=1; column<7; i++, column++)
            output +=  '<td class="blank">&nbsp;<\/td>';
    }
    output += '<\/tr><\/table></div>';
    return output;
};

TGN.Search.BrowseDate.submitDay = function (id,day,month,year)
{
    TGN.Search.BrowseDate.submitFromCalendar(day, month, year);
    setDictionaryCookie("BROWSES", 'bm', month, null, null);
    setDictionaryCookie("BROWSES", 'by', year, null, null);
};

TGN.Search.BrowseDate.submitFromCalendar = function(day,month,year)
{
    document.location = "/Browse/view.aspx?dbid=" + dbid + "&path=" + year + "." + month + "." + day;
};

TGN.Search.BrowseDate.fnReplaceHtml = function (el, html) 
{
    var oldEl = YAHOO.util.Dom.get(el);
    
    if ('undefined' != typeof oldEl && null != oldEl) {
        var newEl = document.createElement(oldEl.nodeName);
        
        // Preserve the element's id and class (other properties are lost)
        newEl.id = oldEl.id;
        newEl.className = oldEl.className;

        // Replace the old with the new
        newEl.innerHTML = html;
        oldEl.parentNode.replaceChild(newEl, oldEl);

        /* Since we just removed the old element from the DOM, return a reference to the new element, which can be used to restore variable references. */
    }
    
    return newEl;
};

TGN.Search.BrowseDate.reload = function (month,year)
{
    var cs = YAHOO.util.Dom.get('CalendarSpot');
    var ca = TGN.Search.BrowseDate.Calendar(month,year);
    
    setDictionaryCookie("BROWSES", 'bm', month, null, null);
    setDictionaryCookie("BROWSES", 'by', year, null, null);
    
    TGN.Search.BrowseDate.fnReplaceHtml(cs, ca);
};

TGN.Search.BrowseDate.changeMonth = function ()
{
    var oMon = _Dom("Month");
    var oYear = _Dom("Year");
    var month = oMon.options[oMon.selectedIndex].value;
    var year = oYear.options[oYear.selectedIndex].value;
    TGN.Search.BrowseDate.reload(month,year);
    oMon.focus();
};

TGN.Search.BrowseDate.changeYear = function ()
{
    var oMon = _Dom("Month");
    var oYear = _Dom("Year");
    var month = oMon.options[oMon.selectedIndex].value;
    var year = oYear.options[oYear.selectedIndex].value;
    var bValidMonth = false;
    for(i = 0; i < availMonths[year].length; i++)
    {
        if(month == availMonths[year][i])
        {
            bValidMonth = true;
            break;
        }
    }
    if(!bValidMonth)
        month = availMonths[year][0];
    TGN.Search.BrowseDate.reload(month,year);
    oYear.focus();
};

TGN.Search.BrowseDate.buildCalendar = function ()
{
    var bd;
    var by = null;
    var bm = null;
    var path = getQueryStringParameter("path");
    if(null != path)
    {
        var parts = path.split('.');
        if(parts.length > 0 && parts[0].length == 4)
        {
            by = parts[0];
            if (parts.length > 1)
                bm = parts[1];
            else
                bm = availMonths[by][0];
        }
    }
    if (null == bm || null == by || null == availMonths[by]) {

        by = getDictionaryCookie("BROWSES", "by");
        bm = getDictionaryCookie("BROWSES", "bm");
    }

    if(null == bm || null == by || null == availMonths[by])
    {
        by = years[years.length-1];
        bm = availMonths[by][availMonths[by].length-1];
    }
    
    bd = TGN.Search.BrowseDate.Calendar(bm,by);
    TGN.Search.BrowseDate.fnReplaceHtml('CalendarSpot', bd);
};

var browseDateDays = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

/***************************************/
/* END Merge browseDate.js information */
/***************************************/

/***************************************/
/* BEG FamilyMemberContainer           */
/***************************************/

/* Family Member Container */
TGN.Ancestry.Search.FamilyMemberContainer = function () {
    // Member variables - some come in from JSON to configure the family member container
    this.UniqueID = "";
    this.PageType = 'Global'; // Global, Category, Collection
    this.MaxFather = 1;
    this.MaxMother = 1;
    this.MaxSpouse = 10;
    this.MaxChild = 10;
    this.MaxSibling = 10;
    this.CurrentRow = 0;
    this.NotSetPrefix = 'msnotset';
    this.FatherFieldPrefix = 'msfn';
    this.MotherFieldPrefix = 'msmn';
    this.ChildFieldPrefix = 'mscn';
    this.SpouseFieldPrefix = 'mssn';
    this.SiblingFieldPrefix = 'msbn';
    this.RowIDPrefix = 'row_';
    this.SelectOptionIDPrefix = 'rel_';
    this.FirstNameIDPrefix = 'fmfn_';
    this.LastNameIDPrefix = 'fmln_';
    this.FirstNameExactIDPrefix = 'fmfnx_';
    this.LastNameExactIDPrefix = 'fmlnx_';
    this.FirstNameExactDivPrefix = 'fmfnxdiv_';
    this.LastNameExactDivPrefix = 'fmlnxdiv_';
    this.HasQueryValues = false;
    this.AvailableFields = { 'f': { 'g': false, 's': false }, 'm': { 'g': true, 's': true }, 's': { 'g': true, 's': true }, 'c': { 'g': true, 's': true }, 'b': { 'g': true, 's': true} };
    this.FamilyMembers = "{ }"; // { "Relationship" : "Father", "FirstName" : "Willy", "LastName" : "Nelson", "FirstNameExact" : 0, "LastNameExact" : 1 };
    this.Relationships = { "ns": 0, "f": 0, "m": 0, "s": 0, "c": 0, "b": 0 }; // The count of each family member type selected
    this.Resources = { "HeadingFamilyMember": "Family Member", "HeadingFirstName": "First Name", "HeadingLastName": "Last Name", "OptionFather": "Father", "OptionMother": "Mother", "OptionSpouse": "Spouse", "OptionSibling": "Sibling", "OptionChild": "Child", "AddRowText": "Add Row", "RemoveRowText": "Remove", "ExactOnlyText": "Exact Only", "ChooseText": "Choose...", "NotAvailableText": "This value is not available in our index" };

    // Initialization
    this.Init = function (initObj) {
        this.PageType = this.GetSetting('PageType', initObj);
        this.MaxFather = this.GetSetting('MaxFather', initObj);
        this.MaxMother = this.GetSetting('MaxMother', initObj);
        this.MaxSpouse = this.GetSetting('MaxSpouse', initObj);
        this.MaxChild = this.GetSetting('MaxChild', initObj);
        this.MaxSibling = this.GetSetting('MaxSibling', initObj);
        this.Relationships = this.GetSetting('Relationships', initObj);
        this.HasQueryValues = this.GetSetting('HasQueryValues', initObj);
        this.FamilyMembers = this.GetSetting('FamilyMembers', initObj);
        this.UniqueID = this.GetSetting('UniqueID', initObj);
        this.Resources = this.GetSetting('Resources', initObj);
        this.AvailableFields = this.GetSetting('AvailableFields', initObj);
        this.Setup(initObj);
        this.ParentForm().FMC = this;
    };

    this.SetMaximums = function () {
        if (!this.IsRelationshipAllowed('f')) {
            this.MaxFather = 0;
        }

        if (!this.IsRelationshipAllowed('m')) {
            this.MaxMother = 0;
        }

        if (!this.IsRelationshipAllowed('s')) {
            this.MaxSpouse = 0;
        }

        if (!this.IsRelationshipAllowed('c')) {
            this.MaxChild = 0;
        }

        if (!this.IsRelationshipAllowed('b')) {
            this.MaxSibling = 0;
        }
    };

    this.AdjustSettingsBasedOnPageType = function () {
        // Adjust relationship maximums...
        if (this.PageType == 'Collection') {
            // Limit to one spouse for collection searches
            this.MaxSpouse = 1;
        }
    };

    this.Setup = function (initObj) {
        this.AdjustSettingsBasedOnPageType();
        this.SetMaximums();

        if (!this.HasQueryValues) {
            this.AddRow("", "", "", "", "");
        }
        else {
            // If there are query values
            this.PopulateFromQueryString();
        }

        this.CheckHideEverything();
    };

    this.ParentForm = function () {
        return TGN.SM.InstContainer[this.UniqueID + '_search-form'];
    };

    this.PopulateFromQueryString = function () {
        for (var i = 0; i < this.FamilyMembers.length; i++) {
            this.AddRow(
            this.FamilyMembers[i].Relationship,
            this.FamilyMembers[i].FirstName,
            this.FamilyMembers[i].LastName,
            this.FamilyMembers[i].FirstNameExact,
            this.FamilyMembers[i].LastNameExact);
        }
    };

    this.AddRow = function (rel, fname, lname, exactfn, exactln) {
        // Check that maximum's have not been exceeded. If they have, ignore this call to add a row (like an 11th spouse being added when only 10 are set to be allowed)
        if (this.ShouldAbortAddRow(rel, fname, lname)) { return; }
        if (null == fname || 'undefined' == fname) { fname = ""; }
        if (null == lname || 'undefined' == lname) { lname = ""; }
        var theTable = this.GetMainTable();
        var theBody = theTable.getElementsByTagName('tbody').item(0);
        var theRow = document.createElement('tr');
        var td1 = document.createElement('td');
        var td2 = document.createElement('td');
        var td3 = document.createElement('td');
        var td4 = document.createElement('td');

        td1.innerHTML = this.RenderSelect(rel);
        td2.innerHTML = this.RenderFirstName(fname, exactfn);
        td3.innerHTML = this.RenderLastName(lname, exactln);
        td4.innerHTML = this.RenderRemove();

        theRow.appendChild(td1);
        theRow.appendChild(td2);
        theRow.appendChild(td3);
        theRow.appendChild(td4);

        theBody.appendChild(theRow);

        this.SetID(theRow, this.RowIDPrefix + this.CurrentRow);

        theRow.setAttribute('rowid', this.CurrentRow);

        // Get the newly added select and run checks against it
        var sel = this.GetEl(this.SelectOptionIDPrefix + this.CurrentRow);

        this.OptionChanged(sel);

        // Disable keyboard shortcuts for the select dropdown and the first and last name text box
        if (typeof TGN.KeyWatcher != 'undefined') {
            var fnid = this.GetControlID(this.CurrentRow, rel, "g", "");
            var lnid = this.GetControlID(this.CurrentRow, rel, "s", "");
            var txtFirstName = this.GetEl(fnid);
            var txtLastName = this.GetEl(lnid);
            TGN.KeyWatcher.addListener(sel);
            TGN.KeyWatcher.addListener(txtFirstName);
            TGN.KeyWatcher.addListener(txtLastName);
        }

        this.CurrentRow++;
        if (this.CurrentRow == 1)
            theTable.style.display = 'block';
        this.CheckNoMoreRows();

        // If there is 3 items or less in the dropdown, select the 2nd item - this is to avoid having the user to select a drop down item and have another click.
        // This must also not happen if adding a prepopulated row                 
        var noOptions = this.CountSetRelationships();
        if (noOptions > 3) { // If more than 3 options are taken out of the drop down. This means two or less relationships are left to choose from.
            if (sel.options[sel.selectedIndex].value != rel) { // Don't default select to the same relationship twice
                sel.selectedIndex = 1;
                this.OptionChanged(sel);
            }
        }
    };

    this.RenderSelect = function (rel) {
        var theText = "";
        var theID = this.SelectOptionIDPrefix + this.CurrentRow;

        theText += "<select oldRel=\"0\" class=\"field ancSelect memRel cmbRel SMNoClear \" id=\"" + this.GetID(theID) + "\" onchange=\"TGN.SM.InstMgr('" + this.UniqueID + "_search-form','" + this.UniqueID + "').FMC.OptionChanged(this)\">";

        theText += "<option sort=\"0\" value=\"0\" " + (rel == "" ? "selected" : "") + ">" + this.Resources['ChooseText'] + "</option>";

        if (this.IsRelationshipAllowed('f')) {
            theText += "<option sort=\"1\" value=\"f\" " + (rel == "f" ? "selected" : "") + ">" + this.Resources['OptionFather'] + "</option>";
        }

        if (this.IsRelationshipAllowed('m')) {
            theText += "<option sort=\"2\" value=\"m\" " + (rel == "m" ? "selected" : "") + ">" + this.Resources['OptionMother'] + "</option>";
        }

        if (this.IsRelationshipAllowed('s')) {
            theText += "<option sort=\"3\" value=\"s\" " + (rel == "s" ? "selected" : "") + ">" + this.Resources['OptionSpouse'] + "</option>";
        }

        if (this.IsRelationshipAllowed('c')) {
            theText += "<option sort=\"4\" value=\"c\" " + (rel == "c" ? "selected" : "") + ">" + this.Resources['OptionChild'] + "</option>";
        }

        if (this.IsRelationshipAllowed('b')) {
            theText += "<option sort=\"5\" value=\"b\" " + (rel == "b" ? "selected" : "") + ">" + this.Resources['OptionSibling'] + "</option>";
        }

        theText += "</select>";
        return theText;
    };

    this.RenderFirstName = function (fname, exactfn) {
        var theText = "";
        var id = this.GetID(this.GetControlIDNew('g', ''));
        var name = this.GetControlIDNew('g', '');
        var idx = this.GetID(this.GetControlIDNew('g', '_x'));
        var namex = this.GetControlIDNew('g', '_x');
        var idExactDiv = this.GetID(this.FirstNameExactDivPrefix + this.CurrentRow);
        var conclick = "javascript:TGN.SM.InstMgr('" + this.UniqueID + "_search-form','" + this.UniqueID + "').ExactCBToggle(this)";
        if (null == fname || 'undefined' == fname) { fname = ""; }
        if ((null == exactfn || undefined == exactfn || "0" == exactfn || "" == exactfn)) { exactfn = ""; } else { exactfn = "checked=\"yes\""; }
        if (this.IsMatchAllExactChecked()) {
            exactfn = "checked=\"yes\"";
        }

        theText = '<div><input id="' + id + '" name="' + name + '" class="ancText field" type="text" value="' + fname.replace(/"/g, '&quot;') + '" /></div><div id="' + idExactDiv + '"><div class="sf-exact"><label><input id="' + idx + '" name="' + namex + '" class="ancCheckbox SM_advOpt" type="checkbox" ' + exactfn + ' tabindex="9999" value="1" onclick="' + conclick + '" /> ' + this.Resources["ExactOnlyText"] + '</label></div></div>';
        return theText;
    };

    this.RenderLastName = function (lname, exactln) {
        var theText = "";
        var id = this.GetID(this.GetControlIDNew('s', ''));
        var name = this.GetControlIDNew('s', '');
        var idx = this.GetID(this.GetControlIDNew('s', '_x'));
        var namex = this.GetControlIDNew('s', '_x');
        var idExactDiv = this.GetID(this.LastNameExactDivPrefix + this.CurrentRow);
        var conclick = "javascript:TGN.SM.InstMgr('" + this.UniqueID + "_search-form','" + this.UniqueID + "').ExactCBToggle(this)";
        if (null == lname || 'undefined' == lname) { lname = ""; }
        if ((null == exactln || undefined == exactln || "0" == exactln || "" == exactln)) { exactln = ""; } else { exactln = "checked=\"yes\""; }
        if (this.IsMatchAllExactChecked()) {
            exactln = "checked=\"yes\"";
        }

        theText = '<div><input id="' + id + '" name="' + name + '" class="ancText field" type="text" value="' + lname.replace(/"/g, '&quot;') + '" /></div><div id="' + idExactDiv + '"><div class="sf-exact"><label><input id="' + idx + '" name="' + namex + '" class="ancCheckbox SM_advOpt" type="checkbox" ' + exactln + ' tabindex="9999" value="1" onclick="' + conclick + '" /> ' + this.Resources["ExactOnlyText"] + '</label></div></div>';
        return theText;
    };

    this.RenderRemove = function () {
        var theText = "&nbsp;";
        var rl = "remLink" + this.CurrentRow + "_" + this.UniqueID + "";
        theText = "<a id=\"" + rl + "\" href=\"javascript:;\" tabindex=\"-1\" onclick=\"TGN.SM.InstMgr('" + this.UniqueID + "_search-form','" + this.UniqueID + "').FMC.RemoveRow(this)\">" + this.Resources['RemoveRowText'] + "</a>";
        return theText;
    };

    this.RemoveRow = function (theRow) {
        var theTable = this.GetMainTable();
        var i = theRow.parentNode.parentNode.rowIndex;
        var sel = this.GetEl(this.SelectOptionIDPrefix + (i - 1).toString());
        var theRel = sel.options[sel.selectedIndex].value;

        theTable.deleteRow(i);

        this.Relationships[theRel]--;
        this.EnforceRelationships();
        this.RenumberControls();
        this.ReDoControlNames();
        this.CurrentRow--;
        this.CheckLinkContainers();
        this.CheckNoMoreRows();
    };

    // If there are no rows in the FMC, and there is a link container, make sure the link container is shown only
    this.CheckLinkContainers = function () {
        var theTable = this.GetMainTable();
        var mainID = document.getElementById(this.UniqueID + '_fmc_linkModule_wrapper');
        var linkID = document.getElementById(this.UniqueID + '_fmc_linkModule');
        var divFMC = document.getElementById('FMC_' + this.UniqueID);

        if (this.CurrentRow == 0) {
            // See if there is a link container control. If it is there, show it
            if (null != mainID && 'undefined' != mainID && null != linkID && 'undefined' != linkID) {
                mainID.style.display = 'none';
                linkID.style.display = 'block';
                // Add a default row
                this.AddRow();
            } else {
                theTable.style.display = 'none';
                divFMC.style.marginTop = '0px'; // Keep the spacing tight between LEC and FMC
            }
        } else {
            if (null != mainID && 'undefined' != mainID && null != linkID && 'undefined' != linkID) {
                mainID.style.display = 'block';
                linkID.style.display = 'none';
            } else {
                divFMC.style.marginTop = '15px'; // Put spacing of LEC and FMC back to normal
            }
        }
    };

    // Removes all rows and resets all values
    this.Clear = function () {
        this.Relationships.ns = 0;
        this.Relationships.m = 0;
        this.Relationships.f = 0;
        this.Relationships.s = 0;
        this.Relationships.c = 0;
        this.Relationships.b = 0;
        this.CurrentRow = 0;

        var theTable = this.GetMainTable();
        var theRows = theTable.rows;

        // Removes all rows, except the very first heading row
        for (var i = theTable.rows.length - 1; i > 0; i--) {
            theTable.deleteRow(i);
        }
    };

    // These must be done in the order here
    this.OptionChanged = function (sel) {
        this.SetRelationshipCounts(sel);
        this.EnforceRelationships();
        this.SetControlIDsRow(sel.parentNode.parentNode.getAttribute('rowid'));
        this.CheckDisableEnabledState(sel);
        this.ReDoControlNames();
        this.ShowHideAvailableFields(sel);
        this.EnforceCheckboxRules(sel);
    };

    this.HideExact = function (selId, rowid, rel) {
        _Dom(selId.replace(this.SelectOptionIDPrefix, this.FirstNameExactDivPrefix)).style.display = 'none';
        _Dom(selId.replace(this.SelectOptionIDPrefix, this.LastNameExactDivPrefix)).style.display = 'none';
        this.GetEl(this.GetControlID(rowid, rel, "g", "_x")).style.display = 'none';
        this.GetEl(this.GetControlID(rowid, rel, "s", "_x")).style.display = 'none';
    };

    this.ShowExact = function (selId, rowid, rel) {
        var div1 = _Dom(selId.replace(this.SelectOptionIDPrefix, this.FirstNameExactDivPrefix));
        var div2 = _Dom(selId.replace(this.SelectOptionIDPrefix, this.LastNameExactDivPrefix));
        var txt1 = this.GetEl(this.GetControlID(rowid, rel, "g", ""));
        var txt2 = this.GetEl(this.GetControlID(rowid, rel, "s", ""));
        var chk1 = this.GetEl(this.GetControlID(rowid, rel, "g", "_x"));
        var chk2 = this.GetEl(this.GetControlID(rowid, rel, "s", "_x"));

        // If the text boxes are read only, don't show the checkbox
        if (txt1.readOnly != true) {
            div1.style.display = '';
            chk1.style.display = '';
            if (this.IsMatchAllExactChecked()) { chk1.checked = true; }
        } else {
            div1.style.display = 'none';
            chk1.style.display = 'none';
        }
        if (txt2.readOnly != true) {
            div2.style.display = '';
            chk2.style.display = '';
            if (this.IsMatchAllExactChecked()) { chk2.checked = true; }
        } else {
            div2.style.display = 'none';
            chk2.style.display = 'none';
        }
    };

    // Checks the select drop down relationship attribute and show/hide checkboxes based on rules
    this.EnforceCheckboxRules = function (sel) {
        var rowid = sel.parentNode.parentNode.getAttribute('rowid');
        var relType = sel.options[sel.selectedIndex].value;
        switch (relType) {
            case 'm': this.ShowExact(sel.id, rowid, relType); break;
            case 'f': this.ShowExact(sel.id, rowid, relType); break;
            case 's': this.ShowExact(sel.id, rowid, relType); break;
            case 'c': this.HideExact(sel.id, rowid, relType); break;
            case 'b': this.HideExact(sel.id, rowid, relType); break;
            default: this.HideExact(sel.id, rowid, relType); break;
        }
    };

    this.CheckDisableEnabledState = function (sel) {
        var fnid = ""; var lnid = ""; var fnexid = ""; var lnexid = "";
        var theValue = sel.options[sel.selectedIndex].value;
        var prefix = this.GetRelationshipPrefix(theValue);
        var theRow = sel.parentNode.parentNode;
        var rowid = theRow.getAttribute('rowid');
        var rel = sel.options[sel.selectedIndex].value;

        fnid = this.GetControlID(rowid, rel, "g", "");
        lnid = this.GetControlID(rowid, rel, "s", "");
        fnexid = this.GetControlID(rowid, rel, "g", "_x");
        lnexid = this.GetControlID(rowid, rel, "s", "_x");

        var txtFirstName = this.GetEl(fnid);
        var txtLastName = this.GetEl(lnid);
        var chkFirstName = this.GetEl(fnexid);
        var chkLastName = this.GetEl(lnexid);

        if (theValue == '0') {
            this.EnableDisableField(txtFirstName, false);
            this.EnableDisableField(txtLastName, false);
            chkFirstName.setAttribute('readonly', 'true');
            chkLastName.setAttribute('readonly', 'true');
        }
        else {
            this.EnableDisableField(txtFirstName, true);
            this.EnableDisableField(txtLastName, true);
            chkFirstName.removeAttribute('readonly', 'true');
            chkLastName.removeAttribute('readonly', 'true');
        }
    };

    // This function creates the correct control names so that when searching, the query string reflects the proper naming conventions.
    this.ReDoControlNames = function () {
        var theTable = this.GetMainTable();
        var theRows = theTable.getElementsByTagName('tr');
        var totals = { '0': 0, 'f': 0, 'm': 0, 's': 0, 'c': 0, 'b': 0 };
        for (var i = 0; i < (theRows.length); i++) {
            // Loop through each row and run the name changing
            if (i > 0) {
                try {
                    var rowN = (i - 1).toString();
                    var theRow = theRows[i];

                    // Get the select for this row
                    var sel = this.GetEl(this.SelectOptionIDPrefix + rowN);

                    // Get the relationship
                    var theRel = sel.options[sel.selectedIndex].value;

                    // Get the first name, last name, first name exact, and last name exact controls
                    var txtFirstName = this.GetEl(this.GetRelationshipPrefix(theRel) + 'g' + rowN);
                    var txtLastName = this.GetEl(this.GetRelationshipPrefix(theRel) + 's' + rowN);
                    var chkFirstNameExact = this.GetEl(this.GetRelationshipPrefix(theRel) + 'g' + rowN + '_x');
                    var chkLastNameExact = this.GetEl(this.GetRelationshipPrefix(theRel) + 's' + rowN + '_x');

                    // Change the names to reflect the relationship count

                    txtFirstName.name = this.GetRelationshipPrefix(theRel) + 'g' + totals[theRel].toString();
                    txtLastName.name = this.GetRelationshipPrefix(theRel) + 's' + totals[theRel].toString();
                    chkFirstNameExact.name = this.GetRelationshipPrefix(theRel) + 'g' + totals[theRel].toString() + '_x';
                    chkLastNameExact.name = this.GetRelationshipPrefix(theRel) + 's' + totals[theRel].toString() + '_x';

                    // Increment the relation
                    totals[theRel]++;
                }
                catch (err) {

                }
            }
        }
    };

    this.SetControlIDsRow = function (rowNumber, newNumber) {
        var sel = this.GetEl(this.SelectOptionIDPrefix + rowNumber);
        var relType = sel.options[sel.selectedIndex].value;
        var oldRelType = sel.getAttribute('oldRel');
        var oldPrefix = "";
        var prefix = "";
        var rowN = "";
        var newRowN = "";

        if (null == newNumber || 'undefined' == newNumber) { newNumber = rowNumber; }

        oldPrefix = this.GetRelationshipPrefix(oldRelType);
        prefix = this.GetRelationshipPrefix(relType);
        sel.setAttribute('oldRel', relType);
        newRowN = newNumber.toString();

        if (prefix == "") {
            return "";
        }

        rowN = rowNumber.toString();

        var txtFirstName = this.GetEl(oldPrefix + 'g' + rowN);
        var txtLastName = this.GetEl(oldPrefix + 's' + rowN);
        var chkFirstNameExact = this.GetEl(oldPrefix + 'g' + rowN + '_x');
        var chkLastNameExact = this.GetEl(oldPrefix + 's' + rowN + '_x');
        var divFNExact = this.GetEl(this.FirstNameExactDivPrefix + rowN);
        var divLNExact = this.GetEl(this.LastNameExactDivPrefix + rowN);
        var rLink = this.GetEl("remLink" + rowN);

        var theRow = sel.parentNode.parentNode;

        this.SetID(theRow, this.RowIDPrefix + newNumber.toString());
        theRow.setAttribute('rowid', newNumber.toString());

        this.SetID(sel, this.SelectOptionIDPrefix + newNumber.toString());
        this.SetID(txtFirstName, prefix + 'g' + newRowN);
        this.SetID(txtLastName, prefix + 's' + newRowN);
        this.SetID(chkFirstNameExact, prefix + 'g' + newRowN + '_x');
        this.SetID(chkLastNameExact, prefix + 's' + newRowN + '_x');
        this.SetID(divFNExact, this.FirstNameExactDivPrefix + newRowN);
        this.SetID(divLNExact, this.LastNameExactDivPrefix + newRowN);
        this.SetID(rLink, "remLink" + newRowN);
        return "";
    };

    // FMC:Loops through each row and re-does the id's. This is so the id's are always in the right order from removing/adding rows.
    this.RenumberControls = function () {
        var theTable = this.GetMainTable();
        for (var i = 0; i < (theTable.rows.length); i++) {
            // Loop through each row and run the id renumbering (skip the heading row)
            if (i > 0) {
                try {
                    var theRow = theTable.rows[i];
                    this.SetControlIDsRow(theRow.getAttribute('rowid'), i - 1);
                }
                catch (err) {

                }
            }
        }
    };

    this.SetRelationshipCounts = function (sel) {
        // Checks the select drop down old relationship attribute and decrements the count for that relationship
        // Checks the select drop down new relationship attribute and increments the count for that relationship
        var newRelType = sel.options[sel.selectedIndex].value;
        var oldRelType = sel.getAttribute('oldRel');

        if (newRelType == oldRelType) { oldRelType = '-1'; } // With new rows, just add the count instead of decrementing it and adding it

        switch (oldRelType) {
            case '0': this.Relationships.ns--; break;
            case 'm': this.Relationships.m--; break;
            case 'f': this.Relationships.f--; break;
            case 's': this.Relationships.s--; break;
            case 'c': this.Relationships.c--; break;
            case 'b': this.Relationships.b--; break;
        }

        switch (newRelType) {
            case '0': this.Relationships.ns++; break;
            case 'm': this.Relationships.m++; break;
            case 'f': this.Relationships.f++; break;
            case 's': this.Relationships.s++; break;
            case 'c': this.Relationships.c++; break;
            case 'b': this.Relationships.b++; break;
        }
    };

    this.EnforceRelationships = function () {
        var maxM = (this.Relationships.m >= this.MaxMother);
        var maxF = (this.Relationships.f >= this.MaxFather);
        var maxS = (this.Relationships.s >= this.MaxSpouse);
        var maxC = (this.Relationships.c >= this.MaxChild);
        var maxB = (this.Relationships.b >= this.MaxSibling);
        var noFather = (this.AvailableFields.f.g == false && this.AvailableFields.f.s == false);
        var noMother = (this.AvailableFields.m.g == false && this.AvailableFields.m.s == false);
        var noSpouse = (this.AvailableFields.s.g == false && this.AvailableFields.s.s == false);
        var noChild = (this.AvailableFields.c.g == false && this.AvailableFields.c.s == false);
        var noSibling = (this.AvailableFields.b.g == false && this.AvailableFields.b.s == false);
        var theOption;
        var theTable = this.GetMainTable();
        var theRows = theTable.getElementsByTagName('tr');

        // Loop through each row
        for (var i = 0; i < (theRows.length); i++) {
            if (i > 0) {
                var theRow = theRows[i];
                var theID = theRow.getAttribute('rowid');
                var theSel = this.GetEl(this.SelectOptionIDPrefix + theID);
                var rel = theSel.options[theSel.selectedIndex].value;
                var theIndex = theSel.selectedIndex;

                if (maxF && rel != 'f') {
                    // Father is out
                    this.RemoveSelectOptionByValue(theSel, 'f');
                }
                else {
                    // Check to see if father needs to go back in
                    if (!this.DoesSelectHaveValue(theSel, 'f') && !noFather) {
                        theOption = new Option(this.Resources['OptionFather'], 'f', false, false);
                        theSel.options[theSel.length] = theOption;
                        this.SortSelect(theSel);
                    }
                }

                if (maxM && rel != 'm') {
                    // Mother is out
                    this.RemoveSelectOptionByValue(theSel, 'm');
                }
                else {
                    // Check to see if mother needs to go back in
                    if (!this.DoesSelectHaveValue(theSel, 'm') && !noMother) {
                        theOption = new Option(this.Resources['OptionMother'], 'm', false, false);
                        theSel.options[theSel.length] = theOption;
                        this.SortSelect(theSel);
                    }
                }

                if (maxS && rel != 's') {
                    // Spouse is out
                    this.RemoveSelectOptionByValue(theSel, 's');
                }
                else {
                    // Check to see if spouse needs to go back in
                    if (!this.DoesSelectHaveValue(theSel, 's') && !noSpouse) {
                        theOption = new Option(this.Resources['OptionSpouse'], 's', false, false);
                        theSel.options[theSel.length] = theOption;
                        this.SortSelect(theSel);
                    }
                }

                if (maxC && rel != 'c') {
                    // Child is out
                    this.RemoveSelectOptionByValue(theSel, 'c');
                }
                else {
                    // Check to see if child needs to go back in
                    if (!this.DoesSelectHaveValue(theSel, 'c') && !noChild) {
                        theOption = new Option(this.Resources['OptionChild'], 'c', false, false);
                        theSel.options[theSel.length] = theOption;
                        this.SortSelect(theSel);
                    }
                }

                if (maxB && rel != 'b') {
                    // Sibling is out
                    this.RemoveSelectOptionByValue(theSel, 'b');
                }
                else {
                    // Check to see if sibling needs to go back in
                    if (!this.DoesSelectHaveValue(theSel, 'b') && !noSibling) {
                        theOption = new Option(this.Resources['OptionSibling'], 'b', false, false);
                        theSel.options[theSel.length] = theOption;
                        this.SortSelect(theSel);
                    }
                }
            }
        }
    };

    this.RemoveSelectOptionByValue = function (sel, value) {
        for (var i = 0; i < sel.length; i++) {
            var theOption = sel.options[i];
            if (theOption.value == value) {
                sel.remove(i);
            }
        }
    };

    this.SortSelect = function (origSel) {

        var newSel = origSel;
        var origSelect = origSel.options[origSel.selectedIndex].value;

        this.SortIndividualOption(origSel, newSel, "0");

        if (this.IsRelationshipAllowed('f')) {
            this.SortIndividualOption(origSel, newSel, "f");
        }

        if (this.IsRelationshipAllowed('m')) {
            this.SortIndividualOption(origSel, newSel, "m");
        }

        if (this.IsRelationshipAllowed('s')) {
            this.SortIndividualOption(origSel, newSel, "s");
        }

        if (this.IsRelationshipAllowed('c')) {
            this.SortIndividualOption(origSel, newSel, "c");
        }

        if (this.IsRelationshipAllowed('b')) {
            this.SortIndividualOption(origSel, newSel, "b");
        }

        for (i = 0; i < newSel.length; i++) {
            if (newSel.options[i].value == origSelect) {
                newSel.selectedIndex = i;
                break;
            }
        }
    };



    this.SortIndividualOption = function (origSel, newSel, rel) {
        for (var i = 0; i < origSel.length; i++) {
            var theOption = origSel.options[i];

            if (theOption.value == rel) {
                try {
                    
                    newSel.appendChild(theOption);

                }
                catch (err) {
                    newSel.options[newSel.length] = theOption;
                }
                return;
            }
        }
    };

    // Helper Function
    this.IsRelationshipAllowed = function (rel) {
        if (null == rel || 'undefined' == rel || rel == "" || rel == "0") { return true; }

        if (this.AvailableFields[rel].g == true || this.AvailableFields[rel].s == true) {
            return true;
        }

        return false;
    };

    // Helper Function
    this.GetRelationshipPrefix = function (rel) {
        var rv = "";
        switch (rel) {
            case "f": rv = this.FatherFieldPrefix; break;
            case "m": rv = this.MotherFieldPrefix; break;
            case "s": rv = this.SpouseFieldPrefix; break;
            case "c": rv = this.ChildFieldPrefix; break;
            case "b": rv = this.SiblingFieldPrefix; break;
            default: rv = this.NotSetPrefix; break;
        }

        return rv;
    };

    // Helper Function
    this.DoesSelectHaveValue = function (sel, desiredValue) {
        for (var i = 0; i < sel.length; i++) {
            var theOption = sel.options[i];
            if (theOption.value == desiredValue) {
                return true;
            }
        }
        return false;
    };

    // Helper Function
    this.GetControlIDNew = function (type, exact) {
        var prefix = this.NotSetPrefix;
        var rowNumber = this.CurrentRow;
        var rv = prefix + type + rowNumber + exact;
        return rv;
    };

    // Helper Function
    this.GetControlID = function (rowNumber, rel, type, exact) {
        var prefix = this.GetRelationshipPrefix(rel);
        var newExact = (null == exact ? "" : exact);
        var newRow = rowNumber.toString();
        var rv = prefix + type + newRow + newExact;
        return rv;
    };

    // Helper Function
    this.SetName = function (ctrl, name) {
        ctrl.name = name;
    };

    // Helper Function
    this.GetID = function (id) {
        return id + '_' + this.UniqueID;
    };

    // Helper Function
    this.SetID = function (ctrl, id) {
        ctrl.id = id + '_' + this.UniqueID;
    };

    // Helper Function
    this.GetMainID = function () {
        return 'FMC_' + this.UniqueID;
    };

    // Helper Function
    this.GetMainTable = function () {
        return document.getElementById('fmcTable_' + this.UniqueID);
    };

    // Helper Function
    this.GetEl = function (id) {
        return document.getElementById(id + '_' + this.UniqueID);
    };

    // Helper Function
    this.GetSetting = function (setting, initObj) {
        if (null != initObj[setting] && 'undefined' != initObj[setting]) {
            return initObj[setting];
        }
        else {
            return this[setting]; // default
        }
    };

    // Helper Function
    this.ShouldAbortAddRow = function (rel, fname, lname) {
        var abort = false;
        switch (rel) {
            case 'f': if (this.Relationships.f >= this.MaxFather) { abort = true; } break;
            case 'm': if (this.Relationships.m >= this.MaxMother) { abort = true; } break;
            case 's': if (this.Relationships.s >= this.MaxSpouse) { abort = true; } break;
            case 'c': if (this.Relationships.c >= this.MaxChild) { abort = true; } break;
            case 'b': if (this.Relationships.b >= this.MaxSibling) { abort = true; } break;
        }

        // Set fname and lname
        if (null == fname || 'undefined' == fname) { fname = ''; }
        if (null == lname || 'undefined' == lname) { lname = ''; }

        /* Taking this out for now - it is preventing new rows from being added
        // If there is no first name or last name and this is not the first row, abort as well
        if (("" == fname) && ("" == lname) && this.CurrentRow > 0) {
        abort = true;
        }
        */

        // If the maximum rows are currently showing, abort this as well
        if (this.MaximumReached()) {
            abort = true;
        }

        // Check to see if the relationship is allowed to be added
        if (!this.IsRelationshipAllowed(rel)) {
            abort = true;
        }

        return abort;
    };

    // Helper Function
    this.MaximumReached = function () {
        if (this.CurrentRow == this.GetMaxAllowedRows()) {
            return true;
        }

        return false;
    };

    // Helper Function
    this.CheckNoMoreRows = function () {
        var divAdd = this.GetEl('fmcAddLink');

        if (this.CurrentRow >= this.GetMaxAllowedRows()) {
            divAdd.style.display = 'none';
        } else {
            divAdd.style.display = '';
        }
    };

    // Helper Function - What fields to show for a selected relationship
    this.ShowHideAvailableFields = function (sel) {
        var showG = true;
        var showS = true;
        var rel = sel.options[sel.selectedIndex].value;
        var theRow = sel.parentNode.parentNode;
        var rowid = theRow.getAttribute('rowid');
        switch (rel) {
            case 'f': if (this.AvailableFields.f.g != true) { showG = false; } if (this.AvailableFields.f.s != true) { showS = false; } break;
            case 'm': if (this.AvailableFields.m.g != true) { showG = false; } if (this.AvailableFields.m.s != true) { showS = false; } break;
            case 's': if (this.AvailableFields.s.g != true) { showG = false; } if (this.AvailableFields.s.s != true) { showS = false; } break;
            case 'c': if (this.AvailableFields.c.g != true) { showG = false; } if (this.AvailableFields.c.s != true) { showS = false; } break;
            case 'b': if (this.AvailableFields.b.g != true) { showG = false; } if (this.AvailableFields.b.s != true) { showS = false; } break;
            case '0': break;
        }

        var idfn = this.GetID(this.GetControlID(rowid, rel, 'g', ""));
        var idln = this.GetID(this.GetControlID(rowid, rel, 's', ""));
        var theFieldG = document.getElementById(idfn);
        var theFieldGX = this.GetEl(this.FirstNameExactDivPrefix + rowid);
        var theFieldS = document.getElementById(idln);
        var theFieldSX = this.GetEl(this.LastNameExactDivPrefix + rowid);

        if (showG == false) {
            this.EnableDisableField(theFieldG, false);
            theFieldG.setAttribute("title", this.Resources['NotAvailableText']);
            theFieldGX.style.display = 'none';
        }
        else {
            theFieldG.setAttribute("title", "");
            theFieldGX.style.display = '';
        }

        if (showS == false) {
            this.EnableDisableField(theFieldS, false);
            theFieldS.setAttribute("title", this.Resources['NotAvailableText']);
            theFieldSX.style.display = 'none';
        }
        else {
            theFieldS.setAttribute("title", "");
            theFieldSX.style.display = '';
        }
    };

    // Helper Function
    this.IsMatchAllExactChecked = function () {
        var el = document.getElementById(this.UniqueID + '_' + 'xcb');
        if (el.checked) {
            return true;
        } else {
            return false;
        }
    };

    // Helper Function
    this.GetMaxAllowedRows = function () {
        var theMax = this.MaxFather + this.MaxMother + this.MaxSpouse + this.MaxChild + this.MaxSibling;
        return theMax;
    };

    // Helper Function
    this.RemoveBlankRows = function () {
        var theTable = this.GetMainTable();
        var theRows = theTable.getElementsByTagName('tr');

        // Loop through each row
        for (var i = 0; i < (theRows.length); i++) {
            if (i > 0) {
                var theRow = theRows[i];
                var theID = theRow.getAttribute('rowid');
                var theSel = this.GetEl(this.SelectOptionIDPrefix + theID);
                var rel = theSel.options[theSel.selectedIndex].value;
                if (rel == '0') {
                    this.RemoveRow(theRow);
                }
            }
        }
    };

    // Helper Function
    this.GetRelNumber = function (rel) {
        var theNumber = 0;
        if (null == rel || 'undefined' == rel) { rel = ''; }
        switch (rel) {
            case '': case '0':
                theNumber = this.Relationships.ns;
                break;
            case 'f':
                theNumber = this.Relationships.f;
                break;
            case 'm':
                theNumber = this.Relationships.m;
                break;
            case 's':
                theNumber = this.Relationships.s;
                break;
            case 'c':
                theNumber = this.Relationships.c;
                break;
            case 'b':
                theNumber = this.Relationships.b;
                break;
        }
        if (theNumber > 0) {
            theNumber--;
        }
        return theNumber;
    };

    // Helper Function
    this.EnableDisableField = function (theField, enable) {
        if (enable == false) {
            theField.setAttribute('readonly', 'true');
            theField.readOnly = true;
            theField.className = theField.className + ' disabled';
        }
        else {
            theField.removeAttribute('readonly', 'true');
            theField.readOnly = false;
            theField.className = theField.className.replace(' disabled', '');
        }
    };

    // Helper Function
    this.CheckHideEverything = function () {
        if (!this.AvailableFields.f.g && !this.AvailableFields.f.s &&
            !this.AvailableFields.m.g && !this.AvailableFields.m.s &&
            !this.AvailableFields.s.g && !this.AvailableFields.s.s &&
            !this.AvailableFields.c.g && !this.AvailableFields.c.s &&
            !this.AvailableFields.b.g && !this.AvailableFields.b.s) {
            var el = this.GetEl('FMC');
            el.style.display = 'none';
        }
    };

    // Helper Function - returns the number of relationships that will not show up in the family member select drop down.
    this.CountSetRelationships = function () {
        var count = 0;
        if (!this.AvailableFields.f.g && !this.AvailableFields.f.s) { count++; }
        if (!this.AvailableFields.m.g && !this.AvailableFields.m.s) { count++; }
        if (!this.AvailableFields.s.g && !this.AvailableFields.s.s) { count++; }
        if (!this.AvailableFields.c.g && !this.AvailableFields.c.s) { count++; }
        if (!this.AvailableFields.b.g && !this.AvailableFields.b.s) { count++; }

        return count;
    };
};

/***************************************/
/* END FamilyMemberContainer           */
/***************************************/

/************************************************************************************************************************************************************/
/************************************************************************************************************************************************************/
/************************************************************************************************************************************************************/
/************************************************************************************************************************************************************/
/************************************************************************************************************************************************************/

/***************************************/
/* BEG LifeEventContainer              */
/***************************************/

//Everything starts with the this.Init function. Just look there to see what gets run when the page loads and you can follow what everything is doing through that.

/* Life Event Container */
TGN.Ancestry.Search.LifeEventContainer = function () {
    // Member variables - some come in from JSON to configure the family member container
    // *** Removed some defaults that were really just there for debugging purposes
    this.BaseZIndex = 98;
    this.UniqueID = "";
    this.PageType = 'Global'; // Global, Category, Collection
    this.CurrentRow = 0;
    this.DoMoreEventsLabel = false;

    // Initialization
    this.Init = function (initObj) {

        this.CurrentRow = this.GetSetting('CurrentRow', initObj);
        this.EventsSelected = this.GetSetting('EventsSelected', initObj);
        this.PageType = this.GetSetting('PageType', initObj);
        this.UniqueID = this.GetSetting('UniqueID', initObj);
        this.Resources = this.GetSetting('Resources', initObj);
        this.EventsMaximum = this.GetSetting('EventsMaximum', initObj);
        this.Templates = this.GetSetting('Templates', initObj);
        this.LifeEventCodes = this.GetSetting('LifeEventCodes', initObj);
        this.DefaultEvent = this.GetSetting('DefaultEvent', initObj);
        this.DoMoreEventsLabel = this.GetSetting('DoMoreEventsLabel', initObj);

        // Add this to ensure the correct sort order for the lec drop down
        this.LifeEventCodeSortOrder = this.GetSetting('LifeEventCodeSortOrder', initObj);

        // If we are talking to a version of the form that is less than 2 then SelectOptionText will not exist. 
        // Therefore we need to build it. Also, LifeEventCodeSortOrder will not exist either. So we need to build it
        // as well.
        if (typeof TGN.SearchWidget.formVersion == 'undefined') {
            TGN.SearchWidget.formVersion = 0;
        }
        if (TGN.SearchWidget.formVersion < 2) {
            this.SetupEventOptionResources();
            this.SetupLifeEventCodeSortOrder();
        }
        if (TGN.SearchWidget.formVersion < 3) {
            this.SetupOldEventIndexes();
        }

        this.SetupEventsSelected();
        this.SetupEventIndexUsage();

        //this.SetupPInfoElem();

        this.Setup(initObj);

        this.ParentForm().LEC = this;
        this.EnforceEvents();
        this.RenumberControls();
        this.EnforceEvents();
        this.CheckNoMoreRows();
    };

    // Obsolete - this supports search form versions earlier than v=2
    this.SetupEventOptionResources = function () {
        this.Resources.SelectOptionText = {
            y: this.Resources['OptionAny'],
            b: this.Resources['OptionBirth'],
            g: this.Resources['OptionMarriage'],
            d: this.Resources['OptionDeath'],
            r: this.Resources['OptionResidence'],
            v: this.Resources['OptionDivorce'],
            a: this.Resources['OptionArrival'],
            e: this.Resources['OptionDeparture'],
            i: this.Resources['OptionMilitary']
        };
    };

    // Obsolete - this supports search form versions earlier than v=2
    this.SetupLifeEventCodeSortOrder = function () {
        this.LifeEventCodeSortOrder = [
            'y',
            'b',
            'd',
            'r',
            'g',
            'v',
            'a',
            'e',
            'i'
        ];
    };

    // Obsolete - this is only required to support form version older than v=3
    this.SetupOldEventIndexes = function () {
        var i, code, selectEl, curEventIndexes = {};
        for (i = 0; i < this.CurrentRow; i++) {
            selectEl = this.GetEl(this.GetIDSelectEvent(i));
            code = selectEl.getAttribute('oldEvent');
            curEventIndexes[code] = curEventIndexes[code] || 0;
            selectEl.setAttribute('oldEventIndex', curEventIndexes[code] || "");
            curEventIndexes[code]++;
        }
    };

    // Obsolete - this is only required to support form version older than v=3
    this.SetupOldEventIndex = function (rowid) {
        var code, selectEl, eventIndex;
        selectEl = this.GetEl(this.GetIDSelectEvent(rowid));
        code = selectEl.getAttribute('oldEvent');
        eventIndex = this.GetNextAvailableEventIndex(code);
        selectEl.setAttribute('oldEventIndex', eventIndex || "");
    };

    // Sets up a dictionary of arrays. One array for each event code. Each array is composed of booleans. Each boolean
    // identifies whether the index of the array is currently being used as an index for that event.
    this.SetupEventIndexUsage = function () {
        var code, max;
        this.EventsIndexUsage = {};
        for (var i = 0; i < this.LifeEventCodes.length; i++) {
            code = this.LifeEventCodes[i];
            this.EventsIndexUsage[code] = [];
            // If this is the default code, then we should use the max allowed rows since you can't really limit
            // the default event to it's given maximum.
            max = (code == this.DefaultEvent ? this.GetMaxAllowedRows() : this.EventsMaximum[code]);
            for (var j = 0; j < max; j++) {
                // If the item has been selected already, then the item in the array will be set to true.
                // otherwise it is set to false.
                this.EventsIndexUsage[code].push(j < this.EventsSelected[code] ? true : false);
            }
        }
    };

    // It appears that sometimes EventsSelected doesn't end up always having a value. Let's just make sure up front that there is a zero if
    // it's undefined, null, NaN, 0, or ""
    this.SetupEventsSelected = function () {
        var code;
        for (var i = 0; i < this.LifeEventCodes.length; i++) {
            code = this.LifeEventCodes[i];
            this.EventsSelected[code] = this.EventsSelected[code] || 0;
        }
    };

    this.ClaimEventIndex = function (eventCode, eventIndex) {
        this.EventsIndexUsage[eventCode][eventIndex] = true;
    };

    this.UnclaimEventIndex = function (eventCode, eventIndex) {
        this.EventsIndexUsage[eventCode][eventIndex] = false;
    };

    this.GetNextAvailableEventIndex = function (eventCode) {
        for (var i = 0; i < this.EventsIndexUsage[eventCode].length; i++) {
            if (!this.EventsIndexUsage[eventCode][i]) {
                return i;
            }
        }
        return -1;
    };

    this.ClaimNextAvailableEventIndex = function (eventCode) {
        var nextAvailableEventIndex = this.GetNextAvailableEventIndex(eventCode);
        if (nextAvailableEventIndex >= 0) {
            this.ClaimEventIndex(eventCode, nextAvailableEventIndex);
        }
    };

    this.AdjustSettings = function () {
        // Show/Hide initial Year/Date label depending on advanced or basic view to start with. Also toggles exact checkboxes
        this.ParentForm().LoadExactCheckBoxes(true);
        this.ParentForm().ToggleAdvTags();
        if (this.DoMoreEventsLabel) {
            this.SetMoreEventsStyles();
        }
    };

    this.SetMoreEventsStyles = function () {
        var head = document.getElementsByTagName('head')[0],
            style = document.createElement('style'),
            rules = document.createTextNode("" +
            ".divLEC label.lecLabel.moreEvents { font-weight: bold; font-size: 12px; color: #000000; margin: 4px 0px 4px 0px; }" +
            ".divLEC tr#row_--2-- div.lec_col2 { margin-top: 8px; } " +
            ".divLEC tr#row_--2-- div.lec_col3 { margin-top: 8px; } " +
            ".divLEC tr#row_--2-- div.lec_col4 { margin-top: 8px; }");

        style.type = 'text/css';
        if (style.styleSheet)
            style.styleSheet.cssText = rules.nodeValue;
        else
            style.appendChild(rules);
        head.appendChild(style);
    };

    this.Setup = function (initObj) {
        this.AdjustSettings();

        // Remove 'remove' column if not a global template
        this.CheckRemoveFeatures();

        // Check to hide everything completely
        this.CheckHideEverything();
    };

    this.ParentForm = function () {
        return TGN.SM.InstContainer[this.UniqueID + '_search-form'];
    };

    this.AddRowNew = function (eventtype, dateinfo, placeinfo) {
        var abortAddRow = false;

        if (null == eventtype || 'undefined' == eventtype) { eventtype = this.DefaultEvent; }

        abortAddRow = this.ShouldAbortAddRow(eventtype, dateinfo, placeinfo);

        if (abortAddRow == true) { return; }

        var theRow = document.createElement('tr');
        var td = document.createElement('td');
        var rowData = this.Templates[eventtype];

        var theTable = this.GetMainTable();
        var theBody = theTable.getElementsByTagName('tbody').item(0);

        if ('undefined' == rowData || null == rowData) {
            return; // Abort
        }

        rowData = rowData.replace(/#CurrentRowNumber#/g, this.EncodeRowNumber(this.CurrentRow));
        rowData = rowData.replace(/#EventIndex#/g, this.GetEventIndex(eventtype));
        rowData = rowData.replace(/#LOCATIONZINDEX#/g, this.GetLocationColZindex(this.CurrentRow).toString());
        rowData = this.GetMoreEventsLabel(rowData, this.CurrentRow);

        // Append the row data
        theRow.setAttribute('rowid', this.CurrentRow);
        theRow.id = 'row_' + this.EncodeRowNumber(this.CurrentRow);
        td.innerHTML = rowData;

        theRow.appendChild(td);
        theBody.appendChild(theRow);

        if (typeof TGN.SearchWidget.formVersion == 'undefined' || TGN.SearchWidget.formVersion < 3) {
            this.SetupOldEventIndex(this.CurrentRow);
        }

        this.SetDateFields(dateinfo, this.CurrentRow);
        this.SetLocationFields(placeinfo, this.CurrentRow);

        // Get the newly added select and run checks against it
        var sel = this.GetEl(this.GetIDSelectEvent(this.CurrentRow));

        this.ClaimNextAvailableEventIndex(eventtype);
        this.EventsSelected[eventtype]++;
        this.EnforceEvents();

        // If exact all, check the place filter option
        this.CheckPlaceFilterOption(this.CurrentRow);

        this.CurrentRow++;
        this.CheckNoMoreRows();
    };

    /*
    // Use this for debugging. It gives a nice console log of the life event container's form data.
    this.ConsoleLec = function () {
    var table = this.GetMainTable();

    for (i = 0; i < table.rows.length; i++) {
    this.ConsoleLecRow(table.rows[i]);
    }
    };
    
    // Use this for debugging. It gives a nice console log of the life event container's form data.
    this.ConsoleLecRow = function (row) {
    var destTags, i, j, l;
    destTags = row.getElementsByTagName("INPUT");
    for (j = 0, l = destTags.length; j < l; j++) {
    if (destTags[j].type == "radio" || destTags[j].type == "checkbox") {
    if (!destTags[j].checked) {
    continue;
    }
    }
    console.log('\t\tname: ' + destTags[j].name + ', value: ' + destTags[j].value + ', id: ' + destTags[j].id);
    };

    destTags = row.getElementsByTagName("SELECT");
    for (j = 0, l = destTags.length; j < l; j++) {
    console.log('\t\tname: ' + destTags[j].name + ', value: ' + destTags[j].value + ', id: ' + destTags[j].id);
    }
    };
    */

    // Whether there should be text that says 'More Events' above the event
    this.GetMoreEventsLabel = function (rowData, rowIndex) {

        if (!this.DoMoreEventsLabel) {
            return rowData;
        }

        var rv = "";
        var replaceText = "<label class=\"lecLabel\">&nbsp;</label>";
        if (null == rowIndex || 'undefined' == rowIndex) {
            rowIndex = this.CurrentRow;
        }
        if (rowIndex == 2) {
            rv = "<label class=\"lecLabel moreEvents\">" + this.Resources.CaptionMoreEvents + "</label>";
            rowData = rowData.replace(replaceText, rv);
        } else {
            rv = rowData;
        }

        rv = rowData;
        return rv;
    };

    // If exact only, check the place filter option for exact only
    this.CheckPlaceFilterOption = function (row) {
        var theDefField = this.GetEl(this.GetIDDefaultPlaceFilter(row));
        var theField = this.GetEl(this.GetIDExactPlaceFilter(row));
        var theExact = this.GetEl(this.GetID("xcb"));
        var exactDate = this.GetEl(this.GetIDExactOnly(row));

        if (null != theField && 'undefined' != theField && null != theExact && 'undefined' != theExact) {
            if (theExact.checked) {
                theField.click();
                theField.checked = true;
            }
            else {
                theDefField.click();
                theDefField.checked = true;
            }

            // Check "exact only" for date field if "match all terms exactly" set...
            if (exactDate != null && exactDate != 'undefined') {
                exactDate.checked = theExact.checked;
            }
        }
    };

    this.SetDateFields = function (dateinfo, row) {
        var selMonth = this.GetEl(this.GetIDMonth(row));
        var selDay = this.GetEl(this.GetIDDay(row));
        var fieldYear = this.GetEl(this.GetIDYear(row));
        var fieldExact = this.GetEl(this.GetIDExactOnly(row));
        var fieldPM = this.GetEl(this.GetIDPlusMinus(row));
        var day, month, year, exact, pm;

        day = ""; month = ""; year = ""; exact = false; pm = "";

        if (dateinfo != null && dateinfo != 'undefined') {
            if (dateinfo.y != null && dateinfo.y != 'undefined') {
                year = dateinfo.y.toString();
            }
            if (dateinfo.m != null && dateinfo.m != 'undefined') {
                month = dateinfo.m.toString();
            }
            if (dateinfo.d != null && dateinfo.d != 'undefined') {
                day = dateinfo.d.toString();
            }
        }

        this.SelectByValue(selMonth, month);
        this.SelectByValue(selDay, day);
        if ('undefined' != fieldYear && null != fieldYear) {
            fieldYear.value = year;
        }
    };

    this.GetDateFields = function (row) {
        var selMonth = this.GetEl(this.GetIDMonth(row));
        var selDay = this.GetEl(this.GetIDDay(row));
        var fieldYear = this.GetEl(this.GetIDYear(row));
        var month = selMonth ? selMonth.options[selMonth.selectedIndex].value : null;
        var day = selDay ? selDay.options[selDay.selectedIndex].value : null;
        var year = fieldYear ? fieldYear.value : null;

        if (!month && !day && !year) {
            return null;
        }
        return {
            m: month,
            d: day,
            y: year
        }
    };

    this.SetLocationFields = function (placeinfo, row) {
        var place = ""; var gpid = ""; var pinfo = ""; var sfexact = ""; var gpidLabel = ""; var gpidFilter = "";
        var fieldLocation = this.GetEl(this.GetIDLocation(row));
        var fieldGPID = this.GetEl(this.GetIDLocationGPID(row));
        var fieldPInfo = this.GetEl(this.GetIDLocationPInfo(row));

        if (placeinfo != null && placeinfo != 'undefined') {
            if (placeinfo.Place != null && placeinfo.Place != 'undefined') {
                place = placeinfo.Place;
            } else {
                try {
                    place = placeinfo;
                } catch (err) {

                }
            }
            if (placeinfo.GPID != null && placeinfo.GPID != 'undefined') {
                gpid = placeinfo.GPID;
            }
            if (placeinfo.PInfo != null && placeinfo.PInfo != 'undefined') {
                pinfo = placeinfo.PInfo;
            }
        }

        if ('undefined' != fieldLocation && null != fieldLocation) {
            fieldLocation.value = place;
        }
        if ('undefined' != fieldGPID && null != fieldGPID) {
            fieldGPID.value = gpid;
        }
        if ('undefined' != fieldPInfo && null != fieldPInfo) {
            fieldPInfo.value = pinfo;
        }
    };

    this.GetLocationFields = function (row) {

        var fieldLocation = this.GetEl(this.GetIDLocation(row));
        var fieldGPID = this.GetEl(this.GetIDLocationGPID(row));
        var fieldPInfo = this.GetEl(this.GetIDLocationPInfo(row));
        var place = fieldLocation ? fieldLocation.value : null;
        var gpid = fieldGPID ? fieldGPID.value : null;
        var pinfo = fieldPInfo ? fieldPInfo.value : null;

        if (!place && !gpid && !pinfo) {
            return null;
        }

        return {
            Place: place,
            GPID: gpid,
            PInfo: pinfo
        };
    };

    // Removes a row from the life event container
    this.RemoveRow = function (el) {
        var theTable = this.GetMainTable();
        var tRow = el.parentNode.parentNode.parentNode;
        var i = tRow.rowIndex;
        var rowid = tRow.getAttribute('rowid');
        var sel = this.GetEl(this.GetIDSelectEvent(rowid));
        var theEvent = sel.options[sel.selectedIndex].value;
        var theEventIndex = sel.getAttribute('oldEventIndex') || 0;
        if (theEvent) {
            this.UnclaimEventIndex(theEvent, theEventIndex);
        }

        theTable.deleteRow(i);
        this.RenumberControls();
        this.EventsSelected[theEvent]--;
        this.EnforceEvents();

        this.CurrentRow--;
        this.CheckLinkContainers();
        this.CheckNoMoreRows();
    };

    this.CheckLinkContainers = function () {
        var theTable = this.GetMainTable();
        var mainID = document.getElementById(this.UniqueID + '_lec_linkModule_wrapper');
        var linkID = document.getElementById(this.UniqueID + '_lec_linkModule');

        if (this.CurrentRow == 0) {
            // See if there is a link container control. If it is there, show it
            if (null != mainID && 'undefined' != mainID && null != linkID && 'undefined' != linkID) {
                mainID.style.display = 'none';
                linkID.style.display = 'block';
                // Add a default row
                this.AddRowNew();
            }
        } else {
            if (null != mainID && 'undefined' != mainID && null != linkID && 'undefined' != linkID) {
                mainID.style.display = 'block';
                linkID.style.display = 'none';
            }
        }
    };

    // Swaps an LEC row with a new one
    this.ReplaceRow = function (el) {
        var theTable = this.GetMainTable();
        var tRow = el.parentNode.parentNode.parentNode;
        var i = tRow.rowIndex;
        var rowid = tRow.getAttribute('rowid');
        var sel = this.GetEl(this.GetIDSelectEvent(rowid));
        var theEvent = sel.options[sel.selectedIndex].value;
    };

    // Completely resets the life event container
    this.Clear = function () {
        // For loop to allow for more dynamic and ignorant js.
        for (var i = 0; i < this.LifeEventCodes.length; i++) {
            this.EventsSelected[this.LifeEventCodes[i]] = 0;
            for (var j = 0; j < this.EventsIndexUsage[this.LifeEventCodes[i]].length; j++) {
                this.EventsIndexUsage[this.LifeEventCodes[i]][j] = false;
            }
        };

        this.CurrentRow = 0;

        var theTable = this.GetMainTable();
        var theRows = theTable.rows;

        // Removes all rows, except the very first heading row
        for (var i = theTable.rows.length - 1; i > 0; i--) {
            theTable.deleteRow(i);
        }
    };

    // When an event is changed or first added in a select event dropdown, this function happens. These must be done in the order here
    this.OptionChanged = function (sel, newRow) {

        var theRow = sel.parentNode.parentNode.parentNode;
        var rowid = theRow.getAttribute('rowid');

        if (typeof (newRow) == "undefined" || !newRow) {
            this.InsertNewRow(theRow, sel.options[sel.selectedIndex].value);
        }

        this.SetEventCounts(sel);
        this.EnforceEvents();

    };

    this.SetupPInfoElem = function (row) {
        var gHandle = "--" + row + "--";
        var elmID = this.UniqueID + "_locationgpid_" + gHandle;
        var curGpid = document.getElementById(this.UniqueID + "_locationgpid_" + gHandle).value;
        var curPinfo = document.getElementById(this.UniqueID + "_locationpinfo_" + gHandle).value;
        var curPinfoLength = curPinfo.length;
        curPinfoFirst = curPinfo.split("-", 1);
        curPinfoFirst = parseFloat(curPinfoFirst);
        curPinfoLast = curPinfo.substring(2, curPinfoLength);

        var curLevel = curPinfo.charAt(0);
        var curExactCB = document.getElementById(this.UniqueID + "_xcb");

        TGN.SM.SetupFilterUI(elmID, curPinfoFirst, curPinfoLast);
    }

    // Inserts a new template into a row
    this.InsertNewRow = function (theRow, eventType) {

        // Set the rowid of the current row
        var rowid = theRow.getAttribute('rowid');
        var year, defEventIndex = "";

        var oldEventType = this.GetEl(this.GetIDSelectEvent(rowid)).getAttribute('oldEvent');
        var oldEventIndex = this.GetEl(this.GetIDSelectEvent(rowid)).getAttribute('oldEventIndex') || defEventIndex;
        if (oldEventIndex == "0") {
            oldEventIndex = defEventIndex;
        }

        // Clear date hints if old event was for birth
        if (oldEventType == 'b') {
            TGN.SM.ClearDateHint(this.UniqueID);
        }

        // Create a new TD and get the new event
        var tdNew = document.createElement('td');
        var rowData = this.Templates[eventType];

        rowData = rowData.replace(/#CurrentRowNumber#/g, this.EncodeRowNumber(rowid));
        rowData = rowData.replace(/#EventIndex#/g, this.GetEventIndex(eventType));
        rowData = rowData.replace(/#LOCATIONZINDEX#/g, this.GetLocationColZindex(rowid).toString());
        rowData = this.GetMoreEventsLabel(rowData, rowid);

        // Append the row data
        tdNew.innerHTML = rowData;

        // Retrieves all of the form data from theRow
        var formData = this.GetFormData(theRow);

        // Remove the TD
        theRow.removeChild(theRow.firstChild);
        theRow.appendChild(tdNew);


        if (typeof TGN.SearchWidget.formVersion == 'undefined' || TGN.SearchWidget.formVersion < 3) {
            this.SetupOldEventIndex(rowid);
        }

        this.GetExactAllChecked(theRow);

        // Defines a function for retrieving form data that matches with the only difference being the event type.
        var getMatchingFormData = function (formElem) {
            if (formElem && formElem.name && formElem.name.substr(0, 2) == "ms" && formElem.name.length >= 5) {
                var isDigitAtFive = /^ms...\d.*/;

                // Following pattern: ["ms"][event][eventtype (meaning place or date)][component (meaning month, day, year, city, etc)][sometimes a number][extra stuff]
                var afterSearchKeyIdx = formElem.name.length > 5 && formElem.name.match(isDigitAtFive) ? 6 : 5;
                return formData["ms" + oldEventType + formElem.name.substr(3, 2) + oldEventIndex + formElem.name.substr(afterSearchKeyIdx)];
            }
            return null;
        };

        // Sets all of the form data on the new td
        this.CopyFormData(tdNew, getMatchingFormData);

        this.SetupPInfoElem(rowid);

        // Re-display date hints for birth event
        if (eventType == 'b') {
            year = this.GetEl(this.GetIDYear(rowid));

            if (year) {
                TGN.SM.DateHintListener(year, this.UniqueID);
            }
        }
    };

    this.GetExactAllChecked = function (source) {
        var searchPageID = this.UniqueID;
        var rowid = source.getAttribute('rowid');
        var exactCBAll = document.getElementById(searchPageID + "_xcb");
        var srcTags = source.getElementsByTagName("INPUT");
        for (var i = 0; i < srcTags.length; i++) {
            if (srcTags.type = "checkbox" && exactCBAll.checked == true) {
                srcTags[i].checked = true;
            } else {
                srcTags[i].checked = false;
            }
        }
    }

    this.GetFormData = function (source) {
        var sourceTag, formData = {};
        var sourceTags = source.getElementsByTagName("INPUT");
        for (i = 0, l = sourceTags.length; i < l; i++) {
            sourceTag = sourceTags[i];
            if (sourceTag.name) {
                if (sourceTag.type == "radio") {
                    if (sourceTag.checked) {
                        formData[sourceTag.name] = sourceTag.value;
                    }
                } else if (sourceTag.type == "checkbox") {
                    formData[sourceTag.name] = sourceTag.checked;
                } else {
                    formData[sourceTag.name] = sourceTag.value;
                }
            }
        }

        sourceTags = source.getElementsByTagName("SELECT");
        for (i = 0, l = sourceTag.length; i < l; i++) {
            sourceTag = sourceTags[i];
            if (sourceTag.name) {
                formData[sourceTag.name] = sourceTag.options[sourceTag.selectedIndex].value;
            }
        }

        return formData;
    };

    // This function is used for when rows are removed, to preserve form data, and renumber the row information
    this.CopyFormData = function (destination, getMatchingFormData) {
        var destTag, formData;
        var destTags = destination.getElementsByTagName("INPUT");
        for (i = 0, l = destTags.length; i < l; i++) {
            destTag = destTags[i];
            formData = getMatchingFormData(destTag);
            if (destTag.name && typeof formData != 'undefined') {
                if (destTag.type == "radio") {
                    if (destTag.value === formData) {
                        destTag.click();
                    }
                } else if (destTag.type == "checkbox") {
                    destTag.checked = formData;
                } else {
                    destTag.value = formData;
                }
            }
        }

        destTags = destination.getElementsByTagName("SELECT");
        for (i = 0, l = destTags.length; i < l; i++) {
            destTag = destTags[i];
            formData = getMatchingFormData(destTag);
            if (destTag.name && formData) {
                for (var optIdx = 0; optIdx < destTag.options.length; optIdx++) {
                    if (destTag.options[optIdx].value == formData) {
                        destTag.selectedIndex = optIdx;
                        break;
                    }
                }
            }
        }
    };

    ////////////////////////////////////////////
    // Person Picker
    ////////////////////////////////////////////

    this.PopulatePersonPicker = function (value) {
        var currentSet = this.CloneObject(this.EventsSelected);
        this.Clear();
        for (ndx in value) {
            this.AddRowNew(value[ndx].event, value[ndx].dateinfo, value[ndx].location);
        }

        // See if each event is now selected. If it is not, and is part of the current set, we need to add a blank row for it so the search template doesn't lose events.
        // For loop to allow for more dynamic and ignorant js.
        for (var i = 0; i < this.LifeEventCodes.length; i++) {
            this.PersonPickerEventCheck(this.LifeEventCodes[i], currentSet);
        };

        // Lastly, if the simple search form is being used and there is a 'life event container' link or 'family member container' link that has not been opened, open these up now.
        this.OpenUpContainerLinks();
    };

    // Opens up the life event and family member container links, if they exist
    this.OpenUpContainerLinks = function () {

        var el1 = this.GetEl(this.GetID('lec_linkModule'));
        var el2 = this.GetEl(this.GetID('fmc_linkModule'));
        var divLEC = this.GetEl(this.GetID('lec_linkModule_wrapper'));
        var divFMC = this.GetEl(this.GetID('fmc_linkModule_wrapper'));

        if (null != el1 && 'undefined' != el1 && el1.style.display != 'none') {
            TGN.Ancestry.Search.LinkModule.ClickLink(this.GetID('lec_linkModule'), this.GetID('lec_linkModule_wrapper'), this.GetID('lec_hiddenparameter'));
            el1.style.display = 'none';
            el1.setAttribute('class', '');
            el1.className = '';
        }

        if (null != el2 && 'undefined' != el2 && el2.style.display != 'none') {
            TGN.Ancestry.Search.LinkModule.ClickLink(this.GetID('fmc_linkModule'), this.GetID('fmc_linkModule_wrapper'), this.GetID('fmc_hiddenparameter'));
            el2.style.display = 'none';
            el2.setAttribute('class', '');
            el2.className = '';
        }

        // Lastly, change the advtog class on the LEC and FMC to not be there
        if (null != divLEC && 'undefined' != divLEC) {
            divLEC.setAttribute('class', '');
            divLEC.className = '';
        }
        if (null != divFMC && 'undefined' != divFMC) {
            divFMC.setAttribute('class', '');
            divFMC.className = '';
        }
    };

    this.PersonPickerEventCheck = function (evt, currentSet) {
        var value = currentSet[evt];
        if ('undefined' != value && null != value) {
            // This event is in the current set. Has it been added?
            var nextValue = this.EventsSelected[evt];
            if ('undefined' != nextValue && null != nextValue) {
                // If the event has not been selected and this isn't the global form and the event is allowed, add it
                if (nextValue < 1 && this.PageType != 'Global' && this.EventsMaximum[evt] > 0) {
                    this.AddRowNew(evt);
                }
            }
        }
    };

    this.CloneObject = function (obj) {
        var clone = {};
        for (var i in obj) {
            if (typeof (obj[i]) == "object")
                clone[i] = cloneObject(obj[i]);
            else
                clone[i] = obj[i];
        }
        return clone;
    };

    ////////////////////////////////////////////
    // Functions to renumber controls
    ////////////////////////////////////////////

    // The purpose of this function is to set new id's for the html controls in a row
    this.SetControlIDsRow = function (rowNumber, newNumber) {
        var sel = this.GetEl(this.GetIDSelectEvent(rowNumber));
        var type = sel.options[sel.selectedIndex].value;

        if (null == newNumber || 'undefined' == newNumber) {
            newNumber = rowNumber;
        } else {
            newNumber = newNumber.toString();
        }

        sel.setAttribute('oldEvent', type);

        var theRow = sel.parentNode.parentNode.parentNode;

        var fieldDay = this.GetEl(this.GetIDDay(rowNumber));
        var fieldMonth = this.GetEl(this.GetIDMonth(rowNumber));
        var fieldYear = this.GetEl(this.GetIDYear(rowNumber));
        var fieldPM = this.GetEl(this.GetIDPlusMinus(rowNumber));
        var fieldExact = this.GetEl(this.GetIDExactOnly(rowNumber));
        var fieldLocation = this.GetEl(this.GetIDLocation(rowNumber));
        var fieldGPID = this.GetEl(this.GetIDLocationGPID(rowNumber));
        var fieldPInfo = this.GetEl(this.GetIDLocationPInfo(rowNumber));
        var fieldRemoveLink = this.GetEl(this.GetIDRemoveLink(rowNumber));
        var fieldRemoveLinkA = this.GetEl(this.GetIDRemoveLinkA(rowNumber));
        var fieldLabelText = this.GetEl(this.GetIDLabelEvent(rowNumber));
        var fieldLocCol = this.GetEl(this.GetIDLocationColumn(rowNumber));
        var fieldLoc = this.GetEl(this.GetIDLocation(rowNumber));
        var fieldAutoComplete = this.GetEl(this.GetIDAutoComplete(rowNumber));
        var fieldACContainer = this.GetEl(this.GetIDACContainer(rowNumber));

        // Change the rowid
        this.SetID(theRow, "row_" + this.EncodeRowNumber(newNumber));
        theRow.setAttribute('rowid', newNumber);

        // Set the id's for the rest of the controls that are available
        this.SetID(sel, this.GetIDSelectEvent(newNumber));
        this.SetID(fieldDay, this.GetIDDay(newNumber));
        this.SetID(fieldMonth, this.GetIDMonth(newNumber));
        this.SetID(fieldYear, this.GetIDYear(newNumber));
        this.SetID(fieldPM, this.GetIDPlusMinus(newNumber));
        this.SetID(fieldExact, this.GetIDExactOnly(newNumber));
        this.SetID(fieldLocation, this.GetIDLocation(newNumber));
        this.SetID(fieldGPID, this.GetIDLocationGPID(newNumber));
        this.SetID(fieldPInfo, this.GetIDLocationPInfo(newNumber));
        this.SetID(fieldRemoveLink, this.GetIDRemoveLink(newNumber));
        this.SetID(fieldRemoveLinkA, this.GetIDRemoveLinkA(newNumber));
        this.SetID(fieldLabelText, this.GetIDLabelEvent(newNumber));
        this.SetID(fieldLocCol, this.GetIDLocationColumn(newNumber));
        this.SetID(fieldAutoComplete, this.GetIDAutoComplete(newNumber));
        this.SetID(fieldACContainer, this.GetIDACContainer(newNumber));

        var fieldDataStr = '{ ';
        var delimiter = ',';
        var qu = '\"'; // This is to escape the string values in the string JSON, so that JSON.parse works

        if (fieldYear != null && typeof fieldYear != 'undefined') {
            fieldDataStr += (qu + fieldYear.id + qu + ':' + qu + fieldYear.value + qu) + delimiter;
        }

        if (fieldExact != null && typeof fieldExact != 'undefined') {
            fieldDataStr += (qu + fieldExact.id + qu + ':' + fieldExact.checked) + delimiter;
        }

        if (fieldPM != null && typeof fieldPM != 'undefined') {
            fieldDataStr += (qu + fieldPM.id + qu + ':' + qu + fieldPM.value + qu) + delimiter;
        }

        if (fieldLoc != null && typeof fieldLoc != 'undefined') {
            fieldDataStr += (qu + fieldLoc.id + qu + ':' + qu + fieldLoc.value + qu);
        }

        fieldDataStr += ' }';

        var fieldData = {};

        try {
            fieldData = JSON.parse(fieldDataStr);
        } catch (err) {

        }

        this.ChangeSearchFormIDs(theRow, rowNumber, newNumber, fieldData);
        this.FixUpLocationZindex(fieldLocCol, this.GetLocationColZindex(newNumber));
        this.ShowAndHideEventLabelAndSelectDisplay(fieldLabelText, sel);

        return "";
    };

    this.ChangeSearchFormIDs = function (row, oldRowNum, newRowNum, fieldData) {
        if (typeof row == 'undefined' || row == null) {
            return;
        }

        var newTd = document.createElement("td");
        var oldTd = row.firstChild;
        var oldTdInnerHTML = oldTd.innerHTML;
        var encodedOldRowNum = this.EncodeRowNumber(oldRowNum);
        var encodedNewRowNum = this.EncodeRowNumber(newRowNum);
        var newTdInnerHTML = oldTdInnerHTML.replace(/--\d+--/g, encodedNewRowNum);

        newTd.innerHTML = newTdInnerHTML;
        var oldSelect = oldTd.getElementsByTagName("select")[0].options[oldTd.getElementsByTagName("select")[0].selectedIndex];
        var newSelect = newTd.getElementsByTagName("select")[0].options[newTd.getElementsByTagName("select")[0].selectedIndex];
        var oldRadioFilter = oldTd.getElementsByTagName("input");
        var checkedObject = null;
        for (var i = 0; i < oldRadioFilter.length; i++) {
            if (oldRadioFilter[i].type == "radio") {
                if (oldRadioFilter[i].checked == true) {
                    checkedObject = { idx: i, checked: oldRadioFilter[i].checked };
                    break;
                }
            }
        }

        row.removeChild(oldTd);
        row.appendChild(newTd);

        var newRadioFilter = row.firstChild.getElementsByTagName("input");
        if (checkedObject) {
            newRadioFilter[checkedObject.idx].checked = checkedObject.checked;
        }

        //Setting old value and selected attribute to the new, as the regExp above buged out these attributes
        if (oldSelect != newSelect) {
            oldSelect.setAttribute("selected", "selected");
            newSelect.setAttribute("selected", "selected");

            newSelect.setAttribute("value", oldSelect.value);
        }

        // oldTdInnerHTML is snapshot of original state of all controls, not of the latest state of them, so used latest values for controls passed in via fieldData...
        if (fieldData != null && typeof fieldData != 'undefined') {

            var fieldYear = this.GetEl(this.GetIDYear(newRowNum));
            var fieldExact = this.GetEl(this.GetIDExactOnly(newRowNum));
            var fieldPM = this.GetEl(this.GetIDPlusMinus(newRowNum));
            var fieldLocation = this.GetEl(this.GetIDLocation(newRowNum));

            if (fieldYear != null && typeof fieldYear != 'undefined' && typeof fieldData[fieldYear.id] != 'undefined') {
                fieldYear.value = fieldData[fieldYear.id];
            }

            if (fieldExact != null && typeof fieldExact != 'undefined' && typeof fieldData[fieldExact.id] != 'undefined') {
                fieldExact.checked = fieldData[fieldExact.id];
            }

            if (fieldPM != null && typeof fieldPM != 'undefined' && typeof fieldData[fieldPM.id] != 'undefined') {
                this.SelectByValue(fieldPM, fieldData[fieldPM.id]);
            }

            if (fieldLocation != null && typeof fieldLocation != 'undefined' && typeof fieldData[fieldLocation.id] != 'undefined') {
                fieldLocation.value = fieldData[fieldLocation.id];
            }
        }
    };

    this.ShowAndHideEventLabelAndSelectDisplay = function (fieldLabelText, sel) {
        if (typeof fieldLabelText == 'undefined' || fieldLabelText == null) {
            return;
        }
        if (typeof sel == 'undefined' || sel == null) {
            return;
        }

        // If the dropdown only has one value, swap to show the label only
        var theAttribute = fieldLabelText.getAttribute('class');
        if ('undefined' == typeof theAttribute || null == theAttribute) {
            theAttribute = fieldLabelText.className;
        }
        if (theAttribute.indexOf('lecPermanent') == -1) {
            if (sel.options.length < 2) {
                sel.style.display = 'none';
                fieldLabelText.style.display = '';
            } else {
                sel.style.display = '';
                fieldLabelText.style.display = 'none';
            }
        }
    };

    this.FixUpLocationZindex = function (locColDiv, newZindexNum) {
        if (typeof locColDiv != 'undefined' && locColDiv != null) {
            document.getElementById(locColDiv.id).style.zIndex = newZindexNum;
        }
    };

    this.GetLocationColZindex = function (locRowNum) {
        var zindex = 98;

        if (typeof locRowNum != 'undefined' && locRowNum != null) {
            zindex = (zindex - locRowNum);
        }

        return zindex;
    };

    // LEC:Loops through each row and re-does the id's. This is so the id's are always in the right order from removing/adding rows.
    this.RenumberControls = function () {
        var theTable = this.GetMainTable();
        for (var i = 0; i < (theTable.rows.length); i++) {
            // Loop through each row and run the id renumbering (skip the heading row)
            if (i > 0) {
                try {
                    var theRow = theTable.rows[i];
                    this.SetControlIDsRow(theRow.getAttribute('rowid'), i - 1);
                    if (i == 3) {
                        if (this.DoMoreEventsLabel) {
                            // Global form 3rd row should show 'More Events' label above the first dropdown
                            var theLabel = theRow.childNodes[0].childNodes[0].childNodes[0];
                            if (null != theLabel && 'undefined' != theLabel) {
                                theLabel.className = "lecLabel moreEvents";
                                theLabel.innerHTML = this.Resources.CaptionMoreEvents;
                            }
                        }
                    }
                }
                catch (err) {
                }
            }
        }
    };

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Functions to handle which events should be showing up in the dropdown lists, and which can be added in non global pages
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    this.GetEventAvailability = function (eventtype) {
        var rv = true;
        if ('undefined' == typeof this.EventsMaximum) {
            rv = false;
        } else if ('undefined' == typeof this.EventsMaximum[eventtype]) {
            rv = false;
        } else {
            rv = (this.EventsMaximum[eventtype] > 0);
        }

        return rv;
    };

    this.EnforceEvents = function () {
        var theOption;
        var theTable = this.GetMainTable();
        var theRowsLength = theTable.rows.length;
        var isMaxed, isNotAllowed, code;
        // Loop through each row
        for (var j = 0; j < (theRowsLength); j++) {
            if (j > 0) {
                var theRow = document.getElementById('row_' + this.EncodeRowNumber((j - 1)));

                if (theRow != null) {
                    var theID = theRow.getAttribute('rowid');
                    var theSel = this.GetEl(this.GetIDSelectEvent(theID));
                    var evt = theSel.options[theSel.selectedIndex].value;
                    var theIndex = theSel.selectedIndex;

                    if (theSel.style.display == 'none') {
                        continue;
                    }
                    // For loop to allow for more dynamic and ignorant js.
                    for (var i = 0; i < this.LifeEventCodes.length; i++) {
                        code = this.LifeEventCodes[i];
                        if (code == this.DefaultEvent) { continue; }

                        isMaxed = (this.EventsSelected[code] >= this.EventsMaximum[code]);
                        isNotAllowed = (!this.IsEventAllowed(code))
                        if ((isMaxed && evt != code) || isNotAllowed) {
                            this.RemoveSelectOptionByValue(theSel, code);
                        }
                        else {
                            // Check to see if it needs to go back in
                            if (!this.DoesSelectHaveValue(theSel, code) && !isNotAllowed) {
                                theOption = new Option(this.Resources.SelectOptionText[code], code, false, false);
                                theSel.options[theSel.length] = theOption;
                                this.SortSelect(theSel);
                            }
                        }
                    }
                }
            }
        }
    };

    this.SelectByValue = function (sel, value) {
        if ('undefined' != typeof sel && null != sel) {
            for (var i = 0; i < sel.length; i++) {
                var theOption = sel.options[i];
                if (theOption.value == value) {
                    sel.options[i].selected = true;
                }
            }
        }
    };

    this.RemoveSelectOptionByValue = function (sel, value) {
        if ('undefined' != typeof sel && null != sel) {
            for (var i = 0; i < sel.length; i++) {
                var theOption = sel.options[i];
                if (theOption.value == value) {
                    sel.remove(i);
                }
            }
        }
    };

    this.SortSelect = function (sel) {
        var optionsDone = false;
        var currentOptions = 0;
        var countOptions = 0;
        var arrayOptions = [];
        var selectedIndex = sel.selectedIndex;
        var selectedValue = sel.options[selectedIndex].value;
        var code;
        // For loop to allow for more dynamic and ignorant js.
        for (var i = 0; i < this.LifeEventCodeSortOrder.length; i++) {
            code = this.LifeEventCodeSortOrder[i];
            if (this.DoesSelectHaveValue(sel, code)) {
                arrayOptions.push(new Option(this.Resources.SelectOptionText[code], code, false, false));
            }
        };

        // Remove all options from the select
        sel.length = 0;

        // Add events in, now in order
        for (var i = 0; i < arrayOptions.length; i++) {
            sel.options[sel.length] = arrayOptions[i];
        }

        // Set the selected value
        this.SelectByValue(sel, selectedValue);

    };

    // Checks the select drop down new event attribute and increments the count for that event
    this.SetEventCounts = function (sel) {

        var oldEvent = sel.getAttribute('oldEvent');
        var newEvent = sel.options[sel.selectedIndex].value;

        // We don't need to do anything if this is the same item.
        if (newEvent == oldEvent) { return; }

        var oldEventIndex = sel.getAttribute('oldEventIndex') || 0;
        this.UnclaimEventIndex(oldEvent, oldEventIndex);
        var newEventIndex = this.GetNextAvailableEventIndex(newEvent);
        this.ClaimEventIndex(newEvent, newEventIndex);

        sel.setAttribute('oldEvent', newEvent);
        sel.setAttribute('oldEventIndex', newEventIndex || "");


        if (typeof this.EventsSelected[oldEvent] == 'undefined') {
            this.EventsSelected[oldEvent] = 0;
        }

        if (typeof this.EventsSelected[newEvent] == 'undefined') {
            this.EventsSelected[newEvent] = 0;
        }

        this.EventsSelected[oldEvent]--;
        this.EventsSelected[newEvent]++;
    };

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Functions to return the name/id that the html controls in the life event container should use
    ///////////////////////////////////////////////////////////////////////////////////////////////

    // Gets the idea for the select event dropdown
    this.GetIDSelectEvent = function (row) {
        row = this.GetRowNumber(row);
        var rv = "selevent_" + row;
        rv = this.GetID(rv);
        return rv;
    };

    // Creates the field ID for a plus minus field for a year
    this.GetIDPlusMinus = function (row) {
        row = this.GetRowNumber(row);
        var rv = "pm_" + row;
        rv = this.GetID(rv);
        return rv;
    };

    // Creates the field ID for a year field
    this.GetIDYear = function (row) {
        row = this.GetRowNumber(row);
        var rv = "year_" + row;
        rv = this.GetID(rv);
        return rv;
    };

    // Creates the field ID for a month field
    this.GetIDMonth = function (row) {
        row = this.GetRowNumber(row);
        var rv = "month_" + row;
        rv = this.GetID(rv);
        return rv;
    };

    // Creates the field ID for a day field
    this.GetIDDay = function (row) {
        row = this.GetRowNumber(row);
        var rv = "day_" + row;
        rv = this.GetID(rv);
        return rv;
    };

    // Creates the field ID for the exact only checkbox
    this.GetIDExactOnly = function (row) {
        row = this.GetRowNumber(row);
        var rv = "exactyear_" + row;
        rv = this.GetID(rv);
        return rv;
    };

    // Creates the field ID for a location field
    this.GetIDLocation = function (row) {
        row = this.GetRowNumber(row);
        var rv = "location_" + row;
        rv = this.GetID(rv);
        return rv;
    };

    // Creates the field ID for Place type ahead GPID (hidden field)
    this.GetIDLocationGPID = function (row) {
        row = this.GetRowNumber(row);
        var rv = "locationgpid_" + row;
        rv = this.GetID(rv);
        return rv;
    };

    // Creates the field ID for Place type ahead PInfo (hidden field)
    this.GetIDLocationPInfo = function (row) {
        row = this.GetRowNumber(row);
        var rv = "locationpinfo_" + row;
        rv = this.GetID(rv);
        return rv;
    };

    // Creates the field ID for Place type ahead GPID (hidden field)
    this.GetIDLocationSFExact = function (row) {
        row = this.GetRowNumber(row);
        var rv = "locationftp_" + row;
        rv = this.GetID(rv);
        return rv;
    };

    this.GetIDLocationGPIDLabel = function (row) {
        row = this.GetRowNumber(row);
        var rv = "locationgpid_" + row + "_DDLabel";
        rv = this.GetID(rv);
        return rv;
    };

    this.GetIDLocationGPIDFilter = function (row) {
        row = this.GetRowNumber(row);
        var rv = "locationgpid_" + row + "_Filter";
        rv = this.GetID(rv);
        return rv;
    };

    // Creates the field ID for the remove link div
    this.GetIDRemoveLink = function (row) {
        row = this.GetRowNumber(row);
        var rv = "rlink_" + row;
        rv = this.GetID(rv);
        return rv;
    };

    // Creates the field ID for the remove link A tag
    this.GetIDRemoveLinkA = function (row) {
        row = this.GetRowNumber(row);
        var rv = "rlinka_" + row;
        rv = this.GetID(rv);
        return rv;
    };

    // Gets the value for the default place filter option
    this.GetIDDefaultPlaceFilter = function (row) {
        row = this.GetRowNumber(row);
        var rv = "locationgpid_" + row + "_defRadio";
        rv = this.GetID(rv);
        return rv;
    };

    // Gets the value for the exact only place filter option
    this.GetIDExactPlaceFilter = function (row) {
        row = this.GetRowNumber(row);
        var rv = "locationgpid_" + row + "_XO_input";
        rv = this.GetID(rv);
        return rv;
    };

    // Gets the id for the event label.
    this.GetIDLabelEvent = function (row) {
        row = this.GetRowNumber(row);
        var rv = "labelevent_" + row;
        rv = this.GetID(rv);
        return rv;
    };

    // Gets the id for the event label.
    this.GetIDLocationColumn = function (row) {
        row = this.GetRowNumber(row);
        var rv = "locationcol_" + row;
        rv = this.GetID(rv);
        return rv;
    };

    // Gets the id for the main auto complete div
    this.GetIDAutoComplete = function (row) {
        row = this.GetRowNumber(row);
        var rv = "location_" + row + "_AutoComplete";
        rv = this.GetID(rv);
        return rv;
    };

    // Gets the id for the AC Container field for auto complete
    this.GetIDACContainer = function (row) {
        row = this.GetRowNumber(row);
        var rv = "location_" + row + "_ACContainer";
        rv = this.GetID(rv);
        return rv;
    };

    //////////////////////
    // Helper Functions //
    //////////////////////

    // Helper Function
    this.ShouldAbortAddRow = function (eventtype, dateinfo, placeinfo) {
        var abort = false;

        if (eventtype != this.DefaultEvent && this.EventsSelected[eventtype] >= this.EventsMaximum[eventtype]) {
            abort = true;
        }

        // Set fname and lname
        if (null == dateinfo || 'undefined' == dateinfo) { dateinfo = ''; }
        if (null == placeinfo || 'undefined' == placeinfo) { placeinfo = ''; }

        // If the maximum rows are currently showing, abort this as well
        if (this.MaximumReached()) {
            abort = true;
        }

        // Check to see if the relationship is allowed to be added
        if (!this.IsEventAllowed(eventtype)) {
            abort = true;
        }

        return abort;
    };

    // Helper Function
    this.MaximumReached = function () {
        if (this.CurrentRow == this.GetMaxAllowedRows()) {
            return true;
        }

        return false;
    };

    // Helper Function
    this.IsEventAllowed = function (evt) {

        if (null == evt || 'undefined' == evt || evt == "" || evt == "0" || evt == "y") { return true; }

        if (this.GetEventAvailability(evt) != 0) {
            return true;
        }

        return false;
    };

    // Helper Function
    // This used to have RenumberControls called, but I took it out as it was causing bugs. The calls were made after each divAdd.style.display call
    this.CheckNoMoreRows = function () {
        if (this.PageType == "Global" || this.PageType == "Special") {
            var divAdd = this.GetEl(this.GetID('lecAddLink'));
            if (this.CurrentRow >= this.GetMaxAllowedRows()) {
                divAdd.style.display = 'none';
            } else {
                divAdd.style.display = '';
            }
        }
    };

    // Helper Function
    this.GetMaxAllowedRows = function () {
        var theMax = 0;
        var code;
        // For loop to allow for more dynamic and ignorant js
        for (var i = 0; i < this.LifeEventCodes.length; i++) {
            code = this.LifeEventCodes[i];
            if ((this.PageType != 'Global' || code != this.DefaultEvent) && typeof this.EventsMaximum[code] != 'undefined' && this.EventsMaximum[code]) {
                theMax += this.EventsMaximum[code];
            }
        };

        if (this.PageType == 'Global') {
            theMax += 1; // Global handle the extra any event
        }

        return theMax;
    };

    // Helper Function
    this.GetSetting = function (setting, initObj) {
        if (null != initObj[setting] && 'undefined' != initObj[setting]) {
            return initObj[setting];
        }
        else {
            return this[setting]; // default
        }
    };

    // Helper Function
    this.GetMainTable = function () {
        return this.GetEl(this.GetID('lecTable'));
    };

    // Helper Function - may not even need it
    this.CheckHideEverything = function () {
        if (1 == 2) {
            var el = this.GetEl(this.GetID('LEC'));
            el.style.display = 'none';
        }
    };

    // Helper Function
    this.CheckRemoveFeatures = function () {
        if (this.PageType != 'Global') {
            var divAdd = this.GetEl(this.GetID('lecAddLink'));
            // TODO: See if the add event link should be removed. If no rows can be added upon page load, then it should be hidden.
            // divAdd.style.display = 'none'; // Removes the 'add event' link at the bottom
        }
    };

    // Helper Function
    this.SetName = function (ctrl, name) {
        if (null != ctrl && 'undefined' != ctrl) {
            ctrl.name = name;
        }
    };

    // Helper Function
    this.SetID = function (ctrl, id) {
        if (null != ctrl && 'undefined' != ctrl) {
            ctrl.id = id;
        }
    };

    // Helper Function
    this.GetID = function (id) {
        return this.UniqueID + '_' + id;
    };

    // Helper Function	
    this.GetEl = function (id) {
        return document.getElementById(id);
    };

    // Helper Function
    this.GetRowNumber = function (row) {
        var rowIdentifier = this.EncodeRowNumber(0);
        if (null != row && 'undefined' != row) {
            rowIdentifier = this.EncodeRowNumber(row);
        }
        return rowIdentifier;
    };

    this.EncodeRowNumber = function (row) {
        return '--' + row + '--';
    };

    // Helper Function
    this.DoesSelectHaveValue = function (sel, desiredValue) {
        for (var i = 0; i < sel.length; i++) {
            var theOption = sel.options[i];
            if (theOption.value == desiredValue) {
                return true;
            }
        }
        return false;
    };

    // Helper Function
    this.GetRemoveLinkState = function (eventtype) {
        var state = "";
        if (this.PageType != "Global") {
            state = 0;
        } else {
            try {
                state = this.AvailableFields[eventtype].r;
            } catch (err) {
                state = 1;
            }
        }
        return state;
    };

    this.GetEventIndex = function (eventtype) {
        var rv = "", nextAvailableEventIndex = this.GetNextAvailableEventIndex(eventtype);
        rv = (nextAvailableEventIndex == 0 ? "" : nextAvailableEventIndex);
        return rv;
    };

    // Helper Function
    this.ShowHideRemove = function (sel) {
        if (this.PageType == 'Global') {
            var rowid = sel.parentNode.parentNode.parentNode.getAttribute('rowid');
            var eventtype = sel.options[sel.selectedIndex].value;
            var theLink = this.GetEl(this.GetIDRemoveLink(rowid));
            if (null != theLink && 'undefined' != theLink) {
                var state = this.GetRemoveLinkState(eventtype);
                if (state == 0) {
                    theLink.style.display = 'none';
                } else {
                    theLink.style.display = '';
                }
            }
        }
    };

    // Tries to find a blank row that already exists for the given event code.
    // If one is found, then the date and place info is set.
    // If one is not found, then a new row is added with the date and place info.
    // If maximums have been reached for the event code or if for whatever reason
    // a row could not be added, then nothing happens.
    this.SetRow = function (eventCode, dateInfo, placeInfo) {
        var foundAndSet = false;
        var theTable = this.GetMainTable();
        var theRowsLength = theTable.rows.length;
        var curDateInfo, curPlaceInfo, theID, theSel, evt, theRow;

        // Loop through each row
        for (var i = 0; i < (theRowsLength); i++) {
            if (i > 0) {
                theRow = document.getElementById('row_' + this.EncodeRowNumber((i - 1)));

                if (theRow != null) {
                    theID = theRow.getAttribute('rowid');
                    theSel = this.GetEl(this.GetIDSelectEvent(theID));
                    evt = theSel.options[theSel.selectedIndex].value;
                    if (evt == eventCode) {
                        curDateInfo = this.GetDateFields(theID);
                        curPlaceInfo = this.GetLocationFields(theID);

                        if (!curDateInfo && !curPlaceInfo) {
                            this.SetDateFields(dateInfo, theID);
                            this.SetLocationFields(placeInfo, theID);
                            foundAndSet = true;
                            break;
                        }
                    }
                }
            }
        }

        if (!foundAndSet) {
            this.AddRowNew(eventCode, dateInfo, placeInfo);
        }
    };

    this.IsLeapYear = function (theYear) {
        if ('undefined' == theYear || null == theYear) {
            theYear = 0;
        }
        var isLeap = (new Date(theYear, 1, 29).getDate() == 29);
        return isLeap;
    };
};
/***************************************/
/* END LifeEventContainer              */
/***************************************/

/***************************************/
/* BEG Estimated Birth Year Calculator */
/***************************************/

TGN.Ancestry.Search.DateCalculator.SetEstimatedBirthYear = function (formID, ebyAgeYearId, ebyAgeNumId, ebyInputId, ebyErrorDivId, calcEBYId) {
    var age = Number(document.getElementById('ebyAgeNum').value), year = Number(document.getElementById('ebyAgeYear').value);
    if ((!isNaN(age) && age > 0) && (!isNaN(year) && year > age && year > 99) && (!isNaN(age) && age < 121)) {
        document.getElementById(ebyInputId).value = Number(year - age);
        document.getElementById(ebyErrorDivId).style.display = 'none';
        document.getElementById(calcEBYId).style.display = 'none';
    }
    else {
        document.getElementById(ebyErrorDivId).style.display = 'block';
    }
};

TGN.Ancestry.Search.DateCalculator.AgeOnKeyUp = function () {
    if (null == event && 'undefined' == event) { return; }
    if (event.keyCode != 39 && event.keyCode != 37) {
        var val = Number(document.getElementById('ebyAgeNum').value.replace(/[^\d]/g, ''));
        if (val == 0) val = '';
        if(document.getElementById('ebyAgeNum').value != val)
            document.getElementById('ebyAgeNum').value = val;
    }
};

TGN.Ancestry.Search.DateCalculator.YearOnKeyUp = function () {
    if (null == event && 'undefined' == event) { return; }
    if (event.keyCode != 39 && event.keyCode != 37) {
        var val = Number(document.getElementById('ebyAgeYear').value.replace(/[^\d]/g, ''));
        if (val == 0) val = '';
        if(document.getElementById('ebyAgeYear').value != val)
            document.getElementById('ebyAgeYear').value = val;
    }
};

TGN.Ancestry.Search.DateCalculator.OnKeyDown = function (e) {
    var key;
    if (window.event) {
        key = e.keyCode;
    } else if (e.which) {
        key = e.which;
    }
    return (key != 13);
};

TGN.Ancestry.Search.DateCalculator.Open = function () {
    var divMain = document.getElementById('calcEBY');
    var iframeEby = document.getElementById('calcEBYiFrame');
    if (divMain.style.display != 'block') {
        divMain.style.display = 'block';
        iframeEby.style.display = 'block';
        iframeEby.style.width = divMain.style.width; iframeEby.style.height = divMain.style.height;
    } else {
        divMain.style.display = 'none';
        iframeEby.style.display = 'none';
        document.getElementById('ebyError').style.display = 'none';
    }
    var divAge = document.getElementById('ebyAgeNum');
    if (divAge.style.display != 'none') {
        divAge.focus();
    }
};

TGN.Ancestry.Search.DateCalculator.Close = function (focusTarget) {
    var divMain = document.getElementById('calcEBY');
    var divError = document.getElementById('ebyError');
    var iframeEby = document.getElementById('calcEBYiFrame');

    iframeEby.style.display = 'none';
    divMain.style.display = 'none';
    divError.style.display = 'none';

    if (focusTarget != null && typeof focusTarget != 'undefined') {
        var targetEl = document.getElementById(focusTarget);

        if (targetEl.style.display != 'none') {
            targetEl.focus();
        }
    }
};

TGN.Ancestry.Search.DateCalculator.OnMouseOut = function (el, event, focusTarget) {
    if (event.type == 'mouseout') {
        var reltg = event.relatedTarget ? event.relatedTarget : event.toElement;
        while (reltg && reltg != el) {
            reltg = reltg.parentNode;
        }
        if (reltg != el) {
            TGN.Ancestry.Search.DateCalculator.Close(focusTarget);
        }
    }
};

TGN.Ancestry.Search.DateCalculator.CloseDialogCheck = function () {
    var it = 0;
};

/***************************************/
/* END Estimated Birth Year Calculator */
/***************************************/

/***************************************/
/* BEG Link Module Code                */
/***************************************/

TGN.Ancestry.Search.LinkModule.ClickLink = function (linkID, moduleID, hiddenID) {
    var divLink = document.getElementById(linkID);
    var divModule = document.getElementById(moduleID);
    var divHidden = document.getElementById(hiddenID);
    divLink.style.display = 'none';
    divModule.style.display = 'block';
    divHidden.value = "1";
    divLink.className = divLink.className.replace(/(advtog|advYes|advNo)/ig, '');
    divModule.className = divModule.className.replace(/(advtog|advYes|advNo)/ig, '');
};

/***************************************/
/* END Link Module Code                */
/***************************************/

/***************************************/
/* BEG Simple Search Form              */
/***************************************/

// Takes the value from the estimated birth year field and moves it to a birth year field for the Life Event Container
TGN.Ancestry.Search.SimpleSearch.MoveBirthYear = function (uniqueID, estYearField) {
    var yearValue = document.getElementById(estYearField).value;
    if (!yearValue) {
        return;
    }
    
    // Call the LEC with the uniqueID and set the year
    var LEC = TGN.SM.InstContainer[uniqueID + '_search-form'].LEC;
    if (LEC) {
        LEC.SetRow('b', { y: yearValue }, null);
    }
};

// Takes the value from the estimated birth year field and moves it to a birth year field for the Life Event Container
TGN.Ancestry.Search.SimpleSearch.MoveSelfPlace = function (uniqueID, placeId, gpidId, pinfoId) {
    var placeValue = document.getElementById(placeId);
    if (!placeValue) {
        return;
    }
    if (YAHOO.lang.trim(placeValue.value) == "") {
        return;
    }
    // Call the LEC with the uniqueID and set the year
    var LEC = TGN.SM.InstContainer[uniqueID + '_search-form'].LEC;
    if (LEC) {
        var gpidValue = document.getElementById(gpidId);
        var pinfoValue = document.getElementById(pinfoId);

        LEC.SetRow('y', null, {
            Place: placeValue.value,
            GPID: gpidValue ? gpidValue.value : null,
            PInfo: pinfoValue ? pinfoValue.value : null
        });

        placeValue.value = "";
        gpidValue.value = "";
        pinfoValue.value = "";
    }
};

/***************************************/
/* END Simple Search Form              */
/***************************************/

/***************************************/
/* BEG Helpers                         */
/***************************************/

// Hacked pause function
TGN.Ancestry.Search.Pause = function(millis) 
{
    var date = new Date();
    var curDate = null;
    do { curDate = new Date(); } 
    while(curDate-date < millis);
};

/***************************************/
/* END Helpers                         */
/***************************************/

