/*
Active Element Architecture framework
-------------------------------------

This file contains the base class definitions for the Active Element Architecture, and also a
starter function which can be used to create the highest level object instance which controls
all the objects on a page.

An active element (AE) is an HTML node the content for which is maintained by an instance of an object
which is a descendant of the activeElement class.  AEs are invoked through an extension to the attributes
of the HTML language.

Several elements on a page can be maintained by a single AE, if their content needs to be identical
and this can save on processing time or time waiting for a server request to complete.

An AE can have child AEs, if it needs to control them as a related set of AEs.  In such a case
the parent AE will initially update the HTML of the connected node, and then create and attach
the child nodes to elements within the updated HTML.  After that it will not update the HTML directly
but through calls to the child nodes which will update their part of the DOM.

activeElement is defined below:

Properties:

- AE_AEid:
- AE_screenName:
- AE_paramList:
- AE_type:
- AE_title:
- AE_controlledAE_List:
- AE_controlledAE_Count:
- AE_HTML_NodeList:
- AE_HTML_NodeCount:

Methods:

- aeParseDOM(): Looks for AEs under current HTML node.
- aeAddControlledAE(pAE): Add AE reference to list of AEs controlled by this one.
- aeAddHTML_Node(pHTML_Node):  Add HTML node to list of nodes controlled by this one.
- aeInitialise(): Initialise this AE. Will be overloaded by descendant classes.
- aeClear(): Clear content from this AEs HTML nodes.
- aeScreenChange(): Re-generate content for this AE for new screen name.
- aeGetScreenName(): Get the current screen name.
- aeGetScreenTitle(): Get the current screen title.
- aeGetAEid(): Get the id of this AE.
- aeGetMasterHTMLid(): Get the HTMLid of the master HTML node for this AE (may not exist).
- aeOutputDebugInformation(): Output useful data about this AE for debugging purposes.

*/

function activeElement(pAE_AEid, pAE_type, pAE_screenName, pAE_HTML_Node, pAE_paramList, pAE_parentAE)
{
    // This is the master AE class which will control all the AEs on a page.
    // The paramList isn't used within this class but is there so it is inherited by other AEs.
    // Remember all start up code is executed on both the master and child AEs!!

    D.debugStartFunction("activeElement", arguments);
    var parentId = (pAE_parentAE) ? pAE_parentAE.aeGetAEid() : "null";
    D.debug("Invoked from " + parentId);
    
    // --- Properties ---
    
    // Properties passed in via constructor (HTML_Node processed further down)
    
    this.AE_AEid = pAE_AEid;
    this.AE_screenName = pAE_screenName;
    this.AE_paramList = (pAE_paramList) ? pAE_paramList : ""; // Not relevant for base class but needed for descendants.
    this.AE_parentAE = pAE_parentAE; // Not relevant for base class but needed for descendants.
    this.AE_status = "invocation";

    // Other Properties
    
    this.AE_AEtype = pAE_type;

    this.AE_title = "Dummy Title"; // Will be populated either from DOM or other AE later
 
    // Array of references to any AEs which are to be controlled by this one.
 
    this.AE_controlledAE_List = new Array;
    this.AE_controlledAE_Count = 0;
    
    // Array of references to any HTML nodes which are controlled by this one (1 master, 0+ slaves)
    
    this.AE_HTML_NodeList = new Array; // Holds a reference to each HTML node maintained by this AE
    this.AE_HTML_NodeCount = 0;
    
    // --- Methods ---
    
    this.aeGetAlgorithmObject = function(pAlgorithmName)
    {
        D.debugStartFunction("aeGetAlgorithmObject", arguments);

        var masterAE = this.aeGetMasterAE();
        
        D.debug("Called from " + this.aeGetAEid() + ", returned id from aeGetMasterAE = " + masterAE.aeGetAEid());
        
        if (!masterAE.AE_algorithmObject)
        {
            D.debug("Array doesn't exist, should be first call (Algorithm = " + pAlgorithmName);
            masterAE.AE_algorithmObject = new Array;
            if (!masterAE.AE_algorithmObject)
            {
                D.debug("Array still doesn't exist after creation!! (Algorithm = " + pAlgorithmName);
            }
        }
        if (!masterAE.AE_algorithmObject[pAlgorithmName])
        {
            D.debug("Algorithm doesn't exist, should be first call for this algorithm (Algorithm = " + pAlgorithmName);
            masterAE.AE_algorithmObject[pAlgorithmName] = new Array;
            masterAE.AE_algorithmObject[pAlgorithmName]['status'] = "Uninitialised";
            var evalString = "masterAE.AE_algorithmObject['" + pAlgorithmName + "']['object'] = new " + pAlgorithmName + "();";
            masterAE.AE_algorithmObject[pAlgorithmName]['status'] = "Initialised";
            D.debug("Eval " + evalString);
            eval(evalString);
        }
        else
        {
            D.debug("Algorithm " + pAlgorithmName + " already exists, returning pointer");
        }

        ret = masterAE.AE_algorithmObject[pAlgorithmName]['object'];

        D.debugEndFunction();
        return ret;
    }
    
    this.aeGetAlgorithmStatus = function(pAlgorithmName)
    {
        D.debugStartFunction("aeGetAlgorithmStatus", arguments);
        
        var ret = true;
        var masterAE = this.aeGetMasterAE();
        
        if (!masterAE.AE_algorithmObject)
        {
            ret = false;
        }
        else if (!masterAE.AE_algorithmObject[pAlgorithmName])
        {
            ret = false;
        }
        else if (!masterAE.AE_algorithmObject[pAlgorithmName]['status'])
        {
            ret = false;
        }
        else
        {
            ret = masterAE.AE_algorithmObject[pAlgorithmName]['status'];
        }
        D.debugEndFunction();
        return ret;
    }
    
    this.aeSetAlgorithmStatus = function(pAlgorithmName, pStatus)
    {
        D.debugStartFunction("aeSetAlgorithmStatus", arguments);
        
        var ret = true;
        var masterAE = this.aeGetMasterAE();
        
        if (!masterAE.AE_algorithmObject)
        {
            ret = false;
        }
        else if (!masterAE.AE_algorithmObject[pAlgorithmName])
        {
            ret = false;
        }
        else if (!masterAE.AE_algorithmObject[pAlgorithmName]['status'])
        {
            ret = false;
        }
        else
        {
            masterAE.AE_algorithmObject[pAlgorithmName]['status'] = pStatus;
        }
        D.debugEndFunction();
        return ret;
    }
    

    this.aeGetStatus = function()
    {
        return this.AE_status;
    }
    
    this.aeSetStatus = function(pStatus)
    {
        this.AE_status = pStatus;
    }

    this.aeGetMsgSeqNum = function()
    {
        // Note - calling this method will automatically increment Sequence Number!!
        
        if (!this.AE_MsgSeqNum)
        {
            this.AE_MsgSeqNum = -1;
        }
        return ++this.AE_MsgSeqNum;
    }

    this.aeParseDOM = function()
    {
        /*
        Looks for active elements within this part of the DOM and activates them.
        
        Child AEs declared within HTML are only valid when the HTML content has itself
        been generated by an AE.  This is to implement the cascading effect of having AEs
        defined in content which is read in or generated by other AEs (e.g. Text).
        
        In this case once the child AEs have been activated the parent AE will no longer
        manage the content for the AE or this would cause a conflict.
        
        Active elements defined by following (non-standard) attributes:

        - AEmode: "master" means this is the declaration and initial instantiation of AE
                  "slave" means this is a secondary connection to a declared AE.

        - AEtype: Defines which AE class will be instantiated for this element. Only relevant
                  for declared AEs. Secondary connections will connect to existing AE.

        - AEid:   Defines the id of a declared AE or the id of the AE to connect to
                  depending upon AEmode.
        
        - AEparamList: Defines a set of parameters to passed into the new AE.
       */
        
        D.debugStartFunction("aeParseDOM", arguments);
        
        // First get all the new AEs under this node (AEmode = "master")
        
        var AEmasterArray = getElementsByAttribute(this.AE_HTML_NodeList[0], "AEmode", "master");
        D.debug("No. declared AEs :" + AEmasterArray.length);
        
        // Now add any slave nodes under this
        
        var AEslaveArray = getElementsByAttribute(this.AE_HTML_NodeList[0], "AEmode", "slave");
        D.debug("No. declared AEs :" + AEslaveArray.length);
        
        // We now have a list of all AEs and all slave nodes under the master HTML node for calling AE which should be activated
        // Go through the list and check that other required attributes are set and create AEs or add slave nodes
        // as appropriate.
        
        // AEs first

        var attributesFound = true;
        var AEtype = "";
        var AEid = "";
        var AEparam = "";
        var i = 0;
        var AE_HTML_Node = 0;
        
        for (i=0; i<AEmasterArray.length; i++)
        {
            attributesFound = true;
            AEtype = getAttributeSafe(AEmasterArray[i], "AEtype");
            if (AEtype == "") {
                D.warn("Missing AEtype in parsed AE declaration for " + i + "th parsed AE");
                attributesFound = false;
            }
            else {
                D.debug("AEtype = " + AEtype);
            }
            AEid = getAttributeSafe(AEmasterArray[i], "AEid");
            if (AEid == "") {
                D.warn("Missing AEid in parsed AE declaration for " + i + "th parsed AE");
                attributesFound = false;
            }
            else {
                D.debug("AEid = " + AEid);
            }
            AEparam = getAttributeSafe(AEmasterArray[i], "AEparam");
            if (AEparam == "") {
                D.warn("Missing AEparam in parsed AE declaration for " + i + "th parsed AE");
                D.warn("Setting to empty string");
                AEparam = "";
            }
            else {
                D.debug("AEparam = " + AEparam);
            }
            if (attributesFound)
            {
                // We have a properly declared AE, so create it and add to the AE list for the calling AE
                
                AE_HTML_Node = AEmasterArray[i];
                var AEstring = "var newAE = new " + AEtype + "(\"" + AEid + "\", AE_HTML_Node, \"" + AEparam + "\", this);";
                
                D.debug("eval string = " + AEstring);
                eval(AEstring);
                D.debug("typeof newAE = " + typeof newAE);
                this.aeAddControlledAE(newAE);
            }
        }
        for (i=0; i<AEslaveArray.length; i++)
        {
            attributesFound = true;
            AEid = getAttributeSafe(AEslaveArray[i], "AEid");
            if (AEid == "") {
                D.warn("Missing AEid in parsed slave node declaration for " + i + "th parsed node");
                attributesFound = false;
            }
            else {
                D.debug("AEid = " + AEid);
            }
            if (attributesFound)
            {
                // We have a properly declared slave node, so create it and add to the list of HTML nodes
                // Call GetAEbyAEid from master downwards so that whole tree is parsed looking for AEid
                
                var AE = this.aeGetMasterAE().aeGetAEbyAEid(AEid);
                
                if (AE)
                {
                    AE.aeAddHTML_Node(AEslaveArray[i]);
                }
                else
                {
                    D.warn("No AE with AEid of " + AEid + " found");
                }
            }
        }
        D.debugEndFunction("aeParseDOM");
    }
    
/*
     this.aeSetAEtype = function(pType)
    {
        D.debugStartFunction("aeSetAE_Type", arguments);
        
        if (this.aeGetAEtype() != "")
        {
            D.debug("Changing from " + this.aeGetAEtype() + " to " + pType);
        }
        else
        {
            D.debug("Setting to " + pType);
        }
        this.AE_type = pType;
    }
*/
 
    this.aeAddControlledAE = function(pAE)
    {
        // Adds a new AE to be controlled by this one.
        
        D.debugStartFunction("aeAddControlledAE", arguments);
        
        this.AE_controlledAE_List[this.AE_controlledAE_Count++] = pAE;
        
        D.debugEndFunction("aeAddControlledAE");
    }
    
    this.aeAddHTML_Node = function(pHTML_Node)
    {
        // Adds a reference to an HTML element whose content will be controlled by this AE.
        
        D.debugStartFunction("aeAddHTML_Node", arguments);

        this.AE_HTML_NodeList[this.AE_HTML_NodeCount++] = pHTML_Node;
        
        D.debugEndFunction("aeAddHTML_Node");
    }
    
    this.aeInitialise = function()
    {
        /*
        Called after new AE has been created.  Populates HTML nodes with startup text
        */
        
        D.debugStartFunction("aeInitialise", arguments);
        if (this.aeGetAEtype() != "Page")
        {
            var text = ""; //"Initialising node for " + this.AE_AEtype + ":" + this.AE_AEid + ", Screen " + this.aeGetScreenName();
            this.aeUpdateHTML_Nodes(text);
        }
        
        // Propogate to any controlled AEs under this one
        
        /*
        for (var i=0; i<this.AE_controlledAE_Count; i++)
        {
            this.AE_controlledAE_List[i].aeInitialise();
        }
        */
        
        
        D.debugEndFunction("aeInitialise");
    }
    
     this.aeClear = function()
    {
        // Clears content on page for this AE and all controlled AEs
    }
    
     this.aeScreenChange = function(pScreenName)
    {
        // Updates screen name for this AE and all controlled AEs.
        // Consequences will depend upon each AE. E.g. navigation AEs will recalculate
        // links for new screen.
        
        D.debugStartFunction("aeScreenChange", arguments);
        this.aeSetScreenName(pScreenName);
        if (this.aeGetAEtype() != "Page")
        {
            this.aeUpdateHTML_Nodes("Screen changed to " + pScreenName);
        }
            
        // Cascade to all child AEs
        
         for (var i=0; i<this.AE_controlledAE_Count; i++)
        {
            D.debug("Cascading to AEid " + this.AE_controlledAE_List[i].AE_AEid);
            this.AE_controlledAE_List[i].aeScreenChange(pScreenName);
        }
        D.debugEndFunction("aeScreenChange");
    }
    
     this.aeGetScreenName = function()
    {
        // Returns screen name for this AE (all AEs on a page share the same screen name)
        
        if (this.aeGetAEtype() == "Page")
        {
            return this.AE_screenName;
        }
        else
        {
            return this.AE_parentAE.aeGetScreenName();
        }
    }
    
    this.aeSetScreenName = function(pNewScreen)
    {
        // Should only be called by top level object, but should code a little more
        // defensively than this!
        
        this.AE_screenName = pNewScreen;
    }
    
    this.aeGetMasterAE = function()
    {
        // Returns the master element of the AE tree
        // Climbs up to the top of the tree until the AE of type "Page" is found
        
        D.debugStartFunction("aeGetMasterAE", arguments);
        D.debug("Current AEid = " + this.aeGetAEid());
        
        if (this.aeGetAEtype() == "Page")
        {
            D.debug("Reached master, id = " + this.aeGetAEid());
            ret = this;
        }
        else
        {
            ret = this.AE_parentAE.aeGetMasterAE();
        }
        D.debugEndFunction();
        return ret;
    }
    
     this.aeGetAEid = function()
    {
        // Returns unique Id for AE.
        
        D.debugStartFunction("aeGetAEid", arguments);
        
        D.debugEndFunction("aeGetAEid");

        return this.AE_AEid;
    }
    
    this.aeGetAEtype = function()
    {
        D.debugStartFunction("aeGetAEtype", arguments);
        
        D.debug("type= " + this.AE_AEtype);
        
        D.debugEndFunction("aeGetAEtype");
        return this.AE_AEtype;
    }
    
    this.aeGetAEbyAEid = function(pAEid)
    {
        // This method is a recursive function which should initially have been called
        // from the master PageAE object, and which cascades through the AE tree looking
        // for an AE with a given AEid.
        
        // First check that the method has been called correctly, either by the parent
        // AE or if this is the top level AE, start cascading down the tree.
        
        D.debugStartFunction("aeGetAEbyAEid", arguments);
        D.debug("Called from " + this.AE_AEid);
        
        var ret = false;
        if (this.AE_AEid == pAEid)
        {
            D.debug("Found");
            ret = this;
        }
        else
        {
            for (var i=0, found=false; i<this.AE_controlledAE_Count && !found; i++)
            {
                ret=this.AE_controlledAE_List[i].aeGetAEbyAEid(pAEid);
                if (ret !== false)
                {
                    D.debug("Found returned, returned value = " + ret + ", id = " + ret.AEid);
                    found = true;
                }
            }
        }
        D.debug("Returning " + ret);
        D.debugEndFunction("aeGetAEbyAEid");

        return ret;
    }
    
     this.aeGetMasterHTMLid = function()
    {
        // Returns id for master HTML Node for an AE.
        
        D.debugStartFunction("aeGetMasterHTMLid", arguments);        
        if (this.AE_HTML_NodeCount >= 1)
        {
            var ret = this.AE_HTML_NodeList[0].getAttribute("id"); // Master is always first in list
        }
        else
        {
            ret = "HTML_Node Undefined";
            D.debug("HTML_Node Undefined");
        }
        D.debugEndFunction();
        
        return ret;
    }
    
    this.aeUpdateHTML_Nodes = function(pHTML_Content)
    {
        // alert("Starting aeUpdateHTML_Nodes");
        D.debugStartFunction("aeUpdateHTML_Nodes", arguments);
        D.debug("this.AE_AEid = " + this.AE_AEid);
        // alert("Node count = " + this.AE_HTML_NodeCount);
        for (var i=0; i<this.AE_HTML_NodeCount; i++)
        {
            D.debug("Updating HTML Node number " + i);
            this.AE_HTML_NodeList[i].innerHTML = pHTML_Content;
        }
        D.debugEndFunction();
    }
    
    // Note: (IBH) this function not yet tested
    // but it's a good one to have, to complement aeUpdateHTML_Nodes above
    // since it is 'a good thing' to be able to update nodes in both of these ways
    this.aeUpdate_Nodes_with_DOM_Nodetree = function(pDOM_Content)
    {
        D.debugStartFunction("aeUpdate_Nodes_with_DOM_Nodetree", arguments);
        D.debug("this.AE_AEid = " + this.AE_AEid);

        for (var i=0; i<this.AE_HTML_NodeCount; i++)
        {
            D.debug("Updating HTML Node number " + i);
            this.AE_HTML_NodeList[i].appendChild(pDOM_Content);
        }
        D.debugEndFunction();
    }
    
    // Return pointer to the node, or tag, for which we have responsibility.
    // This is going to be the master node, and ignores any slave nodes
    this.GetBaseNode = function()
    {
        return this.AE_HTML_NodeList[0];
    }
    
    this.aeUpdateContent = function()
    {
        /*
        This is the function which calculates the HTML to populate the HTML nodes for this AE.
        The content could be calculated locally (say updated link bars) or directly from the server,
        or from data requested from the server.
        
        This function is overloaded for each specific AE.  For the master (Page) AE it does nothing.
        */
        D.debugStartFunction("aeUpdateContent", arguments);        
        
        D.debugEndFunction();
    }
    
    this.aeSendRequest = function(pXMLrequestData)
    {
        /*
        This function will send a request to the server.  The XML request message is passed in and this function
        simply creates an XMLHTTPrequest to "AErouter.php" on the server and sends it using GET (or POST!).
        */
        
        // Firstly, work out which sort of object we need to use which will depend upon which browser we are on.
        
        D.debugStartFunction("aeSendRequest", arguments);        
        if (window.XMLHttpRequest)
        {
            this.XMLHttpRequestObject = new XMLHttpRequest();
        }
        else if (window.ActiveXObject)
        {
            this.XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP");
        }
        
        // If we have successfully found an object we can go ahead
    
        var thisAE = this;
        if (this.XMLHttpRequestObject)
        {
            this.XMLHttpRequestObject.onreadystatechange = function()
            {
                thisAE.aeProcessHTTPstateChange();
            }
            var RequestParser = "AErequestParser.php";
            this.XMLHttpRequestObject.open("POST", RequestParser, true);
            this.XMLHttpRequestObject.setRequestHeader("Content-Type", "text/xml");
            this.XMLHttpRequestObject.send(pXMLrequestData);
        }
        D.debugEndFunction();
    }
 
    this.aeProcessHTTPstateChange = function()
    {
        var text;
        
        D.debugStartFunction("aeProcessHTTPstateChange", arguments);
        D.debug("readyState = " + this.XMLHttpRequestObject.readyState);
        if (this.XMLHttpRequestObject.readyState > 1) D.debug("status = " + this.XMLHttpRequestObject.status);

        if (this.XMLHttpRequestObject.readyState == 4)
        {
            if (this.XMLHttpRequestObject.status == 200)
            {
                var fileType = this.XMLHttpRequestObject.getResponseHeader("Content-Type");
                D.debug("fileType = " + fileType);
                text = this.XMLHttpRequestObject.responseText;
                D.debug("text = " + text);
                if ( fileType == "text/xml")
                {
                    var xmlDoc = this.XMLHttpRequestObject.responseXML;
                    var headerXML = xmlDoc.getElementsByTagName("responseheader")[0];
                    var responsetype = xmlDoc.getElementsByTagName("responsetype")[0].firstChild.nodeValue; // value of contents of <responsetype> tag
                    var dataXML = xmlDoc.getElementsByTagName(responsetype)[0].firstChild;
                    var loggingXML = xmlDoc.getElementsByTagName("logging")[0];

                    var header = this.aeProcessResponseHeader(headerXML);
                    this.aeLogResponse(header, dataXML, loggingXML);
                    
                    if (header['requeststatus'] == 'ok')
                    {
                        switch (header['responsetype'])
                        {
                            case 'HTMLinject' :
                                // D.debug("XML = " + dataXML);
                                // D.debug("XML.firstChild = " + dataXML.firstChild);
                                // D.debug("XML.firstChild.nodeValue = " + dataXML.firstChild.nodeValue);
                                this.aeUpdateHTML_Nodes(dataXML.nodeValue);
                                this.aeParseDOM();
                            break;
                        
                            case 'dataresponse' :
                                this.aeProcessResponseData(dataXML);
                            break;
                        
                            case 'null' :
                            break;
                        
                            default :
                                D.error("Unrecognised response type " + header['responsetype'] + " in " + this.AE_AEid + ":" + this.AE_AEtype);
                            break;
                        }
                    }
                    else
                    {
                        D.error("Status not ok, = " + header['requeststatus']);
                    }
                }
                else
                {
                    // Invalid Response - log
                    
                    D.error("Invalid Response received in " + this.AE_AEid + ":" + this.AE_AEtype);
                    D.error("Received text : " + text);
                }
            }
        }
        D.debugEndFunction();
    }
    
    this.aeXMLnodeCreate = function(pNodeName, pNodeValue)
    {
        // D.debugStartFunction("aeXMLnodeCreate", arguments);
        
        var ret;
        
        if (pNodeName == "") // Crude validation, probably needs to be more sophisticated.
        {
            D.warn("No Node Name Received");
            ret = "";
        }
        else
        {
            ret = "<" + pNodeName + ">" + pNodeValue + "</" + pNodeName + ">" + "\n\r";
        }
        // D.debug("Returning \'" + ret + "\'");
        // D.debugEndFunction();
        return ret;
    }

    this.aeCreateRequestHeaderXML = function(pHeader)
    {
        /*
        The header data is passed as an associative array and formatted as XML
        */
        
        var headerXML = "";
        
        headerXML += this.aeXMLnodeCreate('msgseqnum',   pHeader['msgseqnum']);
        headerXML += this.aeXMLnodeCreate('requesttype', pHeader['requesttype']);
        headerXML += this.aeXMLnodeCreate('loggingflag', pHeader['loggingflag']);
        headerXML += this.aeXMLnodeCreate('aetype',      pHeader['aetype']);
        headerXML += this.aeXMLnodeCreate('aeid',        pHeader['aeid']);
        
        headerXML = this.aeXMLnodeCreate('requestheader', headerXML);
        
        return headerXML;
    }
    
    this.aeCreateDataRequestXML = function()
    {
        // Dummy function to be overloaded as required by descendant classes
    }
    
    this.aeProcessResponseData = function(pXML)
    {
        D.debugStartFunction("aeProcessResponse", arguments);        

        this.aeUpdateHTML_Nodes("<p>Updating from aeProcessResponse</p>");

        D.debugEndFunction();
    }
    
    this.aeLogResponse = function(pHeader, pDataXML, pLoggingXML)
    {
        /*
        This function will output information from the incoming message either for debug or information purposes.
        */

        D.debugStartFunction("aeLogResponse", arguments);

        var LogStatus;
        var LogData;
        var LogMsgs;
        var i;
        
        if (!pLoggingXML.getElementsByTagName)
        {
            D.warn("LoggingXML not XML, type = " + typeof(pLoggingXML) + " value: " + pLoggingXML);
        }
        else
        {
            LogMsgs = pLoggingXML.getElementsByTagName("logmsg");
        }
        
        // First output the data from the header
        
        D.info("Response Header: Seq num.......... " + pHeader['msgseqnum']);
        D.info("Response Header: Request Type..... " + pHeader['requesttype']);
        D.info("Response Header: Logging Flag..... " + pHeader['loggingflag']);
        D.info("Response Header: AE Type.......... " + pHeader['aetype']);
        D.info("Response Header: AE Id............ " + pHeader['aeid']);
        D.info("Response Header: Request Status... " + pHeader['requeststatus']);
        D.info("Response Header: Response Type.... " + pHeader['responsetype']);
        
        // Now logging data
        
        for (i=0; i<LogMsgs.length; i++)
        {
            LogStatus = LogMsgs[i].getElementsByTagName("logmsgstatus")[0].firstChild.nodeValue;
            LogData = LogMsgs[i].getElementsByTagName("logmsgdata")[0].firstChild.nodeValue;
            D.info("Logging " + LogStatus +
                   " message for message number, " + pHeader['msgseqnum'] +
                   ", for AE " + pHeader['aeid'] +
                   " : " + LogData);
        }
        D.debugEndFunction();
    }
    
    this.aeProcessResponseHeader = function(pXMLheader)
    {

        var returnData = new Array();
        var i;
        var printData = "";
        
        returnData['msgseqnum'] = pXMLheader.getElementsByTagName("msgseqnum")[0].firstChild.nodeValue;
        returnData['requesttype'] = pXMLheader.getElementsByTagName("requesttype")[0].firstChild.nodeValue;
        returnData['loggingflag'] = pXMLheader.getElementsByTagName("loggingflag")[0].firstChild.nodeValue;
        returnData['aetype'] = pXMLheader.getElementsByTagName("aetype")[0].firstChild.nodeValue;
        returnData['aeid'] = pXMLheader.getElementsByTagName("aeid")[0].firstChild.nodeValue;
        returnData['requeststatus'] = pXMLheader.getElementsByTagName("requeststatus")[0].firstChild.nodeValue;
        returnData['responsetype'] = pXMLheader.getElementsByTagName("responsetype")[0].firstChild.nodeValue;
        
        // D.debug("Response Header = " + dump(returnData));

        return returnData;
    }
    
    this.aeOutputDebugInformation = function()
    {
        // Outputs information about this AE for debug purposes
        
        D.debugStartFunction("aeOutputDebugInformation", arguments);

        D.debug("aeOutputDebugInformation for AE_AEid : " + this.AE_AEid);
        D.debug(":AE_screenName..: " + this.aeGetScreenName());
        D.debug(":AE_paramList...: " + this.AE_paramList);
        D.debug(":AE_AEtype......: " + this.AE_AEtype);
        D.debug(":AE_title.......: " + this.AE_title);
        D.debug(":AE_status......: " + this.aeGetStatus());
        D.debug("");
        
        D.debug("There are " + this.AE_controlledAE_Count + " controlled Nodes:");
        for (var i=0; i<this.AE_controlledAE_Count; i++)
        {
            this.AE_controlledAE_List[i].aeOutputDebugInformation();
        }
 
        D.debug("");
        D.debug("There are " + this.AE_HTML_NodeCount + " HTML nodes:");
        for (i=0; i<this.AE_HTML_NodeCount; i++)
        {
            D.debug("Name of HTML node [" + i + "]:" + this.AE_HTML_NodeList[i].nodeName);
        }
        D.debugEndFunction();
    }
    
    // Add the passed in HTML node reference to the list.  It will be the first - master node
    
    this.aeAddHTML_Node(pAE_HTML_Node);
    if (this.aeGetAEtype() == "Page")
    {
        this.aeParseDOM();
    }
    this.aeInitialise();
    this.aeUpdateContent();
    
    D.debugEndFunction("activeElement");
    // D.debugWindow.document.close();
}