/*     ****************************************
      ** JPAL (Javascript PBwiki API Library) **
     **             version 0.6b                **
      **          by Jason Nguyen             **
       ****************************************
  
This library is meant to be used with the PBwiki API, which is
documented at api.pbwiki.com.

The library's documentation can be found at http://jpal.pbwiki.com.*/

var jpal = new Object();  //set up the namespace

//some variables
jpal.apikey = null;
jpal.status = null;
jpal.functionList = null;

//set up simple xmlhttprequest object for AJAX
jpal.getXmlHttpObject = function() { 
   var objXMLHttp=null;
   if (window.XMLHttpRequest) objXMLHttp=new XMLHttpRequest();
   else if (window.ActiveXObject) objXMLHttp=new ActiveXObject("Microsoft.XMLHTTP");
   return objXMLHttp;
}

//function to make request
jpal.request = function(call,requestHandler,data) {
   var xmlHttp=jpal.getXmlHttpObject();
   if (xmlHttp==null) {
      alert("Browser does not support HTTP Request");
      return;
   }
   var url = 'api/json/' + call;
   if (url.indexOf('?')==-1) url += '?';
   else url += '&';
   url += 'sid=' + Math.random();
   if (jpal.apikey) url += '&apikey_v1=' + jpal.apikey;
   xmlHttp.onreadystatechange = function() {
      if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete")
         requestHandler(xmlHttp);
   };
   if (!data) xmlHttp.open("GET",url,true); //if no data, then GET
   else xmlHttp.open("POST",url,true);      //if data, POST
   if (data) data = data.replace(new RegExp(unescape("%5C%5C"),"gi"),unescape("%5C%5C"));
   xmlHttp.send( data );
   return;
}

jpal.verifyAccess = function(handler) {
 if (jpal.status) {
    if (handler) handler();
    return;
 }
 jpal.request('verifyaccess',function(xmlHttp) {
    var data = eval('(' + xmlHttp.responseText + ')');
    jpal.status = data.v1.status;
    if (data.v1.functionList) jpal.functionList = data.v1.functionList;
    if (handler) handler();
 });
}

jpal.functionOk = function(call) {
 if (jpal.status!='OK') return false;
 for (var i=0;i<jpal.functionList.length;i++) {
    if (jpal.functionList[i].toLowerCase()==call.toLowerCase()) return true;
 }
 return false;
}

jpal.error = function(err) { alert(err); }

jpal.getPage = function(pageName,handler,format,rev) {
 if (!handler) return;
 var url = 'getpage?page=' + pageName;
 if (typeof format=='string') url+= '&format=' + format;
 if (typeof rev=='string') url+= '&rev=' + rev;
 jpal.verifyAccess(function() {
    if (!jpal.functionOk('getpage')) { jpal.error('Error calling GetPage'); return; }
    jpal.request(url,function(xmlHttp) {
       var text = xmlHttp.responseText;
       text = text.replace(/\r\n|\n|\r/gi,"\\n");
       var data = eval('(' + text + ')').v1;
       //errCode = "Does not exist" if not there
       handler(data);
    });
 });
}

jpal.getPageHistory = function(pageName,handler) {
 if (!handler) return;
 var url = 'getpagehistory?page=' + pageName;
 jpal.verifyAccess(function() {
    if (!jpal.functionOk('getpagehistory')) { jpal.error('Error calling GetPageHistory'); return; }
    jpal.request(url,function(xmlHttp) {
       var data = eval('(' + xmlHttp.responseText + ')').v1;
       handler(data);
    });
 });
}

jpal.getAllPages = function(handler) {
 if (!handler) return;
 jpal.verifyAccess(function() {
    if (!jpal.functionOk('getallpages')) { jpal.error('Error calling GetAllPages'); return; }
    jpal.request('getallpages',function(xmlHttp) {
       var data = eval('(' + xmlHttp.responseText + ')').v1;
       handler(data);
    });
 });
}

jpal.getRecentChanges = function(handler) {
 if (!handler) return;
 jpal.verifyAccess(function() {
    if (!jpal.functionOk('getrecentchanges')) { jpal.error('Error calling GetRecentChanges'); return; }
    jpal.request('getrecentchanges',function(xmlHttp) {
       var data = eval('(' + xmlHttp.responseText + ')').v1;
       handler(data);
    });
 });
}

jpal.getSiteInfo = function(handler) {
 if (!handler) return;
 jpal.verifyAccess(function() {
    if (!jpal.functionOk('getsiteinfo')) { jpal.error('Error calling GetSiteInfo'); return; }
    jpal.request('getsiteinfo',function(xmlHttp) {
       var data = eval('(' + xmlHttp.responseText + ')').v1;
       handler(data);
    });
 });
}

jpal.renderContent = function(data,handler) {
 if (!handler) return;
 jpal.verifyAccess(function() {
    if (!jpal.functionOk('rendercontent')) { jpal.error('Error calling RenderContent'); return; }
    jpal.request('rendercontent',function(xmlHttp) {
       var code = xmlHttp.responseText;
       code = code.replace(/\r\n|\n|\r/gi,"\\n");
       code = eval('(' + code + ')').v1;
       handler(code);
    },data);
 });
}

jpal.addPage = function(page,data,handler,locked,hidden,note) {
 var url = 'addpage?page=' + page;
 if (locked) url+= '&locked=1';
 if (hidden) url+= '&hidden=1';
 if (note) url+= '&note=' + note;
 if (!handler) return;
 jpal.verifyAccess(function() {
    if (!jpal.functionOk('addpage')) { jpal.error('Error calling AddPage'); return; }
    jpal.request(url,function(xmlHttp) {
       var res = eval('(' + xmlHttp.responseText + ')').v1;
       //res contains "pageURL" if successful, otherwise contains "errCode" and "error"
       if (handler) handler(res);
    },data);
 });
}

jpal.deletePage = function(page,handler) {
 var url = 'deletepage?page=' + page;
 jpal.verifyAccess(function() {
    if (!jpal.functionOk('deletepage')) { jpal.error('Error calling DeletePage'); return; }
    jpal.request(url,function(xmlHttp) {
       var res = eval('(' + xmlHttp.responseText + ')').v1;
       if (handler) handler(res);
    });
 });
}

jpal.changePage = function(page,data,handler,locked,hidden,note) {
 var url = 'changepage?page=' + page;
 if (locked) url+= '&locked=1';
 if (hidden) url+= '&hidden=1';
 if (note) url+= '&note=' + note;
 if (!handler) return;
 jpal.verifyAccess(function() {
    if (!jpal.functionOk('changePage')) { jpal.error('Error calling ChangePage'); return; }
    jpal.request(url,function(xmlHttp) {
       var res = eval('(' + xmlHttp.responseText + ')').v1;
       //res contains "pageURL" if successful, otherwise contains "errCode" and "error"
       if (handler) handler(res);
    },data);
 });
}

jpal.getFile = function(file,handler,metaOnly) {
 if (!handler) return;
 var url = 'getfile?file=' + file;
 if (metaOnly) url+= '&metaOnly=1';
 jpal.verifyAccess(function() {
    if (!jpal.functionOk('getfile')) { jpal.error('Error calling GetFile'); return; }
    jpal.request(url,function(xmlHttp) {
       if (xmlHttp.status!=200) {
          var code = new Object;
          code.errCode = xmlHttp.status;
          code.error = 'Could not retrieve file.  File may not exist.';
          handler(code);
       } else if (metaOnly) {
          var header = eval('(' + xmlHttp.responseText + ')').v1;
          handler(header);
       } else {
          var header = eval('(' + xmlHttp.getResponseHeader('X-JSON') + ')').v1;
          handler(header,xmlHttp.responseText);
       }
    });
 }); 
}

jpal.getAllFiles = function(handler) {
 if (!handler) return;
 jpal.verifyAccess(function() {
    if (!jpal.functionOk('getallfiles')) { jpal.error('Error calling GetAllFiles'); return; }
    jpal.request('getallfiles',function(xmlHttp) {
       var data = eval('(' + xmlHttp.responseText + ')').v1;
       handler(data);
    });
 });
}

jpal.addFile = function(file,data,handler) {
 jpal.verifyAccess(function() {
    if (!jpal.functionOk('addfile')) { jpal.error('Error calling AddFile'); return; }
    jpal.request('addfile?file='+file,function(xmlHttp) {
       var res = eval('(' + xmlHttp.responseText + ')').v1;
       //res contains "uploaded" set to "w00t" if successful; else, "errCode" and "error" set
       if (handler) handler(res);
    },data);
 });
}

jpal.deleteFile = function(file,handler) {
 jpal.verifyAccess(function() {
    if (!jpal.functionOk('deletefile')) { jpal.error('Error calling DeleteFile'); return; }
    jpal.request('deletefile?file=' + file,function(xmlHttp) {
       //res contains "deleted" set to "absolutely" if successful; else, "errCode" and "error" set
       var res = eval('(' + xmlHttp.responseText + ')').v1;
       if (handler) handler(res);
    });
 });
}

//all direct API implementations completed above; stuff below are extensions

jpal.appendPage = function(page,data,handler,locked,hidden,note) {
 jpal.verifyAccess(function() {
    if (!jpal.functionOk('getpage')) { jpal.error('Error calling GetPage'); return; }
    if (!jpal.functionOk('changepage')) { jpal.error('Error calling ChangePage'); return; }
    jpal.getPage(page,function(orig) {
      if (orig.errCode) jpal.addPage(page,data,function(res) {
         if (handler) handler(res);
      },locked,hidden,note);
      else jpal.changePage(page,orig.data+data,function(res) {
         if (handler) handler(res);
      },locked,hidden,note);
    },"raw");
 });
}

jpal.keys = '0123456789';
jpal.genKey = function(d) {
   return (d<1) ? '' : jpal.keys.charAt(Math.floor(jpal.keys.length*Math.random())) + jpal.genKey(d-1);
}

//writes to a file, asks for overwrite confirmation, makes a backup if necessary, and reports all errors
jpal.writeFile = function(file,data,handler,skipConfirm) {
 jpal.verifyAccess(function() {
    if (!jpal.functionOk('addfile')) { jpal.error('Error calling AddFile'); return; }
    if (!jpal.functionOk('deletefile')) { jpal.error('Error calling DeleteFile'); return; }
    if (!jpal.functionOk('getfile')) { jpal.error('Error calling GetFile'); return; }
    var tId = 'temp' + jpal.genKey(20);
    jpal.addFile(file,data,function(res) {
       if (res.uploaded && res.uploaded=='w00t') { if (handler) handler(res); return; }
       if (res.errCode==401 && (skipConfirm || confirm('Overwrite '+file+'?')) ) jpal.getFile(file,function(h,origData) {
          jpal.addFile(tId+file,origData,function(res2) {
             if (res2.uploaded && res2.uploaded=='w00t') jpal.deleteFile(file,function(res3) {
                if (res3.deleted && res3.deleted=='absolutely') jpal.addFile(file,data,function(res4) {
                   if (res4.uploaded && res4.uploaded=='w00t') jpal.deleteFile(tId+file,function(res5) {
                      if (!res5.deleted || res5.deleted!='absolutely')
                         alert('Data uploaded, error deleting temp. Please delete '+tId+file+' manually');
                      if (handler) handler(res4);
                   });
                   else {
                      alert('Error uploading new data...attempting to revert');
                      jpal.addFile(file,origData,function(res6) {
                         if (res6.uploaded && res6.uploaded=='w00t') {
                            jpal.deleteFile(tId+file,function(res7) {
                               if (!res7.deleted || res7.deleted!='absolutely')
                                  alert('Reverted, error deleting '+tId+file);
                               if (handler) handler(res4);
                            });
                         }
                         else {
                            alert('Error reverting, backup stored in '+tId+file);
                            if (handler) handler(res4);
                         }
                      });
                   }
                });
                else {
                   alert('Error deleting original...getting rid of backup');
                   jpal.deleteFile(tId+file,function(res8) {
                      if (!res8.deleted || res8.deleted!='absolutely')
                         alert('Error deleting backup at '+tId+file);
                      if (handler) handler(res3);
                   });
                }
             });
             else {
                alert('Error making backup...aborting');
                if (handler) handler(res2);
             }
          });
       });
       else { if (handler) handler(res); return; }
    });
 });
}

jpal.getFileExt = function(str) {
   str = str.split('.');
   return (str.length==0) ? '' : str[str.length-1].toLowerCase();
}

jpal.extMask = function(fl,mask) {
   if (mask=='*') return fl;
   mask = mask.split('|');
   var list = new Array();
   for (var i=0;i<fl.length;i++) {
      var ext = jpal.getFileExt(fl[i]);
      for (var j=0;j<mask.length;j++) {
         if (mask[j].toLowerCase() == ext)
            list.push(fl[i]);
      }
   }
   return list;
}

