﻿/**
*
*  uno.xml.js 
*  by Hideki Yamamoto eu-gsm[+393453332248]
*  Version Alpha 0.0.3.0
*  This file is part of the uno project.
*  The user must agree with the terms specified in
*
*  ©Hideki Yamamoto, all rights reserved.
*
*  Licence       : Http://www.unodot.net/framework/current/uno.licence.txt
*  Documentation : Http://www.unodot.net/framework/current/uno.js.usage.txt
*  History       : Http://www.unodot.net/framework/current/uno.js.history.txt
*
**/
if(!uno){alert('uno.xml.js requires uno.js');}
Namespace.register("uno.xml");
//if (!uno.xml) { uno.xml = {}; }
////////////////////////////CROSSWBROWSER XML PARSE////////////////////////////////
uno.xml.parse = function(xmlstring){
    var xmlDoc = false;
    try{var xmlParser = new DOMParser();xmlDoc = xmlParser.parseFromString(xmlstring, "text/xml");}catch(errr){
    try{xmlDoc= new ActiveXObject("Microsoft.XMLDOM");
        xmlDoc.async=false;
        xmlDoc.loadXML(xmlstring);}catch(err){uno.throwerror('There was an error parsing the xml string or the browser do not support xml parsing.\n'+err.message);
}   }return xmlDoc;};
///////////////////////ALMOST CROSBROWSER SYNCRONOUS XML LOAD////////////////////////////////
uno.xml.syncload = function(url) {
    var xmlDoc = false;
    //Chrome, safari
    if(is_chrome||is_safari){
        //uno.throwerror('Chrome and Safari may not support syncronous xml loading, please use uno.xml.asyncload(url,onstep,onfinish);');
        var page_request = new XMLHttpRequest();
        page_request.open('GET', url, false) //get page synchronously 
        page_request.send(null);
        return page_request.responseXML;
    }else{
    //Internet Explorer
    try{xmlDoc = new ActiveXObject("Microsoft.XMLDOM");}catch(exxx){
        //Firefox, Mozilla, Opera, etc.
        try{xmlDoc = document.implementation.createDocument("", "", null);}catch(exx){
            uno.throwerror('This browser have a problem creating a new xml document using the w3c way[document.implementation.createDocument("", "", null)]\n'+exx.message);}}
        try{xmlDoc.async = false; xmlDoc.load(url); }catch(ex){uno.throwerror('There was an error invoking a [xmlDoc.async = false;xmlDoc.load(url)] : \n'+ex.message);}
    return xmlDoc;}};
////////////////////////////CROSSBROWSER ASYNCRONOUS XML LOAD////////////////////////////////
uno.xml.asyncload = function(url, onstep, onfinish, onerrorfinish) {
    var idx = uno.xml._asyncjobs.length;
    uno.xml._asyncjobs[idx] = new uno.xml._asyncjob(url, onstep, onfinish, onerrorfinish);
    uno.xml._processasyncget(idx);};
uno.xml.asyncloadpost = function(url, onstep, onfinish, onerrorfinish, elm) {
    var idx = uno.xml._asyncjobs.length;
    uno.xml._asyncjobs[idx] = new uno.xml._asyncjob(url, onstep, onfinish, onerrorfinish);
    uno.xml._processasyncpost(idx,elm);};
uno.xml.asyncloadframe = function(url,tform,onstart,onfinish) {
    if (!uno.upload){alert('uno.xml.asyncloadframe(url,elm_or_elmid,onfinish) requires uno.upload.js');}
    var frameid = uno.upload.form(url,tform,onstart,uno.xml._postprocessasyncframe);
    var idx = uno.xml._framefinishes.length;
    uno.xml._framefinishes[idx] = new uno.xml._framefinish(frameid, onfinish);
};

/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////PRIVATE IMPLEMENTATION DETAILS//////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////PRE AND POST PROCESSES///////////////////////////////
uno.xml._processasyncget = function(idx){
    uno.xml._asyncjobs[idx].req = uno.xml._createxmlreq();
    uno.xml._asyncjobs[idx].req.onreadystatechange = function(){eval('uno.xml._postprocessasync(' + idx + ')');};
    uno.xml._asyncjobs[idx].req.open("GET", uno.xml._asyncjobs[idx].url, true);
    uno.xml._asyncjobs[idx].req.send('');};
uno.xml._processasyncpost = function(idx,elm_or_elmid) {
    uno.xml._asyncjobs[idx].req = uno.xml._createxmlreq();
    uno.xml._asyncjobs[idx].req.onreadystatechange = function() { eval('uno.xml._postprocessasync(' + idx + ')'); };
    uno.xml._asyncjobs[idx].req.open("POST", uno.xml._asyncjobs[idx].url, true);
    uno.xml._asyncjobs[idx].req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    uno.xml._asyncjobs[idx].req.send(uno.xml._serialize($(elm_or_elmid)));};
uno.xml._postprocessasyncframe = function(frameid,doc){
    var idx = uno.xml._asyncjobs.length;
    uno.xml._asyncjobs[idx] = new uno.xml._asyncjob('', false, uno.xml._getframefinish(frameid), false);
    uno.xml._asyncjobs[idx].req = new uno.xml._fakerq(uno.unhtmlentities(doc.body.innerHTML));
    uno.xml._postprocessasync(idx);};
uno.xml._postprocessasync = function(idx) {
    if (uno.xml._asyncjobs[idx].req.readyState == 4) {// only if req shows "loaded"
        if (uno.xml._asyncjobs[idx].req.status == 200) {// only if "OK"
            if (uno.xml._asyncjobs[idx].processed == false){
            uno.xml._asyncjobs[idx].processed = true;
            //If the response do not contain a Header["Content-Type" = "text/xml;charset=UTF-8"]
            //req.contentText will be available but req.responseXML will not be parsed.
            //Workaround:[manual parsing, encapsulating a fake request class for readonly javascript properties]:
            //if ((uno.xml._asyncjobs[idx].req.responseXML == null)||(uno.xml._asyncjobs[idx].req.responseXML.decumentElement == null)) {
                try{var text = uno.xml._asyncjobs[idx].req.responseText;
                    delete uno.xml._asyncjobs[idx].req;
                    uno.xml._asyncjobs[idx].req = new uno.xml._fakerq(text);
                }catch(ex){uno.throwerror('Error executing a workaround(No text/xml Content-Type header in loaded xml response.)' + '\n' + ex.message)}
            //}//end of workaround
            if (uno.debug){alert(uno.xml._asyncjobs[idx].req.responseText);}
            uno.xml._invoker(uno.xml._asyncjobs[idx].onfinish,uno.xml._asyncjobs[idx].req,'onfinish','Terminating the XMLHttpRequest Async Job correctly, invoking the onfinish handler');}
        }else {// only if NOT "OK"
            if (uno.debug){alert(uno.xml._asyncjobs[idx].req.responseText);}
            if (uno.xml._asyncjobs[idx].onerrorfinish){uno.xml._invokerstatus(uno.xml._asyncjobs[idx].onerrorfinish,uno.xml._asyncjobs[idx].req,'onerrorfinish','Terminating the XMLHttpRequest Async Job WITH ERRORS, invoking the onerrorfinish handler');}
            else if (uno.xml._asyncjobs[idx].onfinish){uno.xml._invoker(uno.xml._asyncjobs[idx].onfinish,uno.xml._asyncjobs[idx].req,'onfinish','Terminating the XMLHttpRequest Async Job with errors, invoking the onfinish handler because the onerrorfinish handler is not available');}
            else {uno.throwerror('Terminating the XMLHttpRequest Async Job for the url ' + uno.xml._asyncjobs[idx].url + ' with an error : \n' + uno.xml._asyncjobs[idx].req.status);}
    }}else{// only if req do not show "loaded"
        uno.xml._invokerstatus(uno.xml._asyncjobs[idx].onstep,uno.xml._asyncjobs[idx].req,'onstep','Stepping the XMLHttpRequest Async Job , invoking the onstep handler');
}   };
/////////////////////////FAKE CLASS FOR MISSING HEADER AND FRAME PARSING/////////////////////
uno.xml._fakerq = function(xmlstring){this.readyState = 4;this.status = 200;this.statusText = 'OK';this.responseText = xmlstring;this.responseXML = uno.xml.parse(xmlstring);};
/////////////////////////////////MEMORY STRUCTURE FOR ASYC JOBS////////////////////////////
uno.xml._asyncjobs = new Array();
uno.xml._asyncjob = function(_url, _onstep, _onfinish, _onerrorfinish){
    this.processed = false;this.req = false;this.url = _url;
    this.onstep = _onstep;this.onfinish = _onfinish;this.onerrorfinish = _onerrorfinish;};
//////////////////////////////MORE MEMORY STRUCTURE FOR FRAME JOBS/////////////////////////    
uno.xml._framefinishes = new Array();
uno.xml._framefinish = function(_frameid,_onfinish){
    this.frameid = _frameid;
    this.onfinish = _onfinish;};
uno.xml._getframefinish = function(frameid){
    for(var i=0;i<uno.xml._framefinishes.length;i++){
        if(uno.xml._framefinishes[i].frameid == frameid){return uno.xml._framefinishes[i].onfinish;}
    }return false;};
//////////////////////////////////////////MISCELLANEOUS///////////////////////////////
uno.xml._createxmlreq = function(){
    var newreq = false;
    if(window.XMLHttpRequest && !(window.ActiveXObject)){
        try {newreq = new XMLHttpRequest();}
        catch(ex){newreq = false;}
    }else if(window.ActiveXObject){
   	    try {newreq = new ActiveXObject("Msxml2.XMLHTTP");}
   	    catch(ex){
   	        try {newreq = new ActiveXObject("Microsoft.XMLHTTP");}
       	    catch(ex){newreq = false;
    }   }   }
    if(!newreq){uno.throwerror('This browser is neither w3c or mozilla compatible*[2008], uno.xml javascript framework will not work.');}
    return newreq;
};
uno.xml._collect = function(a,f){
    var n=[];
    for(var i=0;i<a.length;i++){var v=f(a[i]);if(v!=null){n.push(v);}}
    return n;};
uno.xml._serialize = function(f){
    var g=function(n){return f.getElementsByTagName(n)};
    var nv=function(e){if(e.name)return encodeURIComponent(e.name)+'='+encodeURIComponent(e.value);else return ''};
    var c1=function(i){if((i.type!='radio'&&i.type!='checkbox')||i.checked)return nv(i)};
    var i=uno.xml._collect(g('input'),c1);var s=uno.xml._collect(g('select'),nv);var t=uno.xml._collect(g('textarea'),nv);
    return i.concat(s).concat(t).join('&');};
uno.xml._invoker = function(func,req,hname,errorsituation){
 if(func){
  try{func(req);}catch(exxxx){
   try{func(req.responseXml);}catch(exxx){
    try{func(req.contentText);}catch(exx){
     try{func();}catch(ex){
      var msg = 'Situation:' + errorsituation + '\n';
      msg = msg + 'The handler '+hname+' could not be invoked without errors in any of the following ways.Set it to false to not have it executed.\n';
      msg = uno.xml_builderrorline(msg,hname+'(xmlrequest)',exxxx);
      msg = uno.xml_builderrorline(msg,hname+'(xmlrequest.responseXML)',exxx);
      msg = uno.xml_builderrorline(msg,hname+'(xmlrequest.contentText)',exx);
      msg = uno.xml_builderrorline(msg,hname+'()',ex);
      uno.throwerror(msg);
}}}}}};
uno.xml._invokerstatus = function(func,req,hname,errorsituation){
 if(func){
  try{func(req);}catch(exxx){
   try{func(req.statusText);}catch(exx){
    try{func();}catch(ex){
     var msg = 'Situation:' + errorsituation + '\n';
     msg = msg + 'The handler '+hname+' could not be invoked without errors in any of the following ways.Set it to false to not have it executed.\n';
     msg = uno.xml_builderrorline(msg,hname+'(xmlrequest)',exxx);
     msg = uno.xml_builderrorline(msg,hname+'(xmlrequest.statusText)',exx);
     msg = uno.xml_builderrorline(msg,hname+'()',ex);
     uno.throwerror(msg);
}}}}};
uno.xml_builderrorline = function(msg,hname,ex){return msg + '\n- ' + hname + ';\n  error was : ' + ex.message + '.';}