function toggleElement(id) {
    var currentElement = $(id);
    if (currentElement.hasClassName('active')) {
        hideElement(currentElement);
    } else {
        showElement(currentElement);
    }
}

function hideElement(el) {
    new Effect.BlindUp(el, {
        duration: 0.25
    });
    $(el).removeClassName('active');
}

function showElement(el) {
    var otherActives = $$('.active');
    otherActives.each(function(e) {
        e.removeClassName('active');
        new Effect.BlindUp(e, {
            duration: 0.25
        });
    })
    new Effect.BlindDown(el, {
        duration: 0.25
    });
    $(el).addClassName('active');
}

function hideAllDropDowns() {
    var actives = $$('.active');
    for(var i = 0; i < actives.length; i++) {
        hideElement(actives[i]);
    }
}

function randomUUID() {
    var s = [], itoh = '0123456789ABCDEF';
    // Make array of random hex digits. The UUID only has 32 digits in it, but we
    // allocate an extra items to make room for the '-'s we'll be inserting.
    for (var i = 0; i <32; i++) s[i] = Math.floor(Math.random()*0x10);
    // Conform to RFC-4122, section 4.4

    s[12] = 4;  // Set 4 high bits of time_high field to version
    s[17] = (s[17] & 0x3) | 0x8;  // Specify 2 high bits of clock sequence
    // Convert to hex chars
    for (var j = 0; j <36; j++) s[j] = itoh[s[j]];
    return s.join('');
}

function gup( name )
{
    name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
    var regexS = "[\\?&]"+name+"=([^&#]*)";
    var regex = new RegExp( regexS );
    var results = regex.exec( window.location.href );
    if( results == null )
        return "";
    else
        return results[1];
}

// General string-wrangling functions

function trim(str, chars) {
    return ltrim(rtrim(str, chars), chars);
}

function ltrim(str, chars) {
    chars = chars || "\\s";
    return str.replace(new RegExp("^[" + chars + "]+", "g"), "");
}

function rtrim(str, chars) {
    chars = chars || "\\s";
    return str.replace(new RegExp("[" + chars + "]+$", "g"), "");
}


// Functions to minimize IE nonsense.

function createXMLHttpRequest() {
    try {
        return new XMLHttpRequest();
    } catch(e) {}
    try {
        return new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {}
    try {
        return new ActiveXObject("Microsoft.XMLHTTP");
    } catch (e) {}
    alert("XMLHttpRequest not supported");
    return null;
}


function createMSDocument(){
    if (typeof arguments.callee.activeXString != "string"){
        var versions = ["MSXML2.DOMDocument.6.0",
        "MSXML2.DOMDocument.3.0",
        "MSXML2.DOMDocument"];

        for (var i=0,len=versions.length; i < len; i++){
            try {
                var xmldom = new ActiveXObject(versions[i]);
                arguments.callee.activeXString = versions[i];
                return xmldom;
            } catch (ex){
            //skip
            }
        }
    }

    return new ActiveXObject(arguments.callee.activeXString);
}

function loadXMLDoc(fname, method, requestbody)
{
    var xmlDoc;

    // code for IE
    if (window.ActiveXObject)
    {
        var request = createXMLHttpRequest();
        var ieNonsense = fname;
        if(ieNonsense.indexOf("?") == -1) {
            ieNonsense = ieNonsense + "?";
        } else {
            ieNonsense = ieNonsense + "&";
        }
        // IE's XmlHttpRequst cache behaviour is broken, so we have to break the
        // spec to make it work. This means that IE will make extra calls.
        ieNonsense = ieNonsense + "ieCacheDefeat="+Math.random();
        if(method){
            request.open("POST", ieNonsense + "&_method=" + method, false);
        } else {
            request.open("GET", ieNonsense, false);
        }
        request.send(requestbody);
        //alert(ieNonsense + "\n\n" + request.responseText);
        xmlDoc = request.responseXML;
        xmlDoc.setProperty("SelectionLanguage","XPath");
    }
    // code for Mozilla, Firefox, Opera, etc.
    else if (document.implementation && document.implementation.createDocument)
    {
        if(method){
            if(fname.indexOf("?") == -1) {
                fname = fname + "?_method=" + method;
            } else {
                fname = fname + "&_method=" + method;
            }
        }
        xmlDoc=document.implementation.createDocument("","",null);
        //        if(xmlDoc.load) {
        //
        //            xmlDoc.async=false;
        //            if(fname && fname != "") {
        //                xmlDoc.load(fname);
        //            }
        //        } else {
        // We're in Webkit-land, with their drunken half-assed DOM implementation.
        var xhReq = createXMLHttpRequest();
        if(method) {
            xhReq.open("POST", fname, false);
        } else {
            xhReq.open("GET", fname, false);

        }
        xhReq.send(requestbody);
        xmlDoc = (new DOMParser()).parseFromString( xhReq.responseText, "text/xml" );
    //        }
    }
    else
    {
        alert('Your browser cannot handle this script');
    }
    return(xmlDoc);
}

function setXMLNodeText(xml, path, value) {
    try {
        var node = pickNode(path, xml);

        // Unified child-extermination code.
        if(node.hasChildNodes()) {
            while(node.hasChildNodes()){
                node.removeChild(node.childNodes[0]);
            }
        }
        var newtext=xml.createTextNode(value);
        node.appendChild(newtext);

    } catch (e) {
        alert("Databinding failed to write value '"+value+"' for path '"+path+"'\n"+e);

        throw e;
    }
};


function transformAndInject(xml,xsl,targetElement)
{
    // code for IE
    if (window.ActiveXObject)
    {
        ex=xml.transformNode(xsl);
        targetElement.innerHTML=ex;
    }
    // code for Mozilla, Firefox, Opera, etc.
    else if (document.implementation
        && document.implementation.createDocument)
        {
        xsltProcessor=new XSLTProcessor();
        xsltProcessor.importStylesheet(xsl);
        resultDocument = xsltProcessor.transformToFragment(xml,document);
        internationalize(resultDocument);
        targetElement.innerHTML = "";
        targetElement.appendChild(resultDocument);
    }
}

pickNodeValue = function(path, xml){
    var node = pickNode(path, xml);
    if(node == null || node.firstChild == null) {
        return "";
    }
    return node.firstChild.nodeValue;
}

pickNode = function(path, xml) {
    var nodes = null;
    var node = null;
    if (window.ActiveXObject)
    {
        try {
            nodes=xml.selectNodes(path);
            if (nodes.length > 0)
            {
                node = nodes[0];
            }
        } catch (e) {
            alert(e);
        }
    } else {
        //var nsResolver = xml.createNSResolver( xml.ownerDocument == null ? xml.documentElement : xml.ownerDocument.documentElement);

        //nodes=xml.evaluate(path, xml, nsResolver, XPathResult.ANY_TYPE, null);
        nodes=xml.evaluate(path, xml, null, XPathResult.ANY_TYPE, null);

        node = nodes.iterateNext();
    }
    return node;
}

function internationalize() {
    var node = findI18nNode();
    while(node != null) {
        var key = trim(node.nodeValue).substr(5);
        var resource = null;
        for(var i = 0; i < resources.length; i++) {
            if(resources[i].labelKey == key) {
                resource = resources[i].labelFriendlyName;
            }
        }
        if(resource != null) {
            node.nodeValue = resource;
        } else {
            node.nodeValue = "???" + key + "???";
        }
        node = findI18nNode();
    }
}

function findI18nNode() {
    if(window.ActiveXObject) {
        // IE does not support XPath expressions on document nodes...
        var elementNames = ["a", "p", "div", "span", "th", "td"];
        for(var i = 0; i < elementNames.length; i++) {
            var elements = document.getElementsByTagName(elementNames[i]);
            for(var j = 0; j < elements.length; j++) {
                //alert(elementNames[i] + ":" + j+ ":");
                if(elements[j].childNodes.length > 0 ) { //&& elements[j].childNodes[0].nodeValue != null && elements[j].childNodes[0].nodeValue.substr(0,5) == "i18n:") {
                    var value = elements[j].childNodes[0].nodeValue;
                    if(value != null && value.substr(0, 5) == "i18n:"){
                        return elements[j].childNodes[0];
                    }
                }
            }
        }
        return null;
    } else {
        return pickNode("//*[starts-with(normalize-space(text()),'i18n:')]/text()", document);
    }
}
function postXML(xml, url) {
    var xmlString = serializeXML(xml);
    var request = createXMLHttpRequest();
    request.open("POST", url, false);
    //Send the proper header information along with the request
    request.setRequestHeader("Content-type", "text/xml");
    request.setRequestHeader("Connection", "close");

    request.send(xmlString);
}

function serializeXML(node) {

    if (typeof XMLSerializer != "undefined"){
        var ser = new XMLSerializer();
        return ser.serializeToString(node) ;
    }
    else if (node.xml) {
        return node.xml;
    }
    else {
        alert("XML.serialize is not supported or can't serialize " + node);
    }
};

function DataBinder(url, fieldmappings) {

    //this.formid = formid;
    //this.form = $(formid);
    this.url = url;
    this.fieldmappings = fieldmappings;
    this.xmlString = null;
    this.marshallValuesToForm = function (db) {
        //        alert("Marshalling to form!");
        for(var i in db.fieldmappings) {
            var field = $(i);
            if(field == null) {
                alert("Data Mapping could not find\nthe field with ID: " + i);
            } else {
                if(field.type == "radio" || field.type == "checkbox" || field.tagName == "checkbox" ) {
                    var booleanValue = db.selectNodeText(db, fieldmappings[i]);
                    if(booleanValue == "true") {
                        field.checked = true;
                    } else {
                        field.checked = false;
                    }
                } else if(field.type == "select" || field.type == "select-one") {
                    var index = -1;
                    var value = db.selectNodeText(db, fieldmappings[i]);
                    for(var j = 0; j < field.length; j++) {
                        if(field.options[j].value == value) {
                            index = j;
                        }
                    }
                    if(index == -1){
                        var elOptNew = document.createElement('option');
                        elOptNew.text = value;
                        elOptNew.value = value;
                        var elSel = field;
                        try {
                            elSel.add(elOptNew, null); // standards compliant; doesn't work in IE
                        }
                        catch(ex) {
                            elSel.add(elOptNew); // IE only
                        }
                        index = field.length -1;
                    }
                    field.selectedIndex = index;
                } else if(field.type == "text" || field.type == "password" || field.type == "textarea" || field.type == "hidden" || field.type == "textarea") {
                    field.value = (db.selectNodeText(db, fieldmappings[i]));
                } else if(fieldmappings[i].match(/^xslt:/)) {
                    var xslt = loadXMLDoc(fieldmappings[i].substring(5));
                    transformAndInject(db.xmlDocument, xslt, field);
                    internationalize();
                } else {
                    field.innerHTML = db.selectNodeText(db, fieldmappings[i]);
                }
            }
        }
    };
    this.marshallValuesToXML = function (db) {
        for(var i in db.fieldmappings) {
            var value = null;
            var field = $(i);
            if(field.getValue) {
                if(field.type == 'checkbox') {
                    if(field.checked) {
                        value = 'true';
                    } else {
                        value = 'false';
                    }
                } else
                {
                    value = field.getValue();
                }
            }
            if(value != null) {
                db.setNodeText(db, fieldmappings[i], value);
            }
        }
    };

    this.loadURL = function (db, url) {
        db.url = url;
        db.xmlDocument = loadXMLDoc(url);
        //db.xmlString = serializeXML(db.xmlDocument);
        db.marshallValuesToForm(db);
    };

    this.reload = function (db) {
        db.loadURL(db, db.url);
    };



    this.doSave = function(db, db_callback) {
        db.marshallValuesToXML(db);

        db.xmlString = serializeXML(db.xmlDocument);
        postXML(db.xmlDocument, db.url);
        if(db_callback) {
            db_callback(request);
        }

    };

    

    this.selectNodeText = function(db, path) {
        returnable = "";
        if(db.xmlDocument != null) {
            returnable = pickNodeValue(path, db.xmlDocument);
        }
        return returnable;

    };

    this.setNodeText = function(db, path, value) {
        if(db.xmlDocument != null) {
            try {
                var xml = db.xmlDocument;
                setXMLNodeText(xml, path, value);
            } catch (e) {
                alert("Databinding failed to write value '"+value+"' for path '"+path+"'\n"+e);
                alert("path: '"+path+"'");

                throw e;
            }
        }
    };

    this.loadURL(this, url);

}







