//-----------------------------------------------------------
var sRAProg = "report_ajax.js";
var sRAVers = "20120113";
//
// This contains code primarily related to the new container-based report and inputform 
// apps and AJAX processing.
//
// Version History (in reverse chronological order, most recent first):
//  20120113:dms:Added error handling for the situation when no response from server for handleFormRefresh
//  20120111:dms:Added some niceties to the failure message in handleFormSubmit
//  20111116:dms:Add menu refreshes to reflect status change in running or viewed reports 
//  20111013:dms:minor change in hopes of better tuning the PeriodicalUpdater
//  20110812:dms:fixed bug in setTargets pertaining to a href sunk in div
//  20110722:dms:fixed restoreScrollTableEvents management of target cell names in support of
//               re-registration of click event
//  20110709:dms:removed propagation of _activePage_ url parameter
//  20110701:dms:added performance enhancements to save and restore scrollTableEvents methods
//  20110624:dms:modified handleFormSubmit in support of redirect (for excel auto-open initially)
//           dms:modified saveScrollTableEvents to add additional checking to prevent failure when click events not registered with prototype
//  20110510:dms:modified restoreScrollTableEvents to more accurately grab table elements and run slightly faster
//  20110510:dms:modified restoreScrollTableEvents to more accurately grab table elements and run slightly faster.
//  20110322:dms:removed disableInput functions because it was changing the rendering (ie bold to unbold, etc)
//           and it was redundant with the graying out of the screen between pages anyway
//  20110318:dms:modified restoreScrollTableEvents to manage target cell names
//  20110316:dms:added functions to save and restore scroll table events
//  20110216:dms:Added more detail to ajax exception output message
//  20101220 Modify to prevent a completing report from overwriting whatever currently viewed page unless it 
//           corresponds to that report
//  20101214 Modify error handling to incorporate uniformity
//  20101207 Modified handleFormSubmit and handleReportRefresh to propagate tab setting if exists
//  20101108 Added function traceReportsRun to populate ENV_REQUEST_RUN table of reports run by specific user
//           id, and when requested.
//  20100927 Fixed array bug in setTarget
//  20100915 In setTargets, added target cell id prefix of tgt_ to fix leading number bug
//  20100913 Modified retrieveFromRecovery to NOT run cleanRecovery upon completion
//  20100909 Finished adding report (currently) recovery code: saveForRecovery, retrieveFromRecovery, bRecordsToRecover,
//           cleanRecovery
//  20100818 Add setTargets to set the target data in a report after the report has been displayed
//  20100802 Localized rptPU variable in handleReportRefresh since it's globalized use was causing cross-report overlap
//           which materialized in a blinking shadow when running a report since it was checking for the running of
//           report 'B' (which was likely completed - thus, the blinking) though it was actually running report 'A'
//  20100723 Modified handleReportRefresh to call new method that queries db rather than run report.asp
//           over and over just to check completion; also modified method params to accept 2 params - 
//           #1 is the method run to check for report completion; #2 is the method to run to refresh the page
//-----------------------------------------------------------

var recoverSession = false;                                //indicates if there is a session to restore
var scrollTableEvents = $H();                              //data table events to be restored after conversion to scroll table

function handleFormSubmit (event, url, validationRequired, formParamsProvided) {

   // Purpose:   Since introducing the notion of a container within which all activity takes place for this system,
   //            this function uses AJAX to handle ALL submits for the system (not just forms as the name implies).
   //
   //            This process manages the legacy disableInput function while processing.
   //
   //            Failure and exceptions are handled via javascript alerts for lack of anything better right now, 
   //            though this might be revisited.
   //
   // Arguments: event:              The event that was triggered to cause the submission
   //            url:                The URL of the next process to run.  This may or may not have parameters 
   //                                included.  It may be absolute or relative.
   //            validationRequired: Allows the calling routine to tell this method whether or not validation needs 
   //                                to be performed at the form field level.  This is typically false.
   //            formParamsProvided: Independent of whether paramaters are included with the url, this boolean
   //                                will indicate whether additional form fields need to be serialized and 
   //                                concatenated with the url.
   //
   // Returns:   neither true or false
   // ------------------------------------------------------------------------------------------------------------

   var frm;
   if (event) { 
      Event.stop(event);                                   // to ensure no bubble-up handling of event, discontinue processing of event
      frm = Event.element(event);                          // get object that event was triggered on; this was likely a form...
   }
   var addlParams = "";                                    // form parameters to be submitted that were not included with the url
   var validChange = true;                                 // assumed true but could be changed during form field validation
   var field = frm;                                        // ...or form field...

   if (validationRequired) {                               // if validation is required...
      if (event.type == "submit") {                        // and it was a submit event...
         field = frm.children[0];                          // the event was triggered at the form level and the field can be derived from the DOM
      } else {                                             // otherwise
         frm = field.form;                                 // the event was triggered at the field level and the form can be derived from the DOM
      }
      validChange = submitChg(field,((field.type == "text" && field.id == "DISPLAYPARAMS") ? validateAscList : null),null);
   }

   if (!formParamsProvided) {
      if (addlParams.length > 0) addlParams += "&";
      addlParams += frm.serialize(); // get form fields and values in serialized form if calling routine dictates
   }

   if (validChange) {
      
      if ((String(url)).indexOf("?") > -1) {               // create complete url
         if (addlParams.length > 0) url += "&" + addlParams;
      } else {
         if (addlParams.length > 0) url += "?" + addlParams;
      }
         
      new Ajax.Request(url, {                              // using AJAX, run code at url
         method: 'post',
         onSuccess: function(transport) {                  // upon success
            var json = transport.responseJSON;
            if (json != null && assessJsonResponse(json, 'handleFormSubmit') == "success") {
               if (json.result.toUpperCase() == 'REDIRECT') {  // did response include a page redirection?
                  window.location=json.dest                // yes; call new page
               }
            } else {
               $('body_content').update(transport.responseText); // update container with ajax return
            }
         },
         onFailure: function (oXHR, oJson) {
            handleErr('C100', 'ZC100', sRAProg+".handleFormSubmit", sRAVers, "Failure: There has been an internal system failure.<br />Please contact your system administrator.<br />Status:  " + oXHR.status);
         },
         onException: function(request, err) {
            handleErr('C100', 'ZC101', sRAProg+".handleFormSubmit", sRAVers, "Exception: " + err.message + "<br/><br/>Resulting from the following:<br/>" + request.transport.responseText);
         }
      });
   }
}

//-----------------------------------------------------------

function handleReportRefresh (runUrl, refreshUrl) {

   // Purpose:   Since introducing the notion of a container within which all activity takes place for this system,
   //            this function uses AJAX to handle report processing refresh checking.  It relies on the rptPU global
   //            variable that is defined in main_menu_ajax.js due to its wider scope - it is defined and created when
   //            index.html is loaded and lives until, essentially, the user navigates outside of this system.
   //
   //            The Periodical Updater is created once and then started and stopped as necessary for a particular
   //            url defined.  This has NOT been tested with multiple reports running and may need to be modified 
   //            accordingly.
   //
   //            Failure and exceptions are handled via javascript alerts for lack of anything better right now, 
   //            though this might be revisited.
   //
   // Arguments: runUrl: The URL of the process to run continually to see if the report has completed.  URL can be absolute 
   //                    or relative and should include all parameters necessary for execution.
   //            refreshUrl: The URL of the process that will be run to refresh the screen once the process behind
   //                        runUrl deems the process for which it was waiting has completed
   //
   // Returns:   false

   var rptPU = null;
   var rqstId = null;
   var rptId = null;

   // The AJAX PeriodicalUpdater process requires, as a parameter, a div to update each time it executes.  Unfortunately,
   // this causes a container "blink" when the report is still processing since it's considered a "complete" and "success".
   // As such, the concept of a 'blackhole' (hidden div) is used to eliminate the "blink".  When the report check
   // is completed successfully, a DOM inspection is done and, if the report is complete, the container updates are done 
   // manually.

   if($('blackhole') == undefined) {                    // if the hidden div object has not been created already, do so
      var d = new Element('div', { 'id': 'blackhole', 'style': 'display:none;' });
      document.body.appendChild(d);
   }

   //need to uniquely identify a running report in order to ensure that the only page that is refreshed
   //corresponds to the report that just finished
   rqstId = runUrl.parseQuery().rqstid;
   rptId = "isrunning" + rqstId;

   if ($(rptId) != undefined) {$(rptId).update("Checking&hellip;&nbsp;&nbsp;")}  // indicate to the user that we are currently checking to see if report has completed
   rptPU = new Ajax.PeriodicalUpdater('blackhole', runUrl, {
      method: 'post',
      frequency: 3,
      decay: 1.02,
      onCreate: function() {
         if ($(rptId) != undefined) {$(rptId).update("Checking&hellip;&nbsp;&nbsp;");}  // this may be redundant; if so, remove the former, not this one
      },
      onSuccess: function(transport) {                  // when check completed successfully
         if ((String(transport.responseText)).indexOf("Processing") > -1) {  // is report still processing?
            if ($(rptId) != undefined) {$(rptId).update("Processing&hellip;&nbsp;&nbsp;");}  // if so, replace "checking" with "processing"
         } else if ((String(transport.responseText)).indexOf("Done") > -1) {            
            if ($(rptId) != undefined) {
               $(rptId).update("Done - refreshing page&hellip;&nbsp;&nbsp;");  // if not still processing, indicate done
               new Ajax.Updater({ success: "body_content", failure: "error" }, refreshUrl, {evalScripts: "true"});
//               initMenu(false);                            //update to reflect completion of running processes
            }
            rptPU.stop();                               // stop checking
         } else if ((String(transport.responseText)).indexOf("Login") > -1) {
            rptPU.stop();                               // stop checking
         } else {
            if (transport.responseText.length > 0) {
               var errObj = transport.responseText.evalJSON();
               errObj = errObj.result.parseQuery();
               handleErr(errObj.code, errObj.loc, errObj.prog, errObj.ver, "Error: :" + errObj.msg);
            } else {
               handleErr('C100', 'ZC102', sRAProg+".handleReportRefresh", sRAVers, "Error:  An unexpected null result occurred.");
            }
         }
      },
      onComplete: function(transport) {
//            alert('completed');
      },
      onFailure: function(transport) {
         handleErr('C100', 'ZC103', sRAProg+".handleReportRefresh", sRAVers, "Failure: " + transport.status);
      },
      onException: function(request, err) {
         handleErr('C100', 'ZC104', sRAProg+".handleReportRefresh", sRAVers, "Exception: " + err.message + "<br/><br/>Resulting from the following:<br/>" + request.transport.responseText);
      }
   });
   
   initMenu(false);                                        //update to reflect start of running processes
   return false;
}

//-----------------------------------------------------------

function cleanPU() {

   // Purpose:   if a periodicalupdater is running, simply stop it

   if (rptPU != null) {
      rptPU.stop();
   }
}

//-----------------------------------------------------------

function setTargets(a1, a2, d1, d2) {

   // Purpose:   given across1, across2, down1, down2 param values, highlight corresponding report target cells
   //
   // Returns:   nothing
   var aA1, aA2, aD1, aD2;
   var elem, params;
   var iBadCellCount = 0;

   if (a1 != null && a1.length > 0 && d1 != null && d1.length > 0) { //minimum requirement is a down1 and across1 value
      aA1 = a1.split(',');                                 //parse across1 values by comma
      aA2 = (a2 != null && a2.length > 0) ? a2.split(',') : new Array(aA1.length); //if exists, parse across2 values or create same sized empty array
      aD1 = d1.split(',');                                 //parse down 1 values by comma
      aD2 = (d2 != null && d2.length > 0) ? d2.split(',') : new Array(aD1.length); // if exists, parse down2 values or create same sized empty array

      //now that a1, a2, d1, d2 are parsed, put back together so we can identify 
      //the div to which the target cell is attributed and toggle it
      for (var i = 0; i < aD1.length; i++) {               //for each down1 value 
         elem = "tgt_"+aD1[i];                                    //start with down1
         if (aD2[i] != undefined && aD2[i].length > 0) { elem = elem + "_" + aD2[i]; } //if exists, concat down2
         elem = elem + "_" + aA1[i];                       //concat across1
         if (aA2[i] != undefined && aA2[i].length > 0) { elem = elem + "_" + aA2[i]; } //if exists, concat across2

         //extract the parameters from the href call that correspond to this 
         //DOM element identified by the div we just created
         if (elem.length > 4 && $(elem) != undefined) {                            //more than just base 'tgt_' in string
            params = $(elem).select('a')[0].href;
            params = params.substring(params.indexOf("','")+3,params.indexOf("');"));
            toggleCell(elem, params);                      //given the dom element we just identified, and params we extracted, toggle cell background
         } else {
            iBadCellCount += 1;
         }
      }
      if (iBadCellCount > 0) {
         handleErr('B105', 'ZC105', sRAProg+".setTargets", sRAVers, "Failure: " + iBadCellCount + " targeted cells is/are no longer relevant in this report");
      }
   }
}

//-----------------------------------------------------------

function saveForRecovery() {
   // Purpose:   This is an entirly behind-the-scenes process that saves (currently) report information every
   //            time a report is displayed in full on the page such that, if the session ends, the user can
   //            restore the point that they were at prior to the session ending
   // Arguments: none
   // Returns:   false
   
   //again the blackhole div will be used to catch response messages so the user doesn't have to be bothered
   //with them
   if($('blackhole') == undefined) {                       // if the hidden div object has not been created already, do so
      var d = new Element('div', { 'id': 'blackhole', 'style': 'display:none;' });
      document.body.appendChild(d);
   }

   //note: refresh=1 forces no screen gray-out/loading msg
   new Ajax.Updater({success: 'blackhole', failure: 'blackhole' }, 'recovery.asp?task=saveForRecovery&refresh=1', {evalScripts: 'true'});
   setTimeout("initMenu(false)",2000);                     //refresh menu after updating recovery lists
}

//-----------------------------------------------------------

function traceReportsRun() {

   // Purpose:   This is an entirly behind-the-scenes process that saves (currently) report information every
   //            time a report is requested to be run by a specific user so the user can view a report of 
   //            recently run reports.
   // Arguments: none
   // Returns:   false

   //again the blackhole div will be used to catch response messages so the user doesn't have to be bothered
   //with them
   if($('blackhole') == undefined) {                    // if the hidden div object has not been created already, do so
      var d = new Element('div', { 'id': 'blackhole', 'style': 'display:none;' });
      document.body.appendChild(d);
   }

   //note: refresh=1 forces no screen gray-out/loading msg
   new Ajax.Updater({success: 'blackhole', failure: 'blackhole' }, 'recovery.asp?task=traceReportsRun&refresh=1', {evalScripts: 'true'});
}

//-----------------------------------------------------------

function retrieveFromRecovery() {

   // Purpose:   This function will retrieve previously saved recovery information such that a (currently) report
   //            can be redisplayed just like it was prior to a session timeout
   // Arguments: none
   // Returns:   false

   var task = "getFromRecovery";
   var url;

   new Ajax.Request('recovery.asp?task=' + task, {
      method: 'post',
      evalJSON: 'force',
      requestHeaders: {Accept: 'application/json'},
      onSuccess: function(transport) { 
         var json = transport.responseJSON;
         if (assessJsonResponse(json, task) == "success") {
            url = "report.asp?" + json.result
            new Ajax.Updater({success: 'body_content', failure: 'error' }, url, {evalScripts: 'true'});
         }
      },
      onFailure: function(transport) { 
         handleErr('C100', 'ZC106', sRAProg+".retrieveFromRecovery", sRAVers, "Failure: " + transport.status);
      },
      onException: function(request, err) { 
         handleErr('C100', 'ZC107', sRAProg+".retrieveFromRecovery", sRAVers, "Exception: " + err.message + "<br/><br/>Resulting from the following:<br/>" + request.transport.responseText);
      }
   });
}

//-----------------------------------------------------------

function bRecordsToRecover() {
   // Purpose:   This function will determine if there are any records to recover
   //            and retrieve the previously saved recovery information such that the
   //            last viewed report in a prior session can be redisplayed just like
   //            it was prior to a session timeout
   // Arguments: none
   // Returns:   false or true depending on if there are records to recover

   var task = "getFromRecovery";

   new Ajax.Request('recovery.asp?task=' + task + '&refresh=1', {
      method: 'post',
      evalJSON: 'force',
      requestHeaders: {Accept: 'application/json'},
      onSuccess: function(transport) { 
         var json = transport.responseJSON;
         if (assessJsonResponse(json, task) == "success") {
            if (json.result.length > 0) { 
               recoverSession = true;
            } else { 
               recoverSession = false;
            }
         }
      },
      onFailure: function(transport) { 
         handleErr('C100', 'ZC108', sRAProg+".bRecordsToRecover", sRAVers, "Failure: " + transport.status);
      },
      onException: function(request, err) { 
         handleErr('C100', 'ZC109', sRAProg+".bRecordsToRecover", sRAVers, "Exception: " + err.message + "<br/><br/>Resulting from the following:<br/>" + request.transport.responseText);
      }
   });
}

//-----------------------------------------------------------

function abortReportProcessing(instance) {

   // Purpose:   This function will abort a running report and restore its original tables
   // Arguments: Report instance ("script_rqstid_") to abort
   // Returns:   false

   var task = "abortReportProcessing";
   var url;

   new Ajax.Request('abortReport.asp?inst=' + instance, {
      method: 'post',
      evalJSON: 'force',
      requestHeaders: {Accept: 'application/json'},
      onSuccess: function(transport) { 
         var json = transport.responseJSON;
         if (assessJsonResponse(json, task) == "success") {
             alert('Report processing has been cancelled.\nPrior results are being restored.\nThis may take a few minutes.');
         }
      },
      onFailure: function(transport) {
         handleErr('C100', 'ZC110', sRAProg+".abortReportProcessing", sRAVers, "Failure: " + transport.status);
      },
      onException: function(request, err) { 
         handleErr('C100', 'ZC111', sRAProg+".abortReportProcessing", sRAVers, "Exception: " + err.message + "<br/><br/>Resulting from the following:<br/>" + request.transport.responseText);
      }
   });
}

//-----------------------------------------------------------

function saveScrollTableEvents() {
   // Purpose: Temporarily save scroll table click events in order to reapply after scroll table manipulation
   //          Note that this only records those click events managed by Prototype, not simple onClick events
   var links = $('gridView').select('a[href="#"]');
   var storageInfo, regInfo, clickEvent, elemId;
   links.each(function(e) {                                //for each clickable link in the table
      elemId = e.readAttribute('id');
      storageInfo = Element.getStorage(elemId);            //check to see if anything stored for that element id
      if (storageInfo != undefined) {                      //if storage defined
         regInfo = storageInfo.get('prototype_event_registry'); //check to see if any events are actually registered
         if (regInfo != undefined) {                       //if events registered
            clickEvent = regInfo.get('click');             //check to see if a *click* event registered
            clickEvent.each(function(wrapper) {            //for each click event registered
               scrollTableEvents.set(elemId, wrapper.handler); //save it
            })
            e.stopObserving('click');                      //stop observing click event for now (restored lated)
         }
      }
   });
}

//-----------------------------------------------------------

function restoreScrollTableEvents() {
   var elemId;

   var gV__cNLinks = $('gridView__cN').select('thead a[href="#"]');
   gV__cNLinks.each(function(link) {
      if (link.id.substring(0,4) != "__cN") {
         link.id = "__cN" + link.id;
      }
   });

   var gV_CFHLinks = $('gridView_CFH').select('thead a[href="#"]');
   gV_CFHLinks.each(function(link) {
      if (link.id.substring(0,4) != "_CFH") {
         link.id = "_CFH" + link.id;
      }
   });

   var gV_CFBLinks = $('gridView_CFB').select('a[href="#"]');
   gV_CFBLinks.each(function(link) {
      if (link.id.substring(0,4) != "_CFB") {
         link.id = "_CFB" + link.id;
      }
   });
   
   var gV_Targets1 = $('report_content').select('[id^="tgt"]'); //get all target objects
   var gV_Targets2 = $('gridView').select('[id^="tgt"]');  //get all *original* target objects
   gV_Targets2.each(function(e) {                          //remove original target objects from list of all target objects
      gV_Targets1 = gV_Targets1.without(e);
   });
   gV_Targets1.each(function(e) {                          //rename remaining, non original target objects
      e.id = "X_" + e.id;
   });

   scrollTableEvents.each(function(pair) {
      if ($(pair.key))          { $(pair.key).observe('click', pair.value); }
      if ($("__cN" + pair.key)) { $("__cN" + pair.key).observe('click', pair.value); }
      if ($("_CFH" + pair.key)) { $("_CFH" + pair.key).observe('click', pair.value); }
      if ($("_CFB" + pair.key)) { $("_CFB" + pair.key).observe('click', pair.value); }
   });
}

// I'm not sure if this legacy functionality has been replicated in the new container-based
// system so I have not deleted it yet.
//handleReportLoad = function() {
//alert("report load");
//   disableAllStatusMsgs(); 
//   showAlertMsg();
//}

//handleReportUnload = function() {
//   var frm = Event.element(event);
//   if (formChanged(document.getElementById(frm))) {
//      return("Changes you made have NOT been saved, and will be lost.");
//   } else { 
//      disableInput(true); 
//      setTimeout("disableInput(false)",15000); 
//   }
//}

