YAHOO.namespace("com.papertrail");

//Make XML entities of these characters:  <, >, ', ", &
//Note:  This outputs literal "&lt;" instead of "<".  I never did figure out why that is.
function XMLEscape(str){
    var retval = str;
    for(var x in XMLEscapeSequences){
        retval = retval.replace(x, XMLEscapeSequences[x]);
    }
    return retval;
}

var XMLEscapeSequences = {
    "<":"&lt;",
    ">":"&gt;",
    //"'":"&apos;",
    "\"":"&quot;",
    "&":"&amp;"
};

//This prevents the possible XSS attack of sending a user a link to the site that contains malicious HTML - right now, just checking for script tags.
function CleanOutputOfScript(str){
    var retval = str;
    for(var x in OutputCleaningRegexen){
        retval = retval.replace(OutputCleaningRegexen[x], "");
    }
    return retval;
}
var OutputCleaningRegexen = {
    "script":/<script[^>]*>/ig
};


YAHOO.util.Event.onDOMReady(function(){
    if(typeof console == typeof junkthatdoesNOTexist){
        //Add logger window for IE.
        (function(){
            var logcontainer = document.createElement("div");
            logcontainer.style.position = "absolute";
            document.getElementsByTagName("body")[0].appendChild(logcontainer);
            logcontainer.style.top = "0";
            logcontainer.style.right = "0";
            YAHOO.util.Dom.addClass(logcontainer, "yui-skin-sam");
            
            var logdiv = document.createElement("div");
            logcontainer.appendChild(logdiv);
            
            var myLogReader = new YAHOO.widget.LogReader(logdiv);
            
        });//();
    } else {
        //Firebug logging
        YAHOO.widget.Logger.enableBrowserConsole();
    }

    YAHOO.com.papertrail.SearchPage = new function(){
        var PTSP = this;  //Self-reference as a function-writing nicety
        
        this.BaseImagePath = YAHOO.com.papertrail.initconfig.BaseImagePath;
        this.ImageSrcs = {
            QueryHistoryName:     "QueryHistoryName.gif",
            QueryHistoryDocument: "QueryHistoryDocument.gif",
            ViewNameReport:       "ViewNameReport.gif",
            ViewDocumentReport:   "ViewDocumentReport.gif",
            ViewSurvey:           "ViewSurvey.gif",
            QueryForDocuments:    "QueryForDocuments.gif",
            QueryForNames:        "QueryForNames.gif",
            ActionDelete:         "ActionDelete.gif",
            ActionContractResults:"ActionContractResults.gif",
            ActionExpandResults:  "ActionExpandResults.gif"
        };
        
        /**
          Define constants for the types of requests the scripts have to act
          around - either a NAME-type request (e.g. search for a emigrant name),
          or a MULTIDOCUMENT-type request (e.g. searching for a diary).
        */
        this.RequestClass = {
            MULTINAME:0,
            MULTIDOCUMENT:1,
            SINGLEDOCUMENT:2,
            NAMEREPORT:4,
            DOCUMENTREPORT:8,
            DOCUMENTSURVEY:16
        };
        
        /**
          Number of queries to show before old ones start being hidden.
        */
        this.ShowLastN = 3;
        
        /**
          Form information separator in the URL bar.
        */
        this.HistoryDelimiter = "~";
        
        /**
          State-reminder for the application.  Assumed true.
        */
        this.isPreloadComplete = true;
        
        /**
          Basically a static database query - these aren't changing any time soon.
        */
        this.Doctypes = {
          "*":"Document",
          "D":"Diary",
          "J":"Journal",
          "R":"Reminiscence",
          "A":"Autobiography",
          "N":"Newspaper Article",
          "G":"Guidebook",
          "L":"Letter",
          "O":"Other"
        };
        
        /**
          Debugger to check for IE6 slowdowns.
          @returns Boolean
        */
        this.AlertBreaksOn = function(){
            return this.ToggleIsOn("radAlertBreak");
        };
        
        /**
          Assumption:  Namescheme of the two radio buttons is @name + ['off'|'on']
        */
        this.ToggleIsOn = function(strRadName){
            var retval = false;
            var aryRads = [document.getElementById(strRadName + "Off"), document.getElementById(strRadName + "On")]; 
            if(aryRads[0] && aryRads[1]){
                retval = aryRads[1].checked;
            }
            return retval;
        };
        
        /**
          @returns Array of header id's.
        */
        this.GetAllHistoryEntryIDs = function(){
            var retary = [], tmpelname;
            for(var i=0, aryAllChildren = document.getElementById("queryhistory").childNodes; i<aryAllChildren.length; i++){
                tmpelname = aryAllChildren[i].nodeName;
                if(tmpelname && tmpelname.toUpperCase() == "DT")
                    retary.push(aryAllChildren[i].id)
                ;
            }
            return retary;
        };
        
        this.ResetHistory = function(){
            for(var aryids = PTSP.GetAllHistoryEntryIDs(), i=aryids.length-1; i>=0; i--){
                //Call the Remove of the Accordion, so the remembered-states object is appropriately reset.
                PTSP.Accordion.Remove(null,aryids[i]);
            }
        };
        YAHOO.util.Event.on([document.getElementById("resetter_names"), document.getElementById("resetter_docs")], "click", function(e){
            YAHOO.util.Event.preventDefault(e);
            PTSP.ResetHistory();
        });
        
        this.GetTableHeaderFormatter = function(reqtype){
            var retobj;
            switch(reqtype){
                case PTSP.RequestClass.MULTINAME:
                    retobj = {
                      "META":"",
                      "LNAME":"Family Name",
                      "FNAME":"First Name",
                      "AGE":"Age",
                      "SEX":"Gender",
                      "YEAR":"Year",
                      "ORIGIN":"Origin",
                      "CODES":"Individual Type",
                      "PARTY":"Party"
                    };
                break;
                case PTSP.RequestClass.MULTIDOCUMENT:
                case PTSP.RequestClass.SINGLEDOCUMENT:
                    retobj = {
                      "META":"",
                      "TITLE":"Title",
                      "LNAME":"Author",
                      "TYPE":"Type",
                      "D_CODE":"Document Code"
                    };
                break;
                default:
                    retobj = {};
                break;
            }
            
            //All formatters get a query error.
            retobj["Error"] = "Query Error";
            retobj["Subreq"] = "Subscription Required";
            
            return retobj;
        };
        
        /**
          @param reqtype One of the RequestClass object's values.
          @param objSample The first record returned from the server out of the results array.
        */
        this.MakeTableHead = function(reqtype, objSample){
            var retary = [];
            var objFormatter = PTSP.GetTableHeaderFormatter(reqtype);
            retary.push("  <thead>");
            retary.push("    <tr>");
            for(var i in objSample){
                if(objSample.hasOwnProperty(i)){
                    retary.push("      <th>" + objFormatter[i] + "</th>")
                }
            }
            retary.push("    </tr>");
            retary.push("  </thead>");
            return retary.join("\n");
        };
        
        /**
          Creates container element for the panels in use by this program.
        */
        this.ContainThePane = (function(){
            var div = document.createElement("div");
            div.id = "PanelContainer";
            YAHOO.util.Dom.addClass([
              document.getElementsByTagName("body")[0],
              div
            ], 'yui-skin-papert');
            document.body.appendChild(div);
            return div;
        })();
        
        /**
          Overlaid report container.
        */
        this.ReportPanel = (function(){
            var elReportPanel = document.createElement("div");
            elReportPanel.id = "PTReportPanel";
            PTSP.ContainThePane.appendChild(elReportPanel);
            var newpanel = new YAHOO.widget.Panel(
              elReportPanel,
              {
                width:"600px",
                close:true,
                visible:false,
                draggable:true,
                modal:true,
                context:null
              }
            );
            
            YAHOO.log("Appended the PanelContainer to an element with id " + document.getElementById("PanelContainer").parentNode.id,"trace","YAHOO.com.papertrail.SearchPage");
            
            return newpanel;
        })();
        
        /**
          "Loading" graphic container.
        */
        this.LoadingPanel = (function(){
            var elLoadingPanel = document.createElement("div");
            elLoadingPanel.id = "PTLoadingPanel";
            PTSP.ContainThePane.appendChild(elLoadingPanel);
            var newpanel = new YAHOO.widget.Panel(
              elLoadingPanel,
              {
                width:"320px",
                close:true,
                visible:false,
                draggable:true,
                modal:false,
                fixedcenter:true
              }
            );
            
            newpanel.setHeader("Loading results, please wait...");
            // Gif yoinked from:  http://us.i1.yimg.com/us.yimg.com/i/us/per/gr/gp/rel_interstitial_loading.gif,
            // c/o the example at http://developer.yahoo.com/yui/examples/container/panel-loading_clean.html
            newpanel.setBody("<img src='/images/rel_interstitial_loading.gif' />");
            newpanel.render(document.body);
            
            return newpanel;
        })();
        
        /**
          Error description container.
        */
        this.ErrorPanel = (function(){
            var elErrorPanel = document.createElement("div");
            elErrorPanel.id = "PTErrorPanel";
            PTSP.ContainThePane.appendChild(elErrorPanel);
            var newpanel = new YAHOO.widget.Panel(
              elErrorPanel,
              {
                width:"50em",
                close:true,
                visible:false,
                draggable:true,
                modal:false,
                fixedcenter:true
              }
            );
            
            return newpanel;
        })();
        
        /**
          
        */
        this.DisplayPanel = function(srcEventTarget, objResponse){
            YAHOO.log("Initializing the DisplayPanel.", "trace", "YAHOO.com.papertrail.SearchPage.DisplayPanel");
            
            var aryPanelXY = [
              ( YAHOO.util.Dom.getViewportWidth() - 600 )/2, //Center (hard-coded 600 because I can't figure out if YUI has a normalize-to-px function anywhere)
              YAHOO.util.Dom.getDocumentScrollTop() + 40 //40px of padding from the top of the viewport
            ];
            PTSP.ReportPanel.cfg.setProperty('xy', aryPanelXY);
            
            PTSP.ReportPanel.setBody(objResponse.responseText);
            
            //URL selector
            var url = "";
            switch(parseInt(objResponse.argument.queryParams.split("inlineaction=")[1].split("&")[0],10)){
                case PTSP.RequestClass.NAMEREPORT:
                    url = "report_name.asp";
                break;
                case PTSP.RequestClass.DOCUMENTREPORT:
                    url = "report_document.asp";
                break;
                case PTSP.RequestClass.DOCUMENTSURVEY:
                    url = "survey.asp";
                break;
                default:
                   YAHOO.log("Did not select an external URL for the requested inlineaction.", "warning", "YAHOO.com.papertrail.SearchPage.DisplayPanel");
                break;
            }
            
            var headercontents = "Paper Trail Report", footercontents = "";
            if(url != ""){
                //headercontents = "Paper Trail Report - overlaid view<br /><a class='NewWinLink' target='_blank' href='" + url + "?" + encodeURI(objResponse.argument.queryParams) + "&amp;print=true' title='(Opens in new window)'>Print-friendly version <img class='NewWinNotif' alt='(opens in new window)' src='/images/24-frame-add-12x12.png' /></a> is available";
                footercontents = "<p><a class='NewWinLink' target='_blank' href='" + url + "?" + encodeURI(objResponse.argument.queryParams) + "&amp;print=true' title='(Opens in new window)'>Print-friendly version <img class='NewWinNotif' alt='(opens in new window)' src='/images/24-frame-add-12x12.png' /></a></p>";
            }
            //footercontents += "<p>Scroll to the beginning of the document to exit.</p>";
            
            PTSP.ReportPanel.setHeader(headercontents);
            PTSP.ReportPanel.setFooter(footercontents);
            
            PTSP.ReportPanel.render(document.body);
            
            PTSP.ReportPanel.show();
            //PTSP.ReportPanel.hide();
        };
        
        
        /**
          A couple interesting events:  Data is loading from a remote location; data has finished loading; and data failed to load.
        */
        this.RemoteDataLoading = new YAHOO.util.CustomEvent('Remote data loading', this);
        this.RemoteDataRequestDone = new YAHOO.util.CustomEvent('Remote data request done', this);
        this.RemoteDataLoadFailed = new YAHOO.util.CustomEvent('Remote data failed to load', this);
        
        //When the remote data is loading, show the panel.
        this.RemoteDataLoading.subscribe(function(strEventType, aryFireArgs, objScope){
            this.LoadingPanel.show();
        });
        
        //When the remote data is loaded, hide the panel.
        this.RemoteDataRequestDone.subscribe(function(strEventType, aryFireArgs, objScope){
            this.LoadingPanel.hide();
        });
        
        //If the remote load failed, display the error.  Input:  The object from asyncRequest.
        this.RemoteDataLoadFailed.subscribe(function(strEventType, aryFireArgs, objScope){
            var strBodyHTML = [
              "<p>There was a server error loading the requested query.  If you would like to report this error to Paper Trail, you can send a bug report by e-mail with ",
              '<a href="mailto:',
              YAHOO.com.papertrail.initconfig.TechNotify,
              '?subject=[Paper Trail] Error report&amp;body=',
              encodeURI(
                'Hello,\n\nI encountered an error while using the Paper Trail service.  The website supplied the below code to help with debugging.\n\n' +
                aryFireArgs[0].toJSONString()
              ).replace(/\&/g,"%26"),   //encodeURI misses the ampersand; note that the 'g' flag must be set to get all the ampersands.
              '">this link</a>; the message body includes technical code which will help resolve the issue.</p>',
              ( (aryFireArgs[0].status == 0) ? "<p>A note:  The type of error you encountered, an HTTP communication failure, is potentially rectifiable by simply trying your action again.  Please report this error with the above link if you've encountered it twice.</p>" : '')
            ].join("");
            
            this.ErrorPanel.setHeader("Server Error");
            
            this.ErrorPanel.setBody(strBodyHTML);
            
            this.ErrorPanel.render(document.body);
            this.ErrorPanel.show();
        });
        
        
        /**
          Type of funcCallback?
          USE THIS URL TO SET A WAITING GRAPHIC:  http://developer.yahoo.com/yui/examples/container/panel-loading.html
        */
        this.RequestData = function(reqtype, queryParams, funcCallback){
            YAHOO.log("Called.", "trace", "YAHOO.com.papertrail.SearchPage.RequestData");

            //Set base query URL
            var queryurl;
            switch(reqtype){
                case PTSP.RequestClass.MULTINAME:
                    queryurl = "var/Query_Name.asp";
                break;
                case PTSP.RequestClass.MULTIDOCUMENT:
                    queryurl = "var/Query_Document.asp";
                break;
                case PTSP.RequestClass.SINGLEDOCUMENT:
                    queryurl = "var/Query_Document.asp";
                break;
                case PTSP.RequestClass.NAMEREPORT:
                    queryurl = "report_name.asp";
                break;
                case PTSP.RequestClass.DOCUMENTREPORT:
                    queryurl = "report_document.asp";
                break;
                case PTSP.RequestClass.DOCUMENTSURVEY:
                    queryurl = "survey.asp";
                break;
                default:
                    YAHOO.log("Unknown request type.", "warning", "YAHOO.com.papertrail.SearchPage.RequestData");
                break;
            }
            
            //Add parameters
            queryurl += "?"+queryParams;
            
            
            var transaction = YAHOO.util.Connect.asyncRequest(
              'GET',
              queryurl,
              {
                success: function(respobj){
                    if(PTSP.ToggleIsOn("radAlertBreak")) alert("Data retrieved.");
                    respobj.argument.funcCallback(respobj);
                    PTSP.RemoteDataRequestDone.fire();
                },
                failure: function(respobj){
                    YAHOO.log(respobj.responseText,"error","YAHOO.com.papertrail.SearchPage.RequestData.failure");
                    
                    PTSP.RemoteDataLoadFailed.fire(respobj);
                    PTSP.RemoteDataRequestDone.fire();
                },
                argument:{
                  queryParams:decodeURI(queryParams),
                  funcCallback:funcCallback
                }
              },
              null
            );
            
            //Notify that there's data in transit
            PTSP.RemoteDataLoading.fire();
        };
        
        
        /**
          Pretty-printer for query parameters.
          @return Returns string wholly describing a query.
        */
        this.PrettyPrint = function(reqtype, paramlist){
            var retval;
            var aryFields, aryNameValPair, fd = {};  //fd = form data; gotta be typed many times.

            YAHOO.log("Formatting:  " + paramlist, "", "YAHOO.com.papertrail.SearchPage.PrettyPrint");
            aryFields = paramlist.split("&");
            for(var i=0; i<aryFields.length; i++){
                aryNameValPair = aryFields[i].split("=");
                fd[aryNameValPair[0]] = CleanOutputOfScript(decodeURI(aryNameValPair[1]));
            }
            YAHOO.log("Format data:  " + fd.toJSONString(), "", "YAHOO.com.papertrail.SearchPage.PrettyPrint");
            
            //Building the sentence this way saves on typing "+ ' ' +" so many times.
            switch(reqtype){
                case PTSP.RequestClass.MULTINAME:
                    if(fd.fromaction){
                        //ASSUME this did not come from the form.
                        retval = 'All names in the document "' + fd.fromtitle + '."';
                    } else {
                        //ASSUME this came from the form.
                        retval = [
                          {"*":"People", "M":"Men", "F":"Women"}[fd.gender],
                          "named (matching " + {
                            "soundex":"Soundex",
                            "lead":"beginning",
                            "contain":"some portion",
                            "match":"exactly"
                          }[fd.namesearchtype] + ")",
                          fd.firstname,
                          fd.lastname,
                          'between',
                          fd.FromYear,
                          'and',
                          fd.ToYear + '.'
                        ].join(' ');
                    }
                break;
                case PTSP.RequestClass.MULTIDOCUMENT:
                    var tmpary = [
                      PTSP.Doctypes[fd.documenttype]
                    ];
                    //Maybe add a title statement.
                    if(fd.title){
                        tmpary.push(
                          "titled (matching " + {
                            "lead":"beginning",
                            "embedded":"some portion",
                            "contain":"some portion",
                            "match":"exactly"
                          }[fd.documentsearchtype] + ")"
                        );
                        tmpary.push('"' + fd.title + '"' + (fd.authlast ? "," : "")); //Comma to separate author clause
                    }
                    
                    //Maybe add an author.
                    if(fd.authlast)
                        tmpary.push("authored by " + fd.authlast)
                    ;
                    retval = tmpary.join(' ') + ".";
                break;
                case PTSP.RequestClass.SINGLEDOCUMENT:
                    retval = "Document mentioning " + fd.namefullname + " in " + fd.year;
                break;
            }
            return retval;
        };
        
        
        this.MakeTableBody = function(reqtype, aryData){
        };
        
        /**
          This ain't gonna be pretty in overlap.
        */
        this.MakeInlineActionLink = function(fromact, toact, objrecord){
            var aryFormParams = [];
            
        };
        
        /**
          Appends a new dt and dd child to the queryhistory object.
          
        */
        this.AddNewQueryToHistory = function(msTimestamp, reqtype, objResponse){
            YAHOO.log("Appending a new query.","trace","YAHOO.com.papertrail.SearchPage.AddNewQueryToHistory");
            if(PTSP.ToggleIsOn("radAlertBreak")) alert("Parsing response text into a JSON object.");
            var aryResults = objResponse.responseText.parseJSON();
            if(PTSP.ToggleIsOn("radAlertBreak")) alert("Finished parsing response text.");
            var paramlist = objResponse.argument.queryParams;  //YAHOO uri-encodes the query parameters when it serializes the string.  That's fine and dandy, but these are now being used for tracking, not for querying.
            
            var elQH = document.getElementById("queryhistory");
            var elNewDT = document.createElement("dt");
            var elNewDD = document.createElement("dd");
            var msNow = (new Date()).valueOf();
            elNewDT.id = "dt_qry" + msTimestamp;
            elNewDD.id = "dd_qry" + msTimestamp;
            
            //Update history state's reflection in URL, if adding something after the page has loaded
            if(PTSP.isPreloadComplete) PTSP.AugmentURL("qhistid=" + msTimestamp + "&" + paramlist);
            
            //Set four things in this switch block:
            // * Query results header (displayed item in Accordion)
            // * Query results table caption
            // * List of action-links in the leftmost cell, via a formatter function
            // * Field to sort on (comparator function)
            var htmlHeader, htmlCaption, numRealResults, funcStrActionFormatter, funcSortComparator;
            numRealResults = aryResults[0].Error ? 0 : aryResults.length;
            switch(reqtype){
                case PTSP.RequestClass.MULTINAME:
                    htmlHeader = "<img src='" + PTSP.BaseImagePath + PTSP.ImageSrcs.QueryHistoryName + "' alt='Name Search' /> " + PTSP.PrettyPrint(reqtype, paramlist) + " (" + numRealResults + " results)";
                    htmlCaption = 'Names';
                    funcStrActionFormatter = function(objrecord){
                        var objmeta = objrecord["META"];
                        YAHOO.log("Formatting object " + objmeta.toJSONString(), "trace", "funcStrActionFormatter");
                        return [
                          "<pre>",
                            "<a href='#" + encodeURI("NameNumber=" + objmeta["NAMENUMBER"] + "&amp;fromaction=" + PTSP.RequestClass.MULTINAME + "&amp;inlineaction=" + PTSP.RequestClass.NAMEREPORT) + "' class='actionlink' title='View name report'><img alt='View name report' src='" + PTSP.BaseImagePath + PTSP.ImageSrcs.ViewNameReport + "' /></a> ",
                            "<a href='#" + encodeURI([
                              "D_Code=" + objmeta["D_CODE"],
                              "fromaction=" + PTSP.RequestClass.MULTINAME,
                              "inlineaction=" + PTSP.RequestClass.SINGLEDOCUMENT,
                              "namefullname=" + objmeta["NAMEFULLNAME"],
                              "year=" + objrecord["YEAR"]
                            ].join("&amp;")) + "' class='actionlink' title='Search for document mentioning this name'><img alt='Search for document mentioning this name' src='" + PTSP.BaseImagePath + PTSP.ImageSrcs.QueryForDocuments + "' /></a> ",
                            "<a href='survey.asp?" + encodeURI("D_Code=" + objmeta["D_CODE"] + "&amp;fromaction=" + PTSP.RequestClass.MULTINAME) + "' class='NewWinLink' target='_blank' title='View survey (Opens in new window)'><img alt='View Survey' src='/images/" + PTSP.ImageSrcs.ViewSurvey + "' /></a>",
                          "</pre>"
                        ].join("");
                    };
                    funcSortComparator = function(a,b){
                        var retval = -1;  //Default:  Assume a < b (assuming "==" takes less time to evaluate than "<")
                        if(a.LNAME == b.LNAME){
                            //retval is still -1
                            if(a.FNAME == b.FNAME) retval = 0;
                            if(a.FNAME > b.FNAME) retval = 1;
                        }
                        if(a.LNAME > b.LNAME) retval = 1;
                        return retval;
                    };
                break;
                case PTSP.RequestClass.MULTIDOCUMENT:
                    htmlHeader = "<img src='" + PTSP.BaseImagePath + PTSP.ImageSrcs.QueryHistoryDocument + "' alt='Document Search' /> " + PTSP.PrettyPrint(reqtype, paramlist) + " (" + numRealResults + " results)";
                    htmlCaption = "Documents";
                    funcStrActionFormatter = function(objrecord){
                        var objmeta = objrecord["META"];
                        YAHOO.log("Formatting object " + objmeta.toJSONString(), "trace", "funcStrActionFormatter");
                        return [
                          "<pre>",
                            //Note:  IE does not recognize "&apos;" as an apostrophe.  Feh.
                            "<a href='#" + encodeURI("D_Code=" + objmeta["D_CODE"] + "&amp;fromaction=" + PTSP.RequestClass.MULTIDOCUMENT  + "&amp;inlineaction=" + PTSP.RequestClass.MULTINAME + "&amp;fromtitle=" + objmeta["TITLE"].replace(/\'/g, "&#39;")) + "' class='actionlink' title='View all names in document'><img alt='View all names in document' src='" + PTSP.BaseImagePath + PTSP.ImageSrcs.QueryForNames + "' /></a> ",
                            "<a href='#" + encodeURI("D_Code=" + objmeta["D_CODE"] + "&amp;fromaction=" + PTSP.RequestClass.MULTIDOCUMENT  + "&amp;inlineaction=" + PTSP.RequestClass.DOCUMENTREPORT                                                          ) + "' class='actionlink' title='View document report'><img       alt='View document report'       src='" + PTSP.BaseImagePath + PTSP.ImageSrcs.ViewDocumentReport + "' /></a> ",
                            "<a href='survey.asp?" + encodeURI("D_Code=" + objmeta["D_CODE"] + "&amp;fromaction=" + PTSP.RequestClass.MULTIDOCUMENT) + "' class='NewWinLink' target='_blank' title='View survey (Opens in new window)'><img alt='View Survey'  src='/images/" + PTSP.ImageSrcs.ViewSurvey + "' /></a>",
                          "</pre>"
                        ].join("");
                    };
                    funcSortComparator = function(a,b){
                        var retval = -1;  //Default:  Assume a < b (assuming "==" takes less time to evaluate than "<")
                        if(a.LNAME == b.LNAME) retval = 0;
                        if(a.LNAME > b.LNAME) retval = 1;
                        return retval;
                    };
                break;
                case PTSP.RequestClass.SINGLEDOCUMENT:
                    htmlHeader = "<img src='" + PTSP.BaseImagePath + PTSP.ImageSrcs.QueryHistoryDocument + "' alt='Document Search' /> " + PTSP.PrettyPrint(reqtype, paramlist);
                    htmlCaption = aryResults[0]["TITLE"] || "Document";
                    funcStrActionFormatter = function(objrecord){
                        var objmeta = objrecord["META"];
                        return [
                          "<pre>",
                            "<a href='#" + encodeURI("D_Code=" + objmeta["D_CODE"] + "&amp;fromaction=" + PTSP.RequestClass.SINGLEDOCUMENT + "&amp;inlineaction=" + PTSP.RequestClass.MULTINAME + "&amp;fromtitle=" + objmeta["TITLE"].replace(/\'/g, "&#39;")) + "' class='actionlink' title='View all names in document'><img alt='View all names in document' src='" + PTSP.BaseImagePath + PTSP.ImageSrcs.QueryForNames + "' /></a> ",
                            "<a href='#" + encodeURI("D_Code=" + objmeta["D_CODE"] + "&amp;fromaction=" + PTSP.RequestClass.SINGLEDOCUMENT + "&amp;inlineaction=" + PTSP.RequestClass.DOCUMENTREPORT                                                          ) + "' class='actionlink' title='View document report'><img       alt='View document report'       src='" + PTSP.BaseImagePath + PTSP.ImageSrcs.ViewDocumentReport + "' /></a> ",
                            "<a href='survey.asp?" + encodeURI("D_Code=" + objmeta["D_CODE"]) + "&amp;fromaction=" + PTSP.RequestClass.SINGLEDOCUMENT + "' class='NewWinLink' target='_blank' title='View survey (opens in new window)'><img alt='View Survey' src='/images/" + PTSP.ImageSrcs.ViewSurvey + "' /></a>",
                          "</pre>"
                        ].join("");
                    };
                    funcSortComparator = function(a,b){
                        return 0;
                    };
                break;
                default:
                    YAHOO.log("Unknown RequestClass:  " + reqtype, "error", "YAHOO.com.papertrail.SearchPage.AddNewQueryToHistory");
                break;
            }
            
            //Header extras - a scrolling-up button and a deleting button
            var htmlHeaderExtras;
            htmlHeaderExtras = [
              "<a class='pseudobutton deleteaction' href='#qhistid=" + msTimestamp + "'><img alt='Clear' title='Clear' src='" + PTSP.BaseImagePath + PTSP.ImageSrcs.ActionDelete + "' /></a>",
              "<a class='pseudobutton scrolltoggleaction'>" + PTSP.Accordion.StateIcons.EXPANDED + "</a>"
            ].join("");
            
            elNewDT.innerHTML = htmlHeaderExtras + htmlHeader;
            
            //Left to database
            //aryResults.sort(funcSortComparator);
            
            //Old-person placeholder from banner of:
            //  http://learningtheworld.eu/2007/foreground-sprites/
            //Pedestrian acquired from:
            //  http://images.jupiterimages.com/common/detail/26/40/23304026.jpg
            
            //Query results body (compacted item in Accordion)
            var aryTabularData = [];  //Makes one HTML string later
            var aryFormattedCodes, aryUnformattedCodes;
            if(PTSP.ToggleIsOn("radAlertBreak")) alert("Beginning to transform " + aryResults.length + " results into HTML text.");
            for(var i=0; i<aryResults.length; i++){
                aryTabularData.push("    <tr>");
                for(var j in aryResults[i]){
                    //Check that we don't accidentally add any Object augmentations (e.g. toJSONString())
                    if(aryResults[i].hasOwnProperty(j)){
                        switch(j.toUpperCase()){
                            case "META":
                                aryTabularData.push("      <td valign='top'>" + funcStrActionFormatter(aryResults[i]) + "</td>");
                            break;
                            case "TYPE":
                                aryTabularData.push("      <td valign='top'>" + PTSP.Doctypes[aryResults[i][j]] + "</td>");
                            break;
                            case "CODES":
                                aryFormattedCodes = aryResults[i][j];
                                aryTabularData.push("      <td valign='top'>" + aryFormattedCodes.join(", ") + "</td>");
                            break;
                            default:
                                aryTabularData.push("      <td valign='top'>" + aryResults[i][j] + "</td>");
                            break;
                        }
                    }
                }
                aryTabularData.push("    </tr>");
            }
            
            if(PTSP.ToggleIsOn("radAlertBreak")) alert("Transforming HTML text into DOM objects.");
            elNewDD.innerHTML = [
              "<table class='results'>",
                 PTSP.MakeTableHead(reqtype, aryResults[0]),
              "  <tbody>",
                   aryTabularData.join("\n"),
              "  </tbody>",
              "</table>"
            ].join("\n");
            
            if(PTSP.ToggleIsOn("radAlertBreak")) alert("Appending query history item to document.");
            elQH.appendChild(elNewDT);
            elQH.appendChild(elNewDD);
            
            if(PTSP.ToggleIsOn("radAlertBreak")) alert("Finished adding query object; now scrolling.");
            //Scroll to newly appended element if not loading the page
            if(PTSP.isPreloadComplete)
                PTSP.Scroller.Goto(msTimestamp)
            ;
            
            
            //Hide older queries
            YAHOO.log("The query history has " + elQH.getElementsByTagName("dt").length + " dt children.");
        };
        
        /**
          Removes a dt/dd sibling pair from the query history dl.
          ASSUMES NAMESCHEME:  elid is of the form "d[t|d]_.+".
        */
        this.RemoveQueryFromHistory = function(elid){
            YAHOO.log("Removing " + elid + " from the document query history.","trace","YAHOO.com.papertrail.SearchPage.RemoveQueryFromHistory");
            var elsuffix = elid.split("_")[1];
            var
              targetdt = document.getElementById("dt_" + elsuffix),
              targetdd = document.getElementById("dd_" + elsuffix)
            ;
            targetdt.parentNode.removeChild(targetdt);
            targetdd.parentNode.removeChild(targetdd);
            
            //elsuffix is the timestamp, tracked in all the queries.
            PTSP.TrimURL(elsuffix.split("qry")[1]);
        };
        
        /**
          Guide the user's screen when results are added to the bottom of the potential 30+ pages on the screen.
        */
        this.Scroller = new function(){
            this.lead = 100;
            this.objScroll = new YAHOO.util.Scroll(
              document.getElementsByTagName("html")[0],
              {
                scroll:{
                  to: [0,800]
                }
              },
              0.75,
              YAHOO.util.Easing.easeOut
            );
            
            /**
              @param queryid The identifier of the query, not necessarily of the associate query container-element.
            */
            this.Goto = function(queryid){
                //Retrieve the top of the target element
                var newdocy = YAHOO.util.Dom.getRegion(
                  document.getElementById("dt_qry" + queryid)
                ).top;
                //Scroll to just before the top
                this.objScroll.attributes["scroll"]["to"] = [0,newdocy - this.lead];
                this.objScroll.animate();
            };
        };
        
        /**
          Simulate a page history on the URL bar.
          @param addition A query represented as serialized form data for the URL.
        */
        this.AugmentURL = function(addition){
            var curloc = document.location.href;
            var newloc;
            YAHOO.log("Augmenting current document URL:  " + document.location.href, "trace", "YAHOO.com.papertrail.SearchPage.AugmentURL");
            
            var aryLocComponents = curloc.split("#");
            
            //We want to augment the list of past queries generated to this point.  So, start or add to what's already there.
            var aryHistory = aryLocComponents[1] ? aryLocComponents[1].split(PTSP.HistoryDelimiter) : [];
            aryHistory.push(addition);
            
            newloc = aryLocComponents[0] + "#" + encodeURI(aryHistory.join(PTSP.HistoryDelimiter));
            document.location.href = newloc;
            
            YAHOO.log("New document URL:  " + document.location.href, "trace", "YAHOO.com.papertrail.SearchPage.AugmentURL");
        };
        
        /**
          Remove an entry from the delimited list in the document-bookmark portion of the URL.
          The minimal URL that will be set by this will be the base URL plus "#", because without a hash the page is considered script-redirected.
          @param subtraction A timestamp, included as part of the query data.
        */
        this.TrimURL = function(subtraction){
            var curloc = document.location.href;
            var newloc;
            YAHOO.log("Trimming current document URL:  " + document.location.href, "trace", "YAHOO.com.papertrail.SearchPage.TrimURL");
            
            //Break apart current href to extract the URI and the old queries
            var aryLocComponents = curloc.split("#");
            
            //Set up queries
            var aryOldHistory = aryLocComponents[1] ? aryLocComponents[1].split(PTSP.HistoryDelimiter) : [];
            var aryNewHistory = [];
            
            //Retain all old queries that do not have the matching timestamp.
            for(var i=0; i<aryOldHistory.length; i++){
                if(aryOldHistory[i].indexOf(subtraction) == -1)
                    aryNewHistory.push(aryOldHistory[i])
                ;
            }
            
            //Build new location string
            //NOTE the hash must be included, else the page is considered redirected.
            newloc = aryLocComponents[0] + "#";
            if (aryNewHistory.length > 0){
                newloc += aryNewHistory.join(PTSP.HistoryDelimiter);
            } else {
                YAHOO.log("There was no query history, but TrimURL was called - how did that happen?", "warning", "YAHOO.com.papertrail.SearchPage.TrimURL");
            }
            
            document.location.href = newloc;
            
            YAHOO.log("New document URL:  " + document.location.href, "trace", "YAHOO.com.papertrail.SearchPage.TrimURL");
        };
    };
    
    YAHOO.com.papertrail.SearchPage.Accordion = new function(){
        
        //Shorthand for the paper trail accordion
        var PTAC = this;
        var PTSP = YAHOO.com.papertrail.SearchPage;
        
        /**
          Speed of the accordion action
        */
        this.ActionSpeed = 0.5;
        
        /**
          This is a hash table that remembers the heights of all of the dd elements that are compacted in an accordion action.
        */
        this.rememberedHeights = {};
        
        this.StateIcons = {
            EXPANDED: "<img alt='Collapse results' title='Collapse results' src='" + PTSP.BaseImagePath + PTSP.ImageSrcs.ActionContractResults + "' />",
            CONTRACTED: "<img alt='Expand results' title='Expand results'   src='" + PTSP.BaseImagePath + PTSP.ImageSrcs.ActionExpandResults + "' />"
        };
        
        /**
          Contract an element.
          Modifies the accordion remembered heights.
          @param elid ID of a DD child of dl#queryhistory.
        */
        this.Action = function(elid){
            YAHOO.log("Acting on " + elid, "trace", "YAHOO.com.papertrail.SearchPage.Accordion.Action");
            var eldd = document.getElementById(elid);
            if(!eldd){
                YAHOO.log("Could not find element #" + elid + "!  No action taken.", "warning", "YAHOO.com.papertrail.SearchPage.Accordion.Action");
            } else {
                //Set overflow to hidden, otherwise compacting animation fails.
                YAHOO.util.Dom.setStyle(eldd, 'overflow', 'hidden');
                
                //Set numpxCurHeight as current number of pixels (YAHOO.....getStyle returns a pixel measurement in Firefox, 'auto' in IE - IE actually acts as I'd expect.  Use Region from YUI instead.)
                var ddregion = YAHOO.util.Dom.getRegion(eldd);
                var numpxCurHeight = ddregion.bottom-ddregion.top;
                YAHOO.log(elid + " is " + numpxCurHeight + " pixels tall.", "trace", "YAHOO.com.papertrail.SearchPage.Accordion.Action");
                
                //Retrieve old height.  If there's no old height, consider the old height to be 0 (being borne from nothing, if symbology's desired).
                if(!PTAC.rememberedHeights.hasOwnProperty(elid)){
                    PTAC.rememberedHeights[elid] = 0;
                } else {
                    //Occupado
                }
                var numpxNewHeight = PTAC.rememberedHeights[elid];
                
                //Store now-old height in accordion's memory of dd's
                PTAC.rememberedHeights[elid] = numpxCurHeight;
                
                //Act
                var anim = new YAHOO.util.Anim(
                  eldd,
                  {
                    height:{
                      to: numpxNewHeight
                    }
                  },
                  PTAC.ActionSpeed
                );
                anim.animate();
                
                //Set graphical state of scrolling icon
                var elAccordionHandleParent = document.getElementById(
                  "dt_" + elid.split("_")[1]
                );
                var elAccordionHandle = null;
                for(var i=0, aryEls = elAccordionHandleParent.getElementsByTagName("a"); i<aryEls.length; i++){
                    if(YAHOO.util.Dom.hasClass(aryEls[i],"scrolltoggleaction")){
                        elAccordionHandle = aryEls[i];
                        break;
                    }
                }
                if(elAccordionHandle){
                    elAccordionHandle.innerHTML = PTAC.StateIcons[
                      (PTAC.rememberedHeights[elid] == 0) ? "EXPANDED" : "CONTRACTED"
                    ];
                }
            }
        };
        
        /**
          Cleans up Accordion references to the element with id elid, then calls on the SearchPage object to remove it from the history.
          Receives the click event that caused this delete act so the default action can be prevented.
        */
        this.Remove = function(e, elid){
            YAHOO.log("Removing " + elid + " from the Accordion object.", "trace", "YAHOO.com.papertrail.SearchPage.Accordion.Remove");
            //YAHOO.util.Event.stopEvent(e);  // This is a convenience method for stopPropagation and preventDefault.  Does not actually stop multiple listeners on one event.  (http://developer.yahoo.com/yui/docs/YAHOO.util.Event.html#stopEvent)
            if(e)
                YAHOO.util.Event.preventDefault(e)
            ;
            if(PTAC.rememberedHeights[elid])
                delete PTAC.rememberedHeights[elid]
            ;
            YAHOO.com.papertrail.SearchPage.RemoveQueryFromHistory(elid);
        };
        
        /**
          Contract or expand a DD element by clicking its similarly-identified sibling DT's child handler,
          - OR -
          Initiate element deletion from the query history.
          Attached to container DL element AFTER other handlers, so the event
          handler does not need to be applied to every new child of the DL.
          This is intended to act on, in CSS selector syntax, "dl.queryhistory > dt", NOT the more general "dl > dt".
          Conceptual examples at: http://com1.devnet.scd.yahoo.com/yui/examples/event/event-delegation.html
        */
        this.Handler = function(e){
            var elTarget = YAHOO.util.Event.getTarget(e);
            var elActionableRoot = document.getElementById("queryhistory");
            var elTargetParent;
            while (elTarget != elActionableRoot){
                if(elTarget.nodeName.toUpperCase() == "A" && YAHOO.util.Dom.hasClass(elTarget, "pseudobutton")){
                    //This is the node we want; act on the uncle DD then stop.
                    elTargetParent = elTarget.parentNode;
                    var ddid = [
                      "dd",
                      elTargetParent.id.split("_")[1]
                    ].join("_");
                    
                    //Are we scrolling, or deleting?
                    if(YAHOO.util.Dom.hasClass(elTarget, "scrolltoggleaction")){
                        PTAC.Action(ddid);
                    } else if(YAHOO.util.Dom.hasClass(elTarget, "deleteaction")){
                        PTAC.Remove(e, ddid);
                    }
                        
                    break;
                } else {
                    //Didn't find an actionable item, so ascend, looking for an appropriate DT
                    elTarget = elTarget.parentNode;
                }
            }
            //No further operations
        }
    };
    
    //Add pseudo-submission to links in result tables
    YAHOO.util.Event.on("queryhistory", "click", function(e){
        var PTSP = YAHOO.com.papertrail.SearchPage;
        
        //Act on CSS selector "#queryhistory table.results a"
        var elTarget = YAHOO.util.Event.getTarget(e);
        YAHOO.log("Called from a " + elTarget, "trace", "$queryhistory.onclick");
        
        //Timing issue - there are multiple click handlers.  One handler deletes elements from the DOM, including the target.
        if(elTarget && elTarget.parentNode){
            var elActionableRoot = document.getElementById("queryhistory");
            while (elTarget && elTarget != elActionableRoot){
                if(elTarget && elTarget.nodeName.toUpperCase() == "A" && YAHOO.util.Dom.hasClass(elTarget, "actionlink")){
                    //Found the anchor - act and stop.
                    //Prevent link from being followed
                    YAHOO.util.Event.preventDefault(e);
                    
                    //For the history, add the query parameters minus the hash
                    var newQueryParams = elTarget.href.split("#")[1];
                    
                    //Convert the parameters to a miniature form, to find the action and determine what to do next.
                    //Find:  inlineaction
                    var nextAction = parseInt(
                      newQueryParams.split("inlineaction=")[1].split("&")[0],  //This hews the string in twain, deleting "inlineaction=" and all leftward text, then deletes any additional parameters coming afterwards by looking for any remaining ampersands and severing there.
                      10 //This keeps parseInt from treating some numbers as octal.  (What a lingual artifact..."010" -> 8)
                    );
                    YAHOO.log("Acting on the inlineaction:  " + nextAction, "trace", "$queryhistory.onclick");
                    
                    //Here, things get interesting.  Are we looking up more names?  Curious about a single name or document?  Act based on the input action.
                    switch(nextAction){
                        case PTSP.RequestClass.MULTINAME:
                        case PTSP.RequestClass.MULTIDOCUMENT:
                        case PTSP.RequestClass.SINGLEDOCUMENT:
                            YAHOO.log("Went down the query-history switch-case branch.", "trace", "$queryhistory.onclick");
                            
                            //Define callback function for YAHOO connection.
                            var funcNextAction = function(objResults){
                                PTSP.AddNewQueryToHistory(
                                  (new Date()).valueOf() + "+" + Math.floor(Math.random()*1000),
                                  nextAction,
                                  objResults
                                );
                            };
                            //YAHOO.log("Type of funcNextAction:  " + typeof funcNextAction, "trace", elTarget.nodeName+".click");
                            
                            //Make search results and append to page
                            PTSP.RequestData(
                              nextAction,
                              newQueryParams,
                              funcNextAction
                            );
                        break;
                        case PTSP.RequestClass.NAMEREPORT:
                        case PTSP.RequestClass.DOCUMENTREPORT:
                            YAHOO.log("Went down the report switch-case branch.", "trace", "$queryhistory.onclick");
                            //Run a nicely-formatted report.
                            
                            //Internet Explorer's throwing a "Member not found" error.  Not sure what's up.
                            YAHOO.log([
                              "Member types that are about to be called:  ",
                              "PTSP.RequestData:  " + typeof PTSP.RequestData,
                              "PTSP.DisplayPanel:  " + typeof PTSP.DisplayPanel
                            ].join("\n"), "trace", "$queryhistory.onclick");
                            
                            PTSP.RequestData(
                              nextAction,
                              newQueryParams,
                              function(objData){
                                  PTSP.DisplayPanel(elTarget, objData);
                              }
                            );
                            
                            YAHOO.log("Finished the call for RequestData.", "trace", "$queryhistory.onclick");
                        break;
                        case PTSP.RequestClass.DOCUMENTSURVEY:
                            YAHOO.log("Went down the survey switch-case branch.", "trace", "$queryhistory.onclick");
                            ////Load up a survey.
                            //PTSP.RequestData(
                            //  nextAction,
                            //  newQueryParams,
                            //  function(objData){
                            //      PTSP.DisplayPanel(elTarget, objData);
                            //  }
                            //);
                            
                            var curbaseurl = document.location.href.split("search.asp")[0];
                            
                            document.location.href = [
                              curbaseurl,
                              "survey.asp?",
                              newQueryParams
                            ].join("");
                        break;
                    }
                    break;
                } else {
                    //Ascend.
                    elTarget = elTarget.parentNode;
                }
            }
        }
    });
    
    //Potentially delete an element with this handler, which is why it's last for the query history.  Execution order seems to be different in IE, though.
    YAHOO.util.Event.on("queryhistory", "click", YAHOO.com.papertrail.SearchPage.Accordion.Handler);
    
    
    //Modify behavior of form submit events
    YAHOO.util.Event.on(
      ["nameform","documentform"],
      "submit",
      function(e){
          //Prevent actual form submission
          YAHOO.util.Event.stopEvent(e);
          
          var formid = YAHOO.util.Event.getTarget(e).id
          var formdata = YAHOO.util.Connect.setForm(formid);
          //Reset this, so we can standardize on just using GET requests instead of mixing and matching POST requests (causes a headache when considering how to handle a form submission versus a SAVED form submission)
          YAHOO.util.Connect.resetFormState();
          
          //Type of request?
          //Neat substitute for a switch statement, eh?  --AJN 20071010
          var reqtype = {
            nameform: YAHOO.com.papertrail.SearchPage.RequestClass.MULTINAME,
            documentform: YAHOO.com.papertrail.SearchPage.RequestClass.MULTIDOCUMENT
          }[formid];
          
          YAHOO.log("New request of reqtype " + reqtype, "trace");
          
          YAHOO.com.papertrail.SearchPage.RequestData(
            reqtype,
            formdata,
            function(objResults){
                YAHOO.com.papertrail.SearchPage.AddNewQueryToHistory(
                  (new Date()).valueOf() + "+" + Math.floor(Math.random()*1000),
                  reqtype,
                  objResults
                );
            }
          );
      }
    );
    
    //Did we load the page on some saved queries?  If yes, process them.
    function PreloadQueries(aryQueryParamSets){
        if(aryQueryParamSets.length == 0){
            //Tell the history modifier that the aplication has finished its preload and can modify the browser history once again.
            YAHOO.com.papertrail.SearchPage.isPreloadComplete = true;
        } else {
            var aryQueryStack = aryQueryParamSets;
            aryQueryStack.reverse(); //For popping
            var curQuery = aryQueryStack.pop();
            aryQueryStack.reverse(); //For resuming original order
            
            YAHOO.log("Preloading query:  " + curQuery + "\n(" + aryQueryStack.length + " queries to go).", "trace", "PreloadQueries");
            
            var reqtype = null;
            if(curQuery.indexOf("NameFormSubmitter") > 0){
                reqtype = YAHOO.com.papertrail.SearchPage.RequestClass.MULTINAME
            } else if(curQuery.indexOf("DocumentFormSubmitter") > 0){
                reqtype = YAHOO.com.papertrail.SearchPage.RequestClass.MULTIDOCUMENT
            } else if(curQuery.indexOf("inlineaction=") > 0) {
                reqtype = parseInt(curQuery.split("inlineaction=")[1].split("&")[0], 10);
            } else {
                //No action found - how'd this query run?
                YAHOO.log("No action found.", "warning", "PreloadQueries");
            }
            if(reqtype !== null){
                //Retrieve the timestamp used before (may as well; the timestamp's necessity is in the history trimming, not so much the construction)
                var qhistid = curQuery.split("qhistid=")[1].split("&")[0];
                YAHOO.com.papertrail.SearchPage.RequestData(
                  reqtype,
                  curQuery,
                  function(objResults){
                      YAHOO.com.papertrail.SearchPage.AddNewQueryToHistory(
                        qhistid,
                        reqtype,
                        objResults
                      );
                      //Recurse after data loads and is processed, keeping timing issues from occurring
                      PreloadQueries(aryQueryStack);
                  }
                );
            } else {
                //Recurse now
                YAHOO.log("Preloaded nothing; no reqtype.");
                PreloadQueries(aryQueryStack);
            }
        }
    }
    //Execute on page load
    (function(){
        var curLocComponents = document.location.href.split("#");
        if(curLocComponents.length > 1){
            //Do not modify the browser history until the pre-defined queries have run.
            YAHOO.com.papertrail.SearchPage.isPreloadComplete = false;
            PreloadQueries(curLocComponents[1].split(YAHOO.com.papertrail.SearchPage.HistoryDelimiter));
        }
    })();
});
