/*
  
  Japano javascript library

  This file contains a javascript API complementing the java serverside API 
  
  See http://japano.sourceforge.net for project details.

  $Id: japano.js,v 1.26 2005/10/05 05:15:46 fforw Exp $
*/

function Japano()
{
  var RT_TEXT=1;
  var RT_JSON=2;
  var RT_HTML=3;
  var RT_XML=4;

  var waitCnt=0;
  
  var createXMLHttpRequest=function()
  {
    var xmlhttp=null;
    
    //// INIT ////
    /*@cc_on @*/
    /*@if (@_jscript_version >= 5)
    // JScript gives us Conditional compilation, we can cope with old IE versions.
    // and security blocked creation of the objects.
    try
    {
      xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch (e)
    {
      try
      {
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
      } 
      catch (E)
      {
       xmlhttp = false;
      }
    }
    @end @*/
    if (!xmlhttp && typeof XMLHttpRequest!='undefined') 
    {
      xmlhttp = new XMLHttpRequest();
    }
    
    if (!xmlhttp)
      throw new Error("Your Browser does not support XMLHttpRequest.");   
      
    return xmlhttp;
  }

  //// PRIVATE FUNCTIONS ////

  var wait=function(wait)
  {
    if (wait)
    {
      waitCnt++;
      document.body.style.cursor="wait";
    }
    else
    {
      waitCnt--;
      if (waitCnt <=0)
      {
        waitCnt=0;
        document.body.style.cursor="auto";
      }  
    }
  }

  var request=function (method, requestType, URL, fn, params, waitCursor)
  {
    var done=false;
    //debug("request( "+method+", "+requestType+", "+URL+", "+fn+", "+params+", "+waitCursor+")");

    var body=null;
    if (params)
    {
      var key;
      if (method == "GET")
      {
        var divider=URL.indexOf("?") < 0 ? "?" : "&";
        for ( key in params)
        {
          URL=URL+divider+key+"="+params[key];
          divider="&";
        }
      }
      else if ( method == "POST")
      {
        body="";
        for ( key in params)
        {
          if (body.length > 0)
          {
            body+="&";
          }
          body+=key+"="+params[key];
        }
      }
      else
      {        
        throw new Error("Unsupported HTTP Method "+method);
      }
    }
    var xmlhttp=createXMLHttpRequest();
    xmlhttp.open( method, URL, true);        

    if (waitCursor)
      wait(true);
    xmlhttp.onreadystatechange=function()
    {
      //debug("ready");
      try
      {
        if (xmlhttp.readyState == 4)
        {
          var status=xmlhttp.status;
          // check http status
          var ok=status == 200;
          if (ok)
          {
            if (requestType == RT_TEXT)
            {
              if (waitCursor)
                wait(false);
              fn( xmlhttp.responseText);
            }
            else if (requestType == RT_JSON)
            {
              if (waitCursor)
                wait(false);
              var response=xmlhttp.responseText;
              if (isValidJSON(response))
              {
                eval("var json="+response);
                fn(json);
              }
              else
              {
                throw new Error("Invalid JSON response \""+response+"\"", response);
              }
            }
            else if (requestType == RT_HTML)
            {            
              if (waitCursor)
                wait(false);
              var div=document.createElement("div");
              div.innerHTML=xmlhttp.responseText;
              var e=div.childNodes[0];            
              fn( e);
            }
            else if (requestType == RT_XML)
            {
              if (waitCursor)
                wait(false);
              fn( xmlhttp.responseXML);
            }
            else
            {
              if (waitCursor)
                wait(false);
              throw new Error("Invalid request type "+requestType);
            }
          }
          else
          {
            if (waitCursor)
              wait(false);
            throw new Error("HTTP error "+status, xmlhttp.responseText);
          }
        }
      }
      catch(e)
      {
        if (waitCursor)
          wait(false);
        throw e;
      }
    }    
    if ( method == "POST")
    {
      xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    }
    xmlhttp.send( body);
  }

  var isValidJSON=function( response)
  {
    // check for valid JSON response
    if (response)
    {
      if (( response.indexOf("null") == 0 || response.indexOf("[") == 0 || response.indexOf("{") == 0 ))
        return true;
    } 
    return false;
  }

  //// PUBLIC FUNCTIONS ////

  this.get=function(URL, fn, params, waitCursor)
  {
    request("GET", RT_JSON, URL, fn, params, waitCursor);
  }
  this.getText=function(URL, fn, params, waitCursor)
  {
    request("GET", RT_TEXT, URL, fn, params, waitCursor);
  }
  this.getHTML=function(URL, fn, params, waitCursor)
  {
    request("GET", RT_HTML, URL, fn, params, waitCursor);
  }

  this.getXML=function(URL, fn, params, waitCursor)
  {
    request("GET", RT_XML, URL, fn, params, waitCursor);
  }  

  /*
  Returns an URL from the given relative URI.
  */
  this.convertToURL=function(URI)
  {
    if (URI.indexOf("http://") == 0)
      return URI;

    var baseUrl=document.URL;
    var strPos=baseUrl.indexOf('$');
    if (strPos > 0)
    {
      var slashPos=baseUrl.indexOf('/', strPos);
      if (slashPos > 0)
      {
        baseUrl=baseUrl.substring(0, slashPos);
      }
      else
      {
        baseUrl=baseUrl.substring(0, strPos-1);
      }
    }
    else
    {
      // skip protocol ( 'https://' is the longest)
      var end=baseUrl.indexOf('/',8);
      baseUrl=baseUrl.substring(0,end);
    }

    if (URI.charAt(0) == '/')
    {
      return baseUrl+URI;
    }
    else
    {
      var url=document.URL;
      var qm=url.lastIndexOf('?');

      var start=url.length-1;
      if (qm > 0)
      {
        start=qm;
      }

      return url.substring(0, url.lastIndexOf('/', start)+1)+URI;
    }  
  }

  this.readParameter=function(formElement)
  {
    if (formElement && formElement.nodeName == "FORM")
    {
      var params=new Array();
      var elements=formElement.elements;
      for (var i=0; i < elements.length; i++)
      {
        var e=elements[i];
        if (e.name && e.name.length > 0)
        {
          params[e.name]=e.value;
        }
      }
      return params;
    }
    else
    {
      throw new Error("element is not a form");
    }
  }

  // commits the form with the given id.
  //   id : id of the form to read
  this.commit=function(id, fn)
  {  
    var form=document.getElementById(id);
    var params=this.readParameter( form);
    params[".part"]=id;
    var URL=this.convertToURL( form.getAttribute("action"));
    var method=form.getAttribute("method").toUpperCase();

    request(method, RT_HTML, URL, fn, params)  
  }

  // custom exception
  this.Error=function(code, response)
  {
    this.code=code;
    this.response=response;  
  }

  // returns whether the result is an error.
  this.isError=function(o)
  {
    if (o && typeof o == 'object' && o instanceof Error)
      return true;
    else
      return false;
  }

  // returns a dump of the given object as definition list 
  this.dump=function(o)
  {  
    if (typeof(o) == 'string')
    {
      s=o+"<br>";
    }  
    else
    {    
      var s="<dl>";
      for (var prop in o)
      {
        try
        {
          var key=prop;
          var value=o[prop];
          s+="<dt>"+key+" ( type "+typeof(value)+")</dt><dd>"+value+"&nbsp;</dd>";
        }
        catch(e)
        {
        }
      }
      s+="</dl>";
    }
    return s;
  }
  
  this.forElement=function( name, className, fn)
  {
    var spans=document.getElementsByTagName( name);
    var regexp=new RegExp("\\b"+className+"\\b");
    for (var i = 0; i < spans.length; i++)
    {
      var span=spans[i];
      if (regexp.test(span.className))
      {
        if (span.onclick)
          span.onclick();
        fn(span, data);
      } 
    } 
  }

  this.forSpan=function( className, fn)
  {
    this.forElement("SPAN", className, fn);
  }

  this.forSpan("jpn_button", 
    function(elem, data)
    {      
      if (data)
      {
        var code="var fn="+data.fn+";";
        eval(code);
        var button=document.createElement("BUTTON");      
        button.addEventListener("click", fn, false);
        while (elem.hasChildNodes())
          elem.removeChild(elem.firstChild);
        elem.appendChild(button);
        button.appendChild(document.createTextNode(data.button));
     }
    });
}

