function replaceall(str, s1, s2) {
    while (str.indexOf(s1) != -1) {
        str = str.replace(s1, s2);
    }
    return str;
}

var whitespace = "\n\r\t ";
var dataType = {};
var valueType = {};
var xPathCompileSupport = (typeof(XPathResult) != "undefined");
if(xPathCompileSupport) {
    dataType = {
        "string": XPathResult.STRING_TYPE,
        "any": XPathResult.ANY_TYPE,
        "boolean": XPathResult.BOOLEAN_TYPE,
        "number": XPathResult.NUMBER_TYPE
    }
    valueType = {
        "string": "stringValue",
        "boolean": "booleanValue",
        "number": "numberValue"
    }
}

function XmlDoc(xml) {
    this.xml = xml;
    this.access = new XMLAccess();
}

XmlDoc.prototype.getElements = function (ns, name) {
    var involker = partial(this.access.getElementsByTagNameNS, this.xml);
    return involker(ns, name);
}

function XMLAccess() {
}

function xmlLoad(url, handler) {
    var d = doXHR(url,
        {mimeType: 'text/xml', Accept: 'text/xml'});
    d.addCallback(handler);
	d.addErrback(errorHandler);
}

function xmlSyncLoad(uri) {
    var req = getXMLHttpRequest();
    req.open("GET", uri, false);
    req.send(null);

    var status = req.status;
    if (status == 200 || status == 201 || status == 204 ||
            status == 304 || status == 1223) {
		//if(!req.responseXML && req.responseText) {
			
			return getDocFromText(req.responseText);
		//}
     //   return req.responseXML;
    }
    return "";
}

function getDocFromText(text) {
    if (window.ActiveXObject) {
        var doc = new ActiveXObject("Microsoft.XMLDOM");
        doc.async = "false";
        doc.loadXML(text);
    } else {
        var parser = new DOMParser();
        var doc = parser.parseFromString(text, "text/xml");
    }
    var result = doc.documentElement;
    return result;
}

function errorHandler(err) {
    logError("my error is:", err);
    if(err.fileName && err.lineNumber)
        logError(err + ' on ' + err.fileName + ':' + err.lineNumber);
    else
        logError(repr(err) + ':' + err.message);
}

XMLAccess.prototype.setXmlDoc = function(xml) {
    this.xmlDomDoc = xml
}

XMLAccess.prototype.getElementsByTagNameNS = function(parent, ns, name) {
    try {
        var result = parent.selectNodes('.//' + ns + ':' + name);
        return result;
    } catch(e) {
    }
    try {
        var result = this.getNodes(NS[ns], name);
        return result;
    } catch(e) {
        logError('no getElementNS!');
        return [];
    }
}

XMLAccess.prototype.getAttributeNS = function(node, ns, name) {
    if(node.getAttributeNS) {
        var result = node.getAttributeNS(NS[ns], name);
    }
    else {
        if(ns != "none") {
            var result = node.getAttribute(ns + ":" + name);
        } else {
            var result = node.getAttribute(name);
        }
    }
    return result;
}

XMLAccess.prototype.getAttributeNode = function(node, name) {
    var result = node.getAttribute(name);
    return result;
}

XMLAccess.prototype.xGetAttrNS = function(node, path, ns, name) {
    var nod = this.getFirstChild(node, path);
    return this.getAttributeNS(nod, ns, name);
}

XMLAccess.prototype.getNodes = function (context, path, dtype) {
    var result;
    if(typeof(context.selectNodes) != "undefined") {
        path = replaceall(path, "none:", "");
        result = context.selectNodes(path);
    }
    else if(xPathCompileSupport) {
        if(typeof(XPathResult.QueryInterface) == "undefined") {
            //why it's different? coz safari 3 supports xpath now!
            //and it's a bit better to parse path without 
            //any namespace in it IF it's not namespace 
            //specified for the nodes.
            path = replaceall(path, "none:", "");
        }
		if (BrowserDetect.browser == 'Firefox') {
        result = this.xmlDomDoc.evaluate(path, 
          context, getNS, dataType[dtype], null);
		  }else{
		  result = document.evaluate(path, 
          context, getNS, dataType[dtype], null);
		  }
    }
    else {
        result = simpleGetNodes(context, path);
    }
    return result;
}

XMLAccess.prototype.getChildren = function(node, path) {
    var nodes = this.getChildrenArray(node, path);
    return iter(nodes);
}

XMLAccess.prototype.getChildNodes = function(node, path) {
    if(typeof(node.selectNodes) != "undefined") {
        //assume ie
        var nodes = xmlAccess.getChildrenArray(node, path);
    }
    else {
        var nodes = xmlAccess.getChildren(node, path);
    }
	return nodes;
}

XMLAccess.prototype.getChildrenArray = function(node, path) {
    var nodes = this.getNodes(node, path, 'any');
	return nodes;
}

XMLAccess.prototype.getSons = function(node, path) {
    var result = [];
    if(typeof(node.selectNodes) == "undefined" && !xPathCompileSupport) {
        result = node.childNodes;
        result = ifilter(function (node) {
            return node.nodeType == '1';
            }, 
            result);
    } else {
        result = this.getNodes(node, path, 'any');
    }
    return iter(result);
}

XMLAccess.prototype.getText = function(node) {
    var result;
    if (node.text) {
        result = node.text;
    } else if (node.textContent) {
        result = node.textContent;
    } else {
        if(node.childNodes.length > 0) {
            result = node.childNodes[0].nodeValue;
        }
    } 
    if (isUndefinedOrNull(result)) {
        result = "";
    }
    return result;
}

XMLAccess.prototype.getCData = function(node) {
    if(node.childNodes.length) {
        var child = node.childNodes[0];
        if(child.nodeName == '#cdata-section') {
            return child.data;
        }
    }
    return "";
}

XMLAccess.prototype.getSingleChildText = function(node, path) {
    var node = this.getNodes(node, path, "string");
    //logDebug("my getfirstchild:", nodes);
    if(node) {
        if(node.length) {
            var child = node[0];
            if(child.text) {
                return child.text;
            }
            else if(child.hasChildNodes()) {
                return child.childNodes[0].nodeValue;
            }
        }
        else if(xPathCompileSupport) {
            return node[valueType["string"]];
        }
    }
    return "";
}

XMLAccess.prototype.getFirstChild = function(node, path, dtype) {
	//logDebug("caller", this.getFirstChild.caller.toString());
    if(!dtype) {
        dtype = 'any';
    }
    var nodes = this.getNodes(node, path, dtype);
	try {
		if(nodes) {
			return iter(nodes).next();
        }
    } catch (e) {}
    return null;
}

function getNS(ns) {
    return NS[ns];
}

function simpleGetNodes(node, path) {
    var segments = path.split('/');
    var result;
    var tmpNode = [node];
    var segemntLen = segments.length
    for(var i = 0; i < segemntLen; i++) {
        var segment = segments[i];
        if(!segment) continue;
        var qname = segment.split(':');
        var ns = "";
        if(qname.length == 2) {
            var ns = getNS(qname[0]);
            var name = qname[1];
        }
        else {
            var name = qname[0];
        }
        if(tmpNode.length > 0) {
            tmpNode = tmpNode[0].getElementsByTagNameNS(ns, name);
        }
        if(!tmpNode) {
            return tmpNode;
        }
    }
    return tmpNode;
}


function isEmpty(str) {
    return (str==null) || (str.length==0);

} 

function trim(trimString, leftTrim, rightTrim) {
    if (isEmpty(trimString)) {
        return "";
    }

    // the general focus here is on minimal method calls - hence only one
    // substring is done to complete the trim.

    if (leftTrim == null) {
        leftTrim = true;
    }

    if (rightTrim == null) {
        rightTrim = true;
    }

    var left=0;
    var right=0;
    var i=0;
    var k=0;

    // modified to properly handle strings that are all whitespace
    if (leftTrim == true) {
        while ((i<trimString.length) && (whitespace.indexOf(trimString.charAt(i++))!=-1)) {
            left++;
        }
    }
    if (rightTrim == true) {
        k=trimString.length-1;
        while((k>=left) && (whitespace.indexOf(trimString.charAt(k--))!=-1)) {
            right++;
        }
    }
    return trimString.substring(left, trimString.length - right);
} 

function httpFormPost(url, data) {
    var client = getXMLHttpRequest();
    client.open('POST', url, true);
	client.onreadystatechange = function (resp) {
		if(client.readyState == 4) {
			logDebug("succeed!");
		}
		console.log("resp", resp);
	}
    client.setRequestHeader("Content-Type" , "application/x-www-form-urlencoded");
    client.send(data);
}

