/*  ************************ Object/functions ***********************

   Object - SOAPClientParameters
    Properties: _pl - Array object of SOAP parameters
    Methods: Add(name, value) - Add a new parameters
             toXml() - Convert the object's parameters into XML
   Object - SOAPClient
    Methods: invoke(url, method, parameters, async, callback)
             _sendSoapRequest(url, method, parameters, async, callback, wsdl)
             _onSendSoapRequest(method, async, callback, wsdl, req)
             _getElementsByTagName(document, tagName, bKeepTagName)
             _deleteElementsByTagName(strIn, tagName) - Delete a tag by name
             _getAttributByName(line, Name) - Return an attritube by name
             _getXmlHttp()
             _serialize(obj) - Create the XML for one parameter
             getValuesByTagName(xmlDoc, tagName) - Return the value for a tag
             _cleanElementByName(line, Name) - Return the value between the tags

// requestNSNInfo() - Request NSN Info from CPS
// loadCPSNSNData() - Package the CPS NSN data into an object and return it
// requestCAGEInfo() - Request CAGE Info from CPS
// loadCPSCAGEData() - Package CPS' CAGE data into an object and return it

    ***************************************************************** */


// Create the SOAPClientParameters object as:
//  Properties: _pl - Array object of SOAP parameters
//  Methods: Add(name, value) - Add a new parameters
//           toXml() - Convert the object's parameters into XML
//           _serialize(obj) - Create the XML for one parameter
function SOAPClientParameters()
{
	var _pl = new Array();

    //  Method - Add(name, value) - Add a new parameters
	this.add = function(name, value)
	{
		_pl[name] = value;
		return this;
	}

    //  Method - toXml() - Convert the object's parameters into XML
	this.toXml = function()
	{
		var xml = "";
		for(var p in _pl)
			xml += '    <' + p + ' xsi:type="xsd:string">' + SOAPClientParameters._serialize(_pl[p]) + '</' + p + '>\n';
		return xml;
	}
}

//  Method - _serialize(obj) - Create the XML for one parameter
SOAPClientParameters._serialize = function(o)
{
    var s = "";
    switch(typeof(o))
    {
        case "string":
            s += o.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"); break;
        case "number":
        case "boolean":
            s += o.toString(); break;
        case "object":
            // Date
            if(o.constructor.toString().indexOf("function Date()") > -1)
            {

                var year = o.getFullYear().toString();
                var month = (o.getMonth() + 1).toString(); month = (month.length == 1) ? "0" + month : month;
                var date = o.getDate().toString(); date = (date.length == 1) ? "0" + date : date;
                var hours = o.getHours().toString(); hours = (hours.length == 1) ? "0" + hours : hours;
                var minutes = o.getMinutes().toString(); minutes = (minutes.length == 1) ? "0" + minutes : minutes;
                var seconds = o.getSeconds().toString(); seconds = (seconds.length == 1) ? "0" + seconds : seconds;
                var milliseconds = o.getMilliseconds().toString();
                var tzminutes = Math.abs(o.getTimezoneOffset());
                var tzhours = 0;
                while(tzminutes >= 60)
                {
                    tzhours++;
                    tzminutes -= 60;
                }
                tzminutes = (tzminutes.toString().length == 1) ? "0" + tzminutes.toString() : tzminutes.toString();
                tzhours = (tzhours.toString().length == 1) ? "0" + tzhours.toString() : tzhours.toString();
                var timezone = ((o.getTimezoneOffset() < 0) ? "+" : "-") + tzhours + ":" + tzminutes;
                s += year + "-" + month + "-" + date + "T" + hours + ":" + minutes + ":" + seconds + "." + milliseconds + timezone;
            }

            // Array
            else if(o.constructor.toString().indexOf("function Array()") > -1)
            {
                for(var p in o)
                {
                    if(!isNaN(p))   // linear array
                    {
                        (/function\s+(\w*)\s*\(/ig).exec(o[p].constructor.toString());
                        var type = RegExp.$1;
                        switch(type)
                        {
                            case "":
                                type = typeof(o[p]);
                            case "String":
                                type = "string"; break;
                            case "Number":
                                type = "int"; break;
                            case "Boolean":
                                type = "bool"; break;
                            case "Date":
                                type = "DateTime"; break;
                        }
                        s += "<" + type + ">" + SOAPClientParameters._serialize(o[p]) + "</" + type + ">"
                    }
                    else    // associative array
                        s += "<" + p + ">" + SOAPClientParameters._serialize(o[p]) + "</" + p + ">"
                }
            }

            // Object or custom function
            else
                for(var p in o)
                    s += "<" + p + ">" + SOAPClientParameters._serialize(o[p]) + "</" + p + ">";
            break;
        default:
            throw new Error(500, "SOAPClientParameters: type '" + typeof(o) + "' is not supported");
    }
    return s;
}

// Create the SOAPClient object
function SOAPClient() {}

// sendSoapRequest() - Send the soap request
SOAPClient._sendSoapRequest = function(url, method, parameters, async, callback, wsdl)
{

	// build SOAP request
  	var sr =
      '<?xml version="1.0" encoding="utf-8"?>\n' +
      '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" ' +
      'SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" ' +
      'xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" ' +
      'xmlns:xsd="http://www.w3.org/1999/XMLSchema">\n' +
  	  '<SOAP-ENV:Body>\n' +
  	  '<' + method + '> \n' +
  	  parameters.toXml() +
  	  '</' + method + '> \n' +
  	  '</SOAP-ENV:Body>\n' +
  	  '</SOAP-ENV:Envelope>';
    var nSRLength = sr.length;

	// send request
    var xmlHttp = SOAPClient._getXmlHttp();
    if (!xmlHttp)   {
        return false;
    }

    // Check for the browser type
    xmlHttp.open("POST", url, async);

    // Keep going
	xmlHttp.setRequestHeader("SOAPAction", url + '.' + method);
	xmlHttp.setRequestHeader("Content-Type", "text/xml");
	xmlHttp.setRequestHeader("Content-Length", nSRLength);
	if(async)
    {
        xmlHttp.onreadystatechange = function()
        {

            // 0 (uninitialized)
            // 1 (loading)
            // 2 (loaded)
            // 3 (interactive)
            // 4 (complete)
            if(xmlHttp.readyState == 4 && xmlHttp.status == 200)    {
                if (xmlHttp.responseText)   {
			        	SOAPClient._onSendSoapRequest(method, async, callback,
			        	  wsdl, xmlHttp);
                }
            }
		}
	}

    // Send it
	xmlHttp.send(sr);
	if (!async)  {
		return SOAPClient._onSendSoapRequest(method, async, callback, wsdl, xmlHttp);
    }
}

// _onSendSoapRequest() - Act on the return XML
SOAPClient._onSendSoapRequest = function(method, async, callback, wsdl, req)
{

    // Start the value we need
	var o = null;
  	var nd = SOAPClient._getElementsByTagName(req.responseText, method + "Response", true);
    if (Empty(nd))  {
        nd = req.responseText;
    }

    // the cal function to create the new page
	if(callback)
		callback(nd);
	if(!async)
		return o;
}

// _getElementsByTagName() - Retrive one Element in the XML
SOAPClient._getElementsByTagName = function(strIn, tagName, bKeepTagName)  {

    // Start with the value we need
    var cValue = '';
    var nStCol = strIn.StrAt('<' + tagName);
    var nEdCol = strIn.StrAt('</' + tagName);

    // Must have both a Starting and Ending position number
    if ((nStCol> 0 ) && (nEdCol > 0))  {

        // Extract the tag and all of its contents
        var nEdTagLen = tagName.length + 3;
        var nTotLen = (nEdCol + nEdTagLen) - nStCol;
        cValue = strIn.Substr(nStCol, nTotLen)

        // If we're to remove the tags, do so
        if (!bKeepTagName)  {
            var nStEdCol = cValue.StrAt('>');
            cValue = cValue.Substr(nStEdCol+1);
            nEdCol = cValue.StrAt('</' + tagName);
            cValue = cValue.Left(nEdCol-1);
        }
    }

    // Done
	return cValue;
}

//  _deleteElementsByTagName() - Delete a tag by name
SOAPClient._deleteElementsByTagName = function(strIn, tagName)  {

    // Start with the value we need
    var cValue = strIn;
    var nStCol = strIn.StrAt('<' + tagName);
    var nEdCol = strIn.StrAt('</' + tagName);

    // Must have both a Start and End number
    if ((nStCol> 0 ) && (nEdCol > 0))  {

        // Find the end >.  There could be attributes.
        var nEdLen = tagName.length+3;

        // Now get the value
        if (nStCol == 1)  {
            var nTotLen = nEdCol + cEdLen;
            cValue = strIn.Substr(nTotLen)
        }  else  {

            // Keep the beginning
            var cBeg = strIn.Left(nStCol-1);

            // Find the end of the string
            var cEnd = strIn.Substr(nEdCol + nEdLen);

            // Put it back together
            cValue = cBeg + cEnd;
        }
    }

    // Done
	return cValue;
}

//  _getAttributByName() - Return an attritube by name
SOAPClient._getAttributByName = function(line, Name)  {

    // Start with the value we need
    var cValue = '';
    var cSrchName = " " + Name + '="';
    var nStCol = line.StrAt(cSrchName);

    // Only if we have something
    if (nStCol > 0)  {

        // ie:  Rule="8"
        var chopPosn = nStCol + cSrchName.length;
        line = line.Substr(chopPosn);

        // Find the end '"'
        var nEdCol = line.StrAt('"');
        if (nEdCol > 0)  {
            cValue = line.Left(nEdCol-1);
        }
    }

    // Done
	return cValue;
}

// private: xmlhttp factory
SOAPClient._getXmlHttp = function()
{

    // Mozilla, Safari, ...
    if (window.XMLHttpRequest)  {
        req = new XMLHttpRequest();
        if (req.overrideMimeType) {
            req.overrideMimeType("text/xml");
        }
        bIsIE = false;

    // IE
    } else if (window.ActiveXObject)  {
        try  {
            req = new ActiveXObject("Msxml2.XMLHTTP");
        } catch (e) {
            try {
                req = new ActiveXObject("Microsoft.XMLHTTP");
            } catch (e) {}
        }
        bIsIE = true;
    }

    // Somthing is wrong
    if (!req) {
        alert("Giving up: ( Cannot create an XMLHTTP instance )");
        return false;
    }
    return req;
}

// getValuesByTagName() - Return the value for a passed tag
SOAPClient.getValuesByTagName = function(xmlDoc, tag)   {
    var xmlText = this._getElementsByTagName(xmlDoc, tag, false);

    // Remove the CDATA tag if it starts this
    var cdataPosn = xmlText.StrAt("<![CDATA[");
    if (cdataPosn==1)   {
        xmlText = xmlText.Substr(cdataPosn + 9);
        cdataPosn = xmlText.StrAt("]]>");
        xmlText = xmlText.Left(cdataPosn - 1);
    }
    return xmlText;
}

// _cleanElementByName() - Return the value between the tags
SOAPClient._cleanElementByName = function(line, Name)  {

    // Start with the value at the end of the first tag
    var nStEdCol = line.StrAt('>');
    line = line.Substr(nStEdCol+1);

    // Find the beginning of the last tag
    var nEdCol = line.StrAt('<');
    var cValue = line.Left(nEdCol - 1);

    // Done
	return cValue;
}

// requestNSNInfo() - Request NSN Info from CPS
var finalNSNCallback = null;        // Our ultimate callback function
var cpsNSNData = null;
function requestNSNInfo(cNSN, funcCallback) {
    finalNSNCallback = funcCallback;
    if (cNSN.length > 0) {
        var url = "cps/svc/GetBasicNSNInfo.wwsoap";
        if (window.location.href.Left(12) == 'http://local')  {
            url = "http://localhost/" + url;
        }  else  {
            url = "http://www.alicorp.com/" + url;
        }
        var pl = new SOAPClientParameters();
        var cKey1 = "%DF%96%9D%AF%AF%9C%93%8A%B2%DF";
        var cKey2 = "%DF%A9%BE%B1%B4%DF%AD%B2%BA%DF";
        pl.add("cLogin", cKey1);
        pl.add("cPassword", cKey2);
        pl.add("cNSNOrPN", cNSN);
	    SOAPClient._sendSoapRequest(url, "GetBasicNSNInfo", pl, true,
	      loadCPSNSNData, null);
    }
    return true;
}

// loadCPSNSNData() - Package the CPS NSN data into an object and return it
function loadCPSNSNData(cXML)  {

    // The return object has these properties:
    //  .cDispNSN  - display version of NSN
    //  .cItemName - Item Name
    //  .cNotes    - Any notes for the NSN
    //  .mcrlRA    - Array object (1-based) of MCRL data objects formatted as:
    //                  .cCAGE     - CAGE Code
    //                  .cCageName - Company Name for CAGE
    //                  .cPartNum  - Part No.
    //                  .cCageRN   - RN

    // Clean up the XML
    var cClnXML = cXML.StrTran('&lt;','<');
    cClnXML = cClnXML.StrTran('&gt;','>');

    // We may have an error
    if (cClnXML.length == 0 || cClnXML.StrAt("Invalid") > 0 ||
      cClnXML.StrAt("info not found") > 0)   {
        return;
    }

    // Extract the values into an object
    var nsnInfo = new Object();
    nsnInfo.cDispNSN = SOAPClient.getValuesByTagName(cClnXML, 'DispNSN');
    nsnInfo.cItemName = SOAPClient.getValuesByTagName(cClnXML, 'ItemName');
    nsnInfo.cNotes = SOAPClient.getValuesByTagName(cClnXML, 'Notes');
    if (nsnInfo.cNotes.length > 0)  {
        nsnInfo.cNotes = "Note: " + nsnInfo.cNotes;
    }

    // Add an MCRL array object
    var tblXML = SOAPClient._getElementsByTagName(cClnXML, 'MCRLTable', true);
    var numRows = SOAPClient._getAttributByName(tblXML, 'tblRows');
    var mcrlRA = new Array();

    // Add all of the MCRL lines to the array
    var tblXML = SOAPClient.getValuesByTagName(tblXML, 'MCRLTable');
    for (var i=1; i <= numRows; i++)    {
        var rowXML = SOAPClient._getElementsByTagName(tblXML, 'SingleMfr', false);
        tblXML = SOAPClient._deleteElementsByTagName(tblXML, 'SingleMfr');

        // Each MCRL line is its own object
        var mcrlObj = new Object();
        mcrlObj.cCAGE = SOAPClient.getValuesByTagName(rowXML, 'CAGECode');
        var cageName = SOAPClient.getValuesByTagName(rowXML, 'Name');
        if (cageName.length > 25)   {
            cageName = cageName.Left(25);
        }
        mcrlObj.cCageName = cageName;
        mcrlObj.cPartNum = SOAPClient.getValuesByTagName(rowXML, 'PartNum');
        mcrlObj.cCageRN = SOAPClient.getValuesByTagName(rowXML, 'RN');

        // Add this object to the array
        mcrlRA[i].mcrlObj = mcrlObj;
    }

    // Add the MCRL object to our overall NSN info object
    nsnInfo.mcrlRA = mcrlRA

    // Pass this onto the final callback function
    finalNSNCallback(nsnInfo);
}

// requestCAGEInfo() - Request CAGE Info from CPS
var finalCAGECallback = null;        // Our ultimate callback function
var cpsCAGEData = null;
function requestCAGEInfo(cCAGE, funcCallback) {
    finalCAGECallback = funcCallback;
    if (cCAGE.length > 0) {
        cCAGE = cCAGE.toUpperCase();
        var url = "cps/svc/GetCAGEInfo.wwsoap";
        if (window.location.href.Left(12) == 'http://local')  {
            url = "http://localhost/" + url;
        }  else  {
            url = "http://www.alicorp.com/" + url;
        }
        var pl = new SOAPClientParameters();
        var cKey1 = "%DF%96%9D%AF%AF%9C%93%8A%B2%DF";
        var cKey2 = "%DF%A9%BE%B1%B4%DF%AD%B2%BA%DF";
        pl.add("cLogin", cKey1);
        pl.add("cPassword", cKey2);
        pl.add("cCage", cCAGE);
	    SOAPClient._sendSoapRequest(url, "GetCAGEInfo", pl, true,
	      loadCPSCAGEData, null);
    }
    return true;
}

// loadCPSCAGEData() - Package CPS' CAGE data into an object and return it
function loadCPSCAGEData(cXML)  {

    // The return object has these properties:
    //  .cCAGE
    //  .cName
    //  .cADDR1
    //  .cADDR2
    //  .cCITY
    //  .cSTATE
    //  .cZIP
    //  .cPhone
    //  .cFax

    // Clean up the XML
    var cClnXML = cXML.StrTran('&lt;','<');
    cClnXML = cClnXML.StrTran('&gt;','>');

    // We may have an error
    if (cClnXML.length == 0 || cClnXML.StrAt("Invalid") > 0 ||
      cClnXML.StrAt("not in ALI's files") > 0)   {
        return;
    }

    // Extract the values into an object
    var cageInfo = new Object();
    cageInfo.cCAGE = SOAPClient.getValuesByTagName(cClnXML, 'CAGE');
    cageInfo.cName  = SOAPClient.getValuesByTagName(cClnXML, 'Name');
    cageInfo.cADDR1 = SOAPClient.getValuesByTagName(cClnXML, 'ADDR1');
    cageInfo.cADDR2 = SOAPClient.getValuesByTagName(cClnXML, 'ADDR2');
    cageInfo.cCITY  = SOAPClient.getValuesByTagName(cClnXML, 'CITY');
    cageInfo.cSTATE = SOAPClient.getValuesByTagName(cClnXML, 'STATE');
    cageInfo.cZIP   = SOAPClient.getValuesByTagName(cClnXML, 'ZIP');
    cageInfo.cPhone = SOAPClient.getValuesByTagName(cClnXML, 'Phone');
    cageInfo.cFax   = SOAPClient.getValuesByTagName(cClnXML, 'Fax');

    // Pass this onto the final callback function
    finalCAGECallback(cageInfo);
}
