function IsNull(o)
{
  return ("undefined" == typeof(o) || "unknown" == typeof(o) || null == o)
}

function IsArray(item)
{
  return item != null && ((item instanceof Array) || (typeof item.splice) == "function");
}

function RemoteCommandBase(sObject, sCommand, sWebServiceNamespace, sUrlBase)
{
  this.Command = sCommand;
  this.GetParameter = getParameter;
  this.ErrorHandler = RemoteCommandDefaultErrorHandler;

  var sXmlDocumentStart = "";
  var sXmlDocumentEnd = "";
  var oXmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
  var aParameters = new Array();
  var sCommandNamespace = sWebServiceNamespace;
  if (IsNull(sUrlBase))
  {
    //sUrlBase = "http://localhost:49596/MP2.Net/";
    //alert (document.location.href.substring (0,document.location.href.lastIndexOf("/")+1));
    // strip off any querystring 
    var iIndexOfQuestionMark = document.location.href.indexOf("?");
    sUrlBase = ((iIndexOfQuestionMark > 0) ? document.location.href.substring (0,iIndexOfQuestionMark) : document.location.href);
    
    sUrlBase = sUrlBase.substring (0,sUrlBase.lastIndexOf("/")+1);
    
    // assuming that the last "section" of sUrlBase is a module name ... let's strip it off
    //if((document.location.href.toLowerCase().indexOf("default.aspx")<0)&&(document.location.href.toLowerCase().indexOf("mvmain.aspx")<0)&&(document.location.href.toLowerCase().indexOf("mvevents.aspx")<0)&&(document.location.href.toLowerCase().indexOf("cmhealth.aspx")<0)&&(document.location.href.toLowerCase().indexOf("sensorlist.aspx")<0))
    //{
    //    sUrlBase = sUrlBase.substring (0,sUrlBase.substring(0, sUrlBase.length-1).lastIndexOf("/")+1);
    //}
  }
    //alert (sUrlBase);
  //var sUrl = sUrlBase + sObject + ".asmx?mp2session=" + g_sSessionId;
  var sUrl=sUrlBase+sObject+".asmx";
  this.Url = sUrl;

  sXmlDocumentStart += "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"

  sXmlDocumentStart += "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">";
  sXmlDocumentStart += "<soap:Body>"

  sXmlDocumentStart += "<" + sCommand + " xmlns=\"" + sCommandNamespace + "\">"

  sXmlDocumentEnd += "</" + sCommand + ">";
  sXmlDocumentEnd += "</soap:Body>";
  sXmlDocumentEnd += "</soap:Envelope>";

  this.Execute = execute;
  this.SetParameter = setParameter;
  this.Abort = abort;

  function getParameter(sName)
  {
    var i = aParameters[sName];
    if (!IsNull(i))
    {
      return aParameters[i];
    } 
    return null;
  }

  function setParameter(sName, sValue)
  {
    /*var oParameter = (IsNull(sValue))? sName : new CommandParameter(sName, sValue);
    if (!IsNull(aParameters[oParameter.Name]))
    {
      aParameters[aParameters[oParameter.Name]] = oParameter;
    }
    else
    {
      aParameters[oParameter.Name] = aParameters.length;
      aParameters.push(oParameter);
    }*/
    
    if (!IsNull (sValue))
    {
        // do we need a CDATA tag?
        if ((typeof (sValue) == "string") && (sValue.substr (0, 9) != "<![CDATA["))
        {
            // do we have any "special" characters (ampersand, quot, less than, or greater than)?
            if ((sValue.indexOf ("&") >= 0) || (sValue.indexOf ("\"") >= 0) || (sValue.indexOf ("<") >= 0) || (sValue.indexOf (">") >= 0))
            {
                sValue = "<![CDATA[" + sValue + "]]>"; 
            }
        }
    
        var oParameter = new CommandParameter(sName, sValue);
        aParameters[oParameter.Name] = oParameter;
    
    }
  }
  
  function abort()
  {
    oXmlHttp.abort();
  }

  function execute(funAsyncCallbackFunction, oData1, oData2)
  {
  //alert ('exec: ' + arguments.length);
    var sXmlDocument = sXmlDocumentStart;

    if (oXmlHttp.readyState > 0 && oXmlHttp.readyState < 4)
    {
      abort();
    }

    //for (var i = 0; i < aParameters.length; i++)
    for (sParameter in aParameters)
    {
      sXmlDocument += aParameters[sParameter].GetXml();
    }
    sXmlDocument += sXmlDocumentEnd;
    var async = !IsNull(funAsyncCallbackFunction);
    if (async)
    {
      var oAsyncResultHandler = new AsyncResultHandler(this, oXmlHttp, funAsyncCallbackFunction, oData1, oData2);
      oXmlHttp.onreadystatechange = oAsyncResultHandler.ReadyStateChanged;
    }

//sXmlDocument = '<?xml version="1.0" encoding="utf-8" ?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><GetPageOfData xmlns="http://tempuri.org/MP2.Net/GridService"><sTableName>EMP</sTableName><sColumnList>FACILITYCODE,EMPCODE,LASTNAME,FIRSTNAME,SHIFT,CRAFT,CREW,CLASS,SENIORITY,SKILLLEVEL,ACCUMSICKHRS,ACCUMVACHRS,HIREDATE,RAISEDATE,SOCSECNUM,ADDR1,ADDR2,ADDR3,CITY,STATE,ZIP,PHONE,NOTES</sColumnList><sSort>FACILITYCODE ASC,EMPCODE ASC</sSort><sFilter><![CDATA[dbo.EMP.FACILITYCODE IN (%ACTIVE%)]]></sFilter><sNamedFilter></sNamedFilter><sJoins><![CDATA[]]></sJoins><iStartIndex>68</iStartIndex><iEndIndex>122</iEndIndex></GetPageOfData></soap:Body></soap:Envelope>';
    oXmlHttp.Open("POST", sUrl, async);
    oXmlHttp.setRequestHeader("SOAPAction", sCommandNamespace + "/" + sCommand);
    oXmlHttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    oXmlHttp.setRequestHeader("Content-Length", sXmlDocument.length);
    oXmlHttp.setRequestHeader("Authorization", "None"); // added 6/14/07 to try and fix intermittent problem on some GP machines (blank error that popped up)
    
//alert (sUrl + " -> " + sXmlDocument);    
    oXmlHttp.Send(sXmlDocument);
    if (!async)
    {
      //TODO/GOLD - change hourglass to loading image...
      document.body.style.cursor = 'wait';  
      var bReturn = new RemoteCommandResult(this, oXmlHttp);
      document.body.style.cursor = 'default';
      return bReturn;
    }
  }
  
    
}
  
  
      function AsyncResultHandler(oRemoteCommand, oXmlHttp, funCallback, oData1, oData2)
    {
      this.ReadyStateChanged = readyStateChanged;
      
      function readyStateChanged()
      {
        if (oXmlHttp.readyState == 4)
        {
            // 5/16/2008 - There appears to be a very strange thing going on with remotecommands in general ... and this seems to a behavior of the XMLHTTP object ...
            //   ... if we start an asynchronous call with one XMLHTTP object ... and then, before that asynchronous call finishes (before it calls 
            //       readyStateChanged with a readyState of 4) another, synchronous call is executed ... the ".Send" call of the second one blocks 
            //       (which we'd expect) ... but then the strange thing is that if the asynchronous call finishes first ... the readyStateChanged
            //       event of the asynchronous call is fired "within" the synchronous call 
            //           - This type of call stack ends up being pretty common in MP2.Net 
            // 5/16/2008 - I have worked around this issue and gotten the "internal" firing of readyStateChanged "out" by calling setTimeout
            setTimeout (readyStateChangeComplete,1);
        }
      }
      
      function readyStateChangeComplete()
      {
        //if (oXmlHttp.readyState == 4)
        {
          // have we gotten back HTML instead of our expected result? (this can occur if the forms authentication ticket has
          //  timed out ... the server will respond the original "post" that we sent with the various redirects that occur
          //  for forms authentication ... and the entire forms authentication process ends up redirecting back to our original
          //  .asmx request ... but we end up doing a "GET" instead of a "POST".  We want to catch this situation and "re" post
          // 
          if ((oXmlHttp.status == 200) && (oXmlHttp.responseText.substring (0, 10).indexOf ("<html>") >= 0))
          {
            window.status = window.status + 'detected 200 ... initiating retry';
            oXmlHttp.abort ();
            oRemoteCommand.Execute (funCallback, oData1, oData2);
            return;
          }
          // REG - Working with Dave, we saw 12029 occur at GP on 7/8/08
          if (oXmlHttp.status == 12029) // 12029 = ERROR_INTERNET_CANNOT_CONNECT / The attempt to connect to the server failed
          {
            window.status = window.status + 'detected 12029 ... initiating retry';
            oXmlHttp.abort ();
            oRemoteCommand.Execute (funCallback, oData1, oData2);
            return;
          }
          if (oXmlHttp.status == 12030) // 12030 = ERROR_INTERNET_CONNECTION_ABORTED / The connection with the server has been terminated
          {
            window.status = window.status + 'detected 12030 ... initiating retry';
            oXmlHttp.abort ();
            oRemoteCommand.Execute (funCallback, oData1, oData2);
            return;
          }
          if (oXmlHttp.status == 12031) // 12031 = ERROR_INTERNET_CONNECTION_RESET / The connection with the server has been reset
          {
            window.status = window.status + 'detected 12031 ... initiating retry';
            oXmlHttp.abort ();
            oRemoteCommand.Execute (funCallback, oData1, oData2);
            return;
          }
        
          if (oXmlHttp.status != 0)
          {
            var result = new RemoteCommandResult(oRemoteCommand, oXmlHttp);
            
            // 7/26/07 - Added try/catch ... issue occurred when running a "long" report ... and closing the report viewer before the report finished running 
            // 10/3/07 - Uncommented try/catch ... it was masking other errors that were occurring ... and the 7/26/07 issues doesn't seem to happen anymore
            //try
            //{
                funCallback(result, oData1, oData2);
            //}
            //catch (e)
            //{
            //}

            oXmlHttp.abort();
          }
        }
      }
    }

  
function RemoteCommandDefaultErrorHandler(sHResult, oXmlNode)
{
  //var sUrl = "/_common/error/dlg_error.aspx?hresult=";
  var sUrl = "SYS/Error.aspx?hresult=";

  if (sHResult == null)
  {
    sHResult = "Not available";
  }
  sUrl += sHResult;
  if ((oXmlNode != null) && (typeof(oXmlNode.selectSingleNode)!="undefined"))
  {
    //var oDescription = oXmlNode.selectSingleNode("error/description");
    var oDescription = oXmlNode.selectSingleNode("faultstring");
/*    if (!IsNull(oDescription))
    {
       // sLastErrorString = oDescription.text;
      //sUrl += "&errMessage=" + encodeURIComponent(oDescription.text);
      //sUrl += "&errMessage=" + encodeURI(oDescription.text);
      if (oDescription.text.length > 1950)
      {
        sUrl += "&errMessage=" + escape(oDescription.text).substring (0, 1950) + " ...";
      }
      else
      {
        sUrl += "&errMessage=" + oDescription.text;
      }
    }*/
  }
  
  if (typeof(PopupWindow) != "undefined")
  {
    PopupWindow(sUrl, null, null, null, (oDescription != null) ? oDescription.text : oXmlNode);
  }
  else
  {
      alert((oDescription!=null)?oDescription.text:oXmlNode.responseText);
  }
  //alert ('RemoteCommandDefaultErrorHandler:' + sUrl);
  //openStdDlg(sUrl, null, 400, 200);
}
  
  

  
function CommandParameter(sName, sValue)
{
  this.Name = sName;
  this.Value = sValue;

  this.GetXml = getParameterXml;

  function getParameterXml()
  {
    var sXml = "<" + this.Name + ">";
    if (IsArray(this.Value))
    {
      var sType = this.Value.type;
      if (IsNull(sType) && this.Value.length > 0)
      {
        sType = "object";
      }
      for (var i = 0; i < this.Value.length; i++)
      {
        sXml += "<" + sType + ">" + this.Value[i] + "</" + sType + ">";
      }
    }
    else
    {
      sXml += this.Value;
    }
    sXml += "</" + this.Name + ">";
    return sXml;
  }
}


function RemoteCommandResult(oRemoteCommand, oXmlHttp)
{
  var sCommand = oRemoteCommand.Command;
  var oXml = oXmlHttp.responseXML;
  var sNamespace = "";
  if (oXml.childNodes.length > 0)
  {
    sNamespace = oXml.childNodes[oXml.childNodes.length - 1].prefix + ":";
  }

  this.RemoteCommand = oRemoteCommand;
  this.RawResponse = oXml;
  this.Xml = oXml.selectSingleNode("/" + sNamespace + "Envelope/" + sNamespace + "Body/" + sCommand + "Response/" + sCommand + "Result");
  this.ReturnValue = ReadXml(this.Xml);
  this.Success = handleSoapResponse(oXmlHttp, this.RemoteCommand);
  this.ConvertToObject = ReadXml;
  
  function handleSoapResponse(oXmlHttp, oRemoteCommand)
  {
    var sHResult = null;
    var oXmlNode = null;
    var oErrorNode;
    var bSuccess = true;
    var oXml = oXmlHttp.responseXML;
    var sNamespace = "";
    if (oXml.childNodes.length > 0)
    {
      sNamespace = oXml.childNodes[oXml.childNodes.length - 1].prefix + ":";
    }

    if (oXml.parseError.errorCode != 0)
    {
      sHResult = "XmlParseError";
      bSuccess = false;
    }
    else if (oXmlHttp.status != 200)
    {
      oXmlNode = oXml.selectSingleNode("/" + sNamespace + "Envelope/" + sNamespace + "Body/" + sNamespace + "Fault");
      if (oXmlNode)
      {
        //oErrorNode = oXmlNode.selectSingleNode("error/code");
        oErrorNode = oXmlNode.selectSingleNode("faultcode");
        if (!IsNull(oErrorNode))
        {
          sHResult = oErrorNode.text;
        }
      }
      else
      {
        sHResult = "ServerError " + oXmlHttp.status + " calling command " + oRemoteCommand.Command + " at " + oRemoteCommand.Url // + " (" + oXmlHttp.statusText + ")"; // + oXmlHttp.responseText ;
        //oXmlNode = oXmlHttp;
        oXmlNode = new Object ();
        oXmlNode.responseText = oXmlHttp.responseText;
      }

      bSuccess = false;
    }
    
    if (bSuccess)
    {
      oXmlNode = oXml.selectSingleNode("/" + sNamespace + "Envelope/" + sNamespace + "Body/" + sCommand + "Response");
      if (IsNull(oXmlNode))
      {
        alert ('debugging code - soaperror ... response text will follow ...');
        //alert (oXml.text);
        alert (oXmlHttp.responseXML.text);
        sHResult = "SoapError";
        bSuccess = false;
      }
    }

    if (!bSuccess)
    {
      if (oRemoteCommand.ErrorHandler)
      {
        oRemoteCommand.ErrorHandler(sHResult, oXmlNode);
      }
    }

    return bSuccess;
  }
  
  function ReadXml(oXml)
  {
    var oReturnValue = new Object();
    if (IsNull(oXml))
    {
      return oReturnValue;
    }
    
    var childNodes = oXml.childNodes;
    for (var i = 0; i < childNodes.length; i++)
    {
      var oChildNode = childNodes.item(i);
      switch (oChildNode.nodeType)
      {
        case 1:
          var oChildObject = ReadXml(oChildNode);
          if (IsNull(oReturnValue[oChildNode.baseName]))
          {
            oReturnValue[oChildNode.baseName] = oChildObject;
          }
          else
          {
            if (!IsArray(oReturnValue[oChildNode.baseName]))
            {
              var property = oReturnValue[oChildNode.baseName];
              oReturnValue[oChildNode.baseName] = new Array();
              oReturnValue[oChildNode.baseName].push(property);
            }

            oReturnValue[oChildNode.baseName].push(oChildObject);
          }
          break;
          
        case 3:
          return fromString(oChildNode.nodeValue);
          
        case 4:
          return oChildNode.text;
          
        default:
          break;
      }
    }

    if (IsNull(oReturnValue.xmlAttributes))
    {
      var attributes = oXml.attributes;
      if (attributes.length > 0)
      {
        oReturnValue.xmlAttributes = new Object();
        for (var i = 0; i < attributes.length; i++)
        {
          oReturnValue.xmlAttributes[attributes.item(i).baseName] = fromString(attributes.item(i).nodeValue);
        }
      }
    }

    return oReturnValue;
  }

  function fromString(sValue)
  {
    if (sValue.toLowerCase() == "true")
    {
      return true;
    }
    else if (sValue.toLowerCase() == "false")
    {
      return false;
    }

    var intValue = parseInt(sValue, 10);
    if (!isNaN(intValue) && intValue.toString() == sValue)
    {
      return intValue;
    }

    var floatValue = parseFloat(sValue);
    if (!isNaN(floatValue) && floatValue.toString() == sValue)
    {
      return floatValue;
    }

    var dateValue = new Date(sValue);
    if (!isNaN(dateValue))
    {
      return dateValue;
    }

    return sValue;
  }
}
