Tag = function() {}
Tag.prototype.attrNames = new Array();
Tag.prototype.initAttrs = function() {
    this.tags = new Array();
    this.attrs = new Object();
    this.params = new Object();
}

Tag.prototype.initCustomTag = function(tagName,parent,node) {
    this.initAttrs();
    this.parent = parent;
    this.tagName = tagName;
    var nodeAttrs = node.attributes;
//    if (parent) {
//        Top.debug("init TAG name="+this.tagName+" parent="+parent.tagName);
//    } else {
//        Top.debug("init TAG name="+this.tagName+" parent=NULL");
//    }
    for (var i=0; i<nodeAttrs.length; i++) {
        var attr = nodeAttrs[i];
        if (attr.specified && (attr.name != "toptype")) {
            //Top.debug(" attr["+attr.name+"]="+attr.value+" spec="+attr.specified);
            this.attrs[attr.name] = attr.value;
        }
    }
}

Tag.prototype.initNode = function(parent,node) {
    this.initAttrs();
    this.parent = parent;
    this.tagName = node.nodeName;
    this.nodeName = node.nodeName;
    this.parentNode = parent;
    var nodeAttrs = node.attributes;
    var parentName = "NULL";
    if (parent) parentName = parent.tagName;
    for (var i=0; i<nodeAttrs.length; i++) {
        var attr = nodeAttrs[i];
        this.attrs[attr.name] = attr.value;
        //Top.debug("  attr="+attr.name+" val="+attr.value+" attVal="+this.attrs[attr.name]);
    }
}

Tag.prototype.apply = function() {
    if (this.parent != null) {
        this.parent.add(this);
    }
//    if (this.parent == null) {
//        Top.debug("APPLY parent=NULL tag="+this.tagName);
//    } else {
//        Top.debug("APPLY parent="+this.parent.tagName+" tag="+this.tagName);
//    }
    return this.parent;
}

Tag.prototype.init = function() {
}

Tag.prototype.add = function(child) {
    this.tags[this.tags.length] = child;
}

Tag.prototype.addText = function(text) {
    this.tags[this.tags.length] = text;
}

Tag.prototype.getAttribute = function(name) {
    return this[name];
}

Tag.prototype.showBody = function(parent) {
    var buf = '';
    for (var i=0; i<this.tags.length; i++) {
        var item = this.tags[i];
        if (item instanceof Tag) {
            //Top.debug(this.tagName+".SHOW item["+i+"]="+item.tagName);
    	    buf += item.show(parent);
        } else if (item instanceof String) {
            //Top.debug(this.tagName+".SHOW text["+i+"]=["+item+"]");
            buf += Top.entify(item);
        } else {
            //Top.debug(this.tagName+".SHOW UNK["+i+"]=["+item.constructor+":"+item.toString()+"]");
            buf += "UNK["+i+"]=["+item.constructor+":"+item.toString()+"]";
        }
    }
    return buf;
}

Tag.prototype.showBodyTags = function(parent) {
    var buf = '';
    for (var i=0; i<this.tags.length; i++) {
        var item = this.tags[i];
        if (item instanceof Tag) {
            //Top.debug(this.tagName+".SHOW item["+i+"]="+item.tagName);
    	    buf += item.show(parent);
        }
    }
    return buf;
}

Tag.prototype.showUnqualifiedAttributes = function() {
    var buf = '';
    for (var attr in this.attrs) {
        var n = attr.indexOf('.');
        if (n >= 0) continue;
        var value = this.attrs[attr];
        if (value == null) continue;
        buf += " "+attr+"='"+value+"'";
    }
    return buf;
}

Tag.prototype.showQualifiedAttributes = function(prefix) {
    var buf = '';
    for (var attr in this.attrs) {
        var n = attr.indexOf('.');
        if (n < 0) continue;
        if (attr.substring(0,n+1) == prefix) {
            var value = this.attrs[attr];
            //Top.debug("showQualified attr="+attr+" value="+value);
            buf += " "+attr.substring(n+1)+"='"+value+"'";
        }
    }
    return buf;
}

Tag.prototype.showInVBox = function(attrs) {
    return "<td"+attrs+">"+this.show()+"</td>";
}

Tag.prototype.showInHBox = function(attrs) {
    return "<td"+attrs+">"+this.show()+"</td>";
}

Tag.prototype.show = function(parent) {
    var buf = '';
    var startNdx = buf.length;
    buf += "<"+this.tagName;
    for (var attr in this.attrs) {
        var value = this.attrs[attr];
        buf += " "+attr+"=\""+Top.entify(value)+"\"";
    }
    //Top.debug("Tag_show hdr="+buf+"> tags.len="+this.tags.length);
    var first = true;
    for (var i=0; i<this.tags.length; i++) {
        var child = this.tags[i];
        if (first) {
            first = false;
            buf += ">\n";
        }
        if (child instanceof Tag) {
            //Top.debug(this.tagName+".SHOW tag["+i+"]="+child.tagName);
            buf += child.show(this);
        } else if (child instanceof String) {
            //Top.debug(this.tagName+".SHOW text["+i+"]="+child);
            buf += Top.entify(child);
        } else {
            //Top.debug(this.tagName+".SHOW UNK["+i+"]=["+child.constructor+":"+child.toString()+"]");
        }
    }
    if (first) {
        buf += "/>";
    } else {
        buf += "</"+this.tagName+">\n";
    }
    //Top.debug(this.tagName+".SHOW buf=["+buf.substring(startNdx)+"]");
    return buf;
}

Tag.prototype.findTag = function(name) {
    //Top.debug("Tag_findTag("+name+") tags.len="+this.tags.length);
    for (var i=0; i<this.tags.length; i++) {
        var tag = this.tags[i];
        if (tag instanceof Tag) {
            //Top.debug("findTag this="+this.tagName+" tag["+tag.tagName+"] id="+tag.attrs.id);
            if (tag.attrs.id == name) return tag;
        }
    }
    for (var i=0; i<this.tags.length; i++) {
        var tag = this.tags[i];
        if (tag instanceof Tag) {
            var rslt = tag.findTag(name);
            if (rslt != null) return rslt;
        }
    }
    return null;
}

// Tag definition ends here

// include:     This implements an include feature.
//
function include() {
}
include.prototype = new Tag();
include.prototype.includes = new Object();
include.prototype.nextIncludeId = 101;

include.prototype.show = function() {
    //Top.debug("include: source="+this.attrs.source);
    Top.send(this.attrs.source);
    var key = this.attrs.source;
    var m = key.lastIndexOf("/");
    if (m >= 0) key = key.substring(m+1);
    var n = key.lastIndexOf(".xml");
    if (n >= 0) key = key.substring(0,n);
    this.includes[key] = this;
    this.includeId = this.nextIncludeId++;
    //Top.debug("include_show key="+key+" id=ID__"+this.includeId);
    return "<DIV id='ID__"+this.includeId+"'>&nbsp;</DIV>";
}

include.prototype.setHtml = function(text) {
    var tag = document.getElementById("ID__"+this.includeId);
    if (tag) tag.innerHTML = text;
}

function inclusion() {
}
inclusion.prototype = new Tag();
inclusion.prototype.includes = include.prototype.includes;

inclusion.prototype.init = function() {
    var key = this.tagName;
    var includeTag = this.includes[key];
    if (includeTag != null) {
        this.params = includeTag.params;
        //Top.debug("inclusion_init key="+key+" params.len="+this.params.length);
    }
}

inclusion.prototype.apply = function() {
    var key = this.tagName;
    var includeTag = this.includes[key];
    if (includeTag != null) {
        //Top.debug("inclusion_init key="+key);
        buf = this.show();
        //Top.debug("inclusion_init key="+key+" HTML=["+buf+"]");
        includeTag.setHtml(buf);
    }
    return this.parent;
}

function param() {
}
param.prototype = new Tag();

param.prototype.apply = function() {
    //Top.debug("param_apply parent="+this.parent);
    if (this.parent != null) {
        //Top.debug("param_apply name="+this.attrs.name+" value="+this.attrs.value);
        this.parent.params[this.attrs.name] = this.attrs.value;
    }
    return this.parent;
}

// This handles parsing errors by displaying a message to 
// the debug console.
function parseerror() {}
parseerror.prototype = new Tag();

parseerror.prototype.apply = function() {
    Top.debug("PARSE ERROR: msg="+this.showBody());
}

Top = {
    
    debugFlag: true,

    options: {
        method: 'get',
        parameters: null
    },
        
    console: null,
    debug: function(text) {
        if ((Top.console == null) || Top.console.closed) {
            Top.console = window.open("","debugConsole","width=600,height=300,resizable,scrollbars");
            Top.console.document.open();
        }
//        if (typeof ActiveXObject == "undefined") {
            text = "<pre>"+Top.entify(text)+"</pre>";
//        }
        Top.console.document.writeln(text);
        Top.console.scrollBy(0,100);
    },

    showSource: function() {
        Top.debug("<html>"+document.documentElement.innerHTML+"</html>");
    },
    
    recoverAttributes: function(attrs,text) {
        //Top.debug("Tag_recoverAttributes tag="+this.tagName);
        var attrList = text.split("&");
        for (var i=0; i<attrList.length; i++) {
            var attr = attrList[i];
            var n = attr.indexOf("=");
            if (n > 0) {
                var name = attr.substring(0,n);
                var value = decodeURIComponent(attr.substring(n+1));
                //Top.debug(" ATTR name="+name+" value="+value);
                attrs[name] = value;
            }
        }
    },
    
    entify: function(text) {
        return text.replace(/&/g,"&amp;")
                   .replace(/</g,"&lt;")
                   .replace(/>/g,"&gt;")
                   .replace(/\"/g,"&quot;");
    },

    deentify: function(text) {
        return text.replace(/&lt;/g,"<")
                   .replace(/&gt;/g,">")
                   .replace(/&quot;/g,"\"")
                   .replace(/&amp;/g,"&");
    },

    tagMap: {},
    namespacesByUrl: {},
    namespacesByPrefix: {},
    defaultNamespaces: [],

    registerTag: function(constr,name) {
        Top.tagMap[name] = constr;
    },

    registerNamespace: function(url,namespace) {
        //Top.debug("registerNamespace: url="+url);
        if ((url == null) || (url.length == 0)) {
            Top.defaultNamespaces[Top.defaultNamespaces.length] = namespace;
        } else {
            Top.namespacesByUrl[url] = namespace;
        }
    },    
    
    registerPrefix: function(prefix,namespace) {
        if (prefix.toUpperCase() == "DEFAULT") {
            //Top.debug("registerPrefix prefix=DEFAULT defNS.len="+Top.defaultNamespaces.length);
            Top.defaultNamespaces[Top.defaultNamespaces.length] = namespace;
        } else {
            //Top.debug("registerPrefix prefix="+prefix+" defNS.len="+Top.defaultNamespaces.length);
            Top.namespacesByPrefix[prefix] = namespace;
        }
    },
    
    openRequests: 0,
    goodResponses: 0,
    badResponses: 0,
    openRequestList: {},
    requestLog: [],
    logRequests: false,
    nextRequestId: 1,
    statusListener: null,    

    send: function(url) {
        Top.sendRaw(url,null,null);
    },

    sendXml: function(url,text) {
        Top.sendRaw(url,text,null);
    },
    
    loadText: function(url,callback) {
        Top.sendRaw(url,null,callback);
    },
    
    sendRaw: function(url,text,callback) {
        //Top.debug("send url="+url+" data="+text);
        var req = null;
        var isIE = false;
        var reqItem = null;
        var requestId = Top.nextRequestId++;            
        stateChange = function() {
            //Top.debug("state="+req.readyState);
            var xmlText = "";
            if (req.readyState == 4) {
                try {
                    if (isIE) {
                        xmlText = req.responseText;
                        if (callback) {
                            callback.applyText(xmlText);
                            return;
                        }
                        //Top.debug("IE: XML=["+req.responseText+"]");
                        var xmlParser = new ActiveXObject("Microsoft.XMLDOM");
                        if (! xmlParser) {
                            Top.debug("IE: NO PARSER");
                            return;
                        }
                        //Top.debug("IE: calling xmlNode");
                        xmlParser.loadXML(xmlText);
                        Top.xmlNode(xmlParser.documentElement,null,xmlText);
                        Top.goodResponses++;
                    } else if ((req.status == 200) || (req.status == 0)) {
                        xmlText = req.responseText;
                        if (callback) {
                            callback.applyText(xmlText);
                            return;
                        }
                        var responseXML = req.responseXML;
                        //Top.debug("MOZ: XML=["+req.responseText+"]");
                        if (responseXML != null) {
                            //Top.debug("MOZ: calling xmlNode");
                            Top.xmlNode(responseXML.documentElement,null,xmlText);
                            Top.goodResponses++;
                        } else {
                            Top.badResponses++;
                            Top.debug("MOZ: responseXML is NULL");
                        }
                    } else {
                        Top.debug("Bad Response req.status="+req.status);
                        Top.badResponses++;
                    }
                } catch (e) {
                    Top.debug("ERROR in SEND: msg="+e);
                    if (e.locator) {
                        Top.debug("ERROR line="+e.locator.lineNumber
                                 +" uri="+e.locator.uri);
                    }
                    Top.debug("ERROR URL=["+url+"]");
                    Top.debug("ERROR xml=["+xmlText+"]");
                    throw e;
                }
                Top.openRequests--;
                delete Top.openRequestList[requestId];
            }
            if (Top.statusListener) Top.statusListener();
        }
        var requestId = Top.nextRequestId++;            
        if (window.XMLHttpRequest) {
            req=new XMLHttpRequest();
        } else if (typeof ActiveXObject != "undefined") {
            isIE = true;
            req = new ActiveXObject("Microsoft.XMLHTTP");
        }
        req.onreadystatechange = stateChange;
        reqItem = [req,url,text];
        Top.openRequestList[requestId] = reqItem;
        if (Top.logRequests) Top.requestLog[Top.requestLog.length] = reqItem;
        Top.openRequests++;
        //Top.debug("Sending XMLHttpRequest as POST url="+url);
        try {
            if (text) {
                req.open("POST",url,true);
                req.setRequestHeader("Content-Type","applications/x-www-form-urlencoded");
                req.send(text);
            } else {
                req.open("GET",url,true);
                req.setRequestHeader("Content-Type","applications/x-www-form-urlencoded");
                req.send(null);
            }
        } catch (e) {
            Top.debug("ERROR in SEND: msg="+e);
            Top.debug("ERROR URL=["+url+"]");
            if (e.locator) {
                Top.debug("ERROR line="+e.locator.lineNumber
                         +" uri="+e.locator.uri);
            }
            throw e;
        }
        if (Top.statusListener) Top.statusListener();
    },

    clearRequestLog: function(e,item) {
        Top.requestLog = [];
    },
    
    startRequestLogging: function(e,item) {
        Top.logRequests = true;
    },
    
    stopRequestLogging: function(e,item) {
        Top.logRequests = false;
    },
    
    showRequestLog: function(e,item) {
        var msg = "RequestLog:\n";
        for (var i=0; i<Top.requestLog.length; i++) {
            var reqItem = Top.requestLog[i];
            var req = reqItem[0];
            var rdy = req.readyState;
            var status = -1;
            if (rdy == 4) {
                status = req.status;
            }
            msg += "req["+i+"] rdy="+rdy+":"+status+" URL="+reqItem[1]+" Msg="+reqItem[2]+"\n";
            if ((rdy == 4) && ((status == 0) || (status == 200))) {
                msg += req.responseText;
            }
        }
        Top.debug(msg);
    },
    
    requestLogAction: function(action) {
        action = action.toUpperCase();
        if ("START" == action) {
            startRequestLogging();
        } else if ("STOP" == action) {
            stopRequestLogging();
        } else if ("SHOW" == action) {
            showRequestLog();
        } else if ("CLEAR" == action) {
            clearRequestLog();
        }
    },
    
    applyTag: function(node,parentNode,parentTag) {
        var tagName = node.getAttribute("toptype");
        var proto = null;
        var prefix = null;
        var namespace;
        var url = null;
        var tag = null;
        var parentName = "NULL";
        if (parentTag) parentName = parentTag.tagName;
        if (tagName) {
            var n = tagName.indexOf(':');
            //Top.debug("applyTag tagName="+tagName+" n="+n);
            if (n >= 0) {
                prefix = tagName.substring(0,n);
                namespace = Top.namespacesByPrefix[prefix];
                tagName = tagName.substring(n+1);
                //Top.debug("applyTag prefix="+prefix+" namespace="+namespace);
            }
            if (namespace != null) {
                proto = namespace[tagName];
                //Top.debug("xmlNode: have temp for tagName="+tagName+" proto="+proto);
            }
        }
        if ((proto == null) && (prefix == null) && tagName) {
            for (var i=0; i<Top.defaultNamespaces.length; i++) {
                proto = Top.defaultNamespaces[i][tagName];
                if (proto != null) break;
            }
        }
        if (typeof(proto) == "function") {
            var children = node.childNodes;
            //Top.debug("TAG tag="+tagName+" parent="+parentName+" children="+children.length);

            tag = new proto();
            tag.initCustomTag(tagName,parentTag,node);

            for (var i=0; i<children.length; i++) {
                var child = children[i];
                if (child.nodeType == 1) {
                    //Top.debug("CALLING applyTag from tag="+tag.tagName);
                    Top.applyTag(child,null,tag);
                } else if (child.nodeType == 3) {
                    tag.addText(new String(child.data));
                } else {
                    Top.debug("Child["+i+"] UNK type="+child.nodeType);
                    //Top.debug("applyXmlNode parent="+tagName+" TEXT="+new String(child.data));
                }
            }
            //Top.debug("calling apply() from applyTag tag="+tag.tagName);
            tag.apply();
            if (parentNode) {
                // If there is a parentNode, we need to generate the HTML
                // text for the Tag we just created and insert it into a
                // temporary DIV tag.  Then move all the children up into the
                // DIV tag parent and delete the DIV tag that contained the
                // Tag definition. Thus, the transform of the Tag replaces the 
                // DIV tag in which it is defined.
                //
                var newChild = document.createElement("div");
                var theHtml = tag.show();
                //Top.debug("====================================================");
                //Top.debug("innerHTML["+tag.tagName+"]\n"+theHtml);
                //Top.debug("----------------------------------------------------");
                newChild.innerHTML = theHtml;
                var grandChildren = newChild.childNodes;
                //Top.debug("grandChildren.len="+grandChildren.length);
                for (var i=0; i<grandChildren.length; i++) {
                    var grandChild = grandChildren[i];
                    parentNode.insertBefore(grandChild,node);
                }
                parentNode.removeChild(node);
                //Top.debug("parentNode.innerHTML(AFTER)\n"+parentNode.innerHTML);
                //Top.debug("====================================================");
            }
        } else if (parentTag) {
            // This is an HTML node embedded in a Tag node. We need to convert
            // it to a Tag and insert it into the parent Tag.
            tagName = node.nodeName;
            //Top.debug("applyTag(HTML-IN-TAG) tagName="+tagName);
            proto = Top.HtmlTag;
            tag = new proto();
            tag.initCustomTag(tagName,parentTag,node);

            var children = node.childNodes;
            for (var i=0; i<children.length; i++) {
                var child = children[i];
                if (child.nodeType == 1) {
                    Top.applyTag(child,null,tag);
                } else if (child.nodeType == 3) {
                    tag.addText(new String(child.data));
                } else {
                    //Top.debug("Child["+i+"] UNK type="+child.nodeType);
                    //Top.debug("applyXmlNode parent="+tagName+" TEXT="+new String(child.data));
                }
            }
            //Top.debug("calling apply() from applyTag(HTML) tag="+tag.tagName);
            tag.apply();
        } else {
            // This is an HTML node embedded not in a Tag node, just go
            // through all the children and call applyTag for each.
            //Top.debug("applyTag(HTML) tagName="+node.nodeName);
            var children = node.childNodes;
            for (var i=0; i<children.length; i++) {
                var child = children[i];
                if (child.nodeType == 1) {
                    Top.applyTag(child,node,null);
                } else if (child.nodeType != 3) {
                    Top.debug("Child["+i+"] UNK type="+child.nodeType);
                    //Top.debug("applyXmlNode parent="+tagName+" TEXT="+new String(child.data));
                }
            }
        }
    },
    
    applyCustomTags: function(node) {
        if (!node) node = document.documentElement;
        Top.applyTag(node,null,null);
    },
    
    xmlNode: function(node,parent,text) {
        if (node == null) {
            Top.debug("xmlNode node=NULL text=["+text+"]");
            return null;
        }
        var tagName = node.nodeName;
        //Top.debug("xmlNode: TAG="+tagName);
        try {
        var url = node.namespaceURI;
        if (url == null) url = "";
        //Top.debug("namespace URL="+url);
        var tagTemp = null;
        var namespace;
        if (url.length > 0) {
            // First, if there is a Namespace, pull it from the namespace obj
            //Top.debug("Checking URLS");
            //Top.debug("xmlNode: tagName="+tagName+" prfx="+node.prefix+" url="+url);
            var n = tagName.indexOf(':');
            if (n >= 0) {
                tagName = tagName.substring(n+1);
            }
            namespace = Top.namespacesByUrl[url];
            if (namespace != null) {
                tagTemp = namespace[tagName];
                //Top.debug("xmlNode: have temp for tagName="+tagName+" tagTemp="+tagTemp);
            }
        }
        if (tagTemp == null) {
            // Second, see if the tagName has been registered or is in
            // a namespace registered with the "default" prefix.
            if ((url.length == 0) && tagName) {
                //Top.debug("Checking DEFAULTS");
                for (var i=0; i<Top.defaultNamespaces.length; i++) {
                    tagTemp = Top.defaultNamespaces[i][tagName];
                    //Top.debug("XmlNode: defaultNS["+i+"]="+Top.defaultNamespaces[i]+" tagName="+tagName+" type="+typeof(tagTemp));
                    if (tagTemp != null) break;
                }
            }
            if (tagTemp == null) {
                // Third, see if there is a global object for the tagName
                //Top.debug("Checking GLOBALS");
                tagTemp = window[tagName];
                if (tagTemp == null) {
                    // Finally, just make it a Tag
                    //Top.debug("Using Generic Tag");
                    tagTemp = Top.standardTag;
                }
            }
        }
        var tag = new tagTemp();
        tag.initNode(parent,node);
        tag.init();
        var children = node.childNodes;
        if (children != null) {
            //Top.debug("Children.len="+children.length);
            for (var i=0; i<children.length; i++) {
                var child = children[i];
                //Top.debug("Child["+i+"]="+child);
                switch (child.nodeType) {
                case 1:
                    // Handle element
                    var childTag = Top.xmlNode(child,tag,"RECURSIVE");
                    //Top.debug(tag.tagName+".add tag["+i+"]="+childTag.tagName);
                    break;
                case 3:
                    // Handle text
                    //Top.debug(tag.tagName+".add TEXT["+i+"]=["+child.data+"]");
                    tag.addText(new String(child.data));
                    //Top.debug("addText DONE");
                    break;
                default:
                   (tag.tagName+".UNK["+i+"] Unexpected type="+child.nodeType);
                }
            }
        }
        //Top.debug("calling apply() from xmlNode tag="+tag.tagName);
        tag.apply();
        return tag;
    } catch (e) {
        Top.debug("ERROR in xmlNode: tagName="+tagName);
        if (e.locator) {
            Top.debug("ERROR line="+e.locator.lineNumber
                     +" uri="+e.locator.uri);
        }
        throw(e);
    }
    }
}

Top.defaultNamespaces[0] = Top.tagMap;

Top.standardTag = function() {}
Top.standardTag.prototype = new Tag();

Top.HtmlTag = function() {}
Top.HtmlTag.prototype = new Tag();
Top.HtmlTag.prototype.add = function(obj) {}

Top.handleResponse = function(response) {
    var responseXml = response.responseXML;
    if (responseXml == null) {
        //Top.debug("Could not parse XML");
    } else {
        //("Top.handleResponse response="+response);
        Top.xmlNode(responseXml.documentElement,null,"From HandleResponse");
    }
}
Top.options.onComplete = Top.handleResponse;

//Top.send = function(url) {
//    new Ajax.Request(url,Top.options);
//}

function recoverAttributes(attrs,text) {
    Top.recoverAttributes(attrs,text);
}

content = function() {}
content.prototype = new Tag();
Top.registerTag(content,"content");
content.prototype.apply = function() {
    var bodyHtml = this.showBody();
    document.getElementById("content").innerHTML = bodyHtml;
}



