﻿// lingrcom.js
//
// Lingr Communication Javascript Class
//
// ver. 0.01 
// ver. 0.02 Bug fix on IE
// ver. 0.03 add return value to leaveRoom()
//           add myid paramater to observe_cb_func, getmsgs_cb_func and ocpchange_cb_func
// ver. 0.04 encode say string (bug fix)
// ver. 0.05 add async version of createSession and enterRoom
//           modify return code of some method
// ver. 0.051 modify createJSONRequest for Opera
//
// Copyright 2007-2008 inutch   http://d.hatena.ne.jp/inutch/


//set cgi path
var lingrcom_cgipath = "./scripts/cgi/";

// implementation of bind //
if( typeof( window.Function.prototype.bind ) == "undefined" ){
  Function.prototype.bind = function(object) {
    var __method = this;
    return function() {
      return __method.apply(object, arguments);
    };
  };
}


// Common Function //

if( typeof( window.txt2json ) == "undefined" ){
  function txt2json(str)
  {
    return eval( "(" + str + ")" );
  }
}

if( typeof( window.displog ) == "undefined" ){
  function displog(str)
  {
    try{
      console.debug(str);
    }
    catch(e){
    }
  }
}


/////// Lingr Communicasion Class //////////////////////////////////////////////


//Constructor
function LingrCom(myname)
{
  //g_lingrcom_prefix_cnt is global variable common between multiple LingrCom object
  if( typeof(g_lingrcom_prefix_cnt) == "undefined" ){
    g_lingrcom_prefix_cnt = 0;
  }

  this.objname = myname;

  this.session_id = null;
  this.my_id = null;
  this.room_ticket = null;
  this.nickname = null;

  this.room_counter = null;
  this.room_max_obs_time = null;
  this.obs_timer = null;

  this.ses_obj = null;
  this.ses_cb_func = null;

  this.entrm_obj = null;
  this.entrm_cb_func = null;

  this.say_obj = null;
  this.say_cb_func = null;

  this.observe_obj = null;
  this.observe_cb_func = null;

  this.getmsgs_obj = null;
  this.getmsgs_cb_func = null;

  this.ocpchange_cb_func = null;

  this.error_code = null;

  this.isMSIE = false;
  this.isFireFox = false;
  this.isOpera = false;
  this.isSafari = false;

//  window.alert(window.navigator.userAgent);

  if( window.navigator.userAgent.match(/MSIE/i) ){
    this.isMSIE = true;
//    window.alert("MSIE");
  }
  else if( window.navigator.userAgent.match(/Firefox/i) ){
    this.isFireFox = true;
//    window.alert("FireFox");
  }
  else if( window.navigator.userAgent.match(/Opera/i) ){
    this.isOpera = true;
//    window.alert("Opera");
  }
  else if( window.navigator.userAgent.match(/Safari/i) ){
    this.isSafari = true;
//    window.alert("Safari");
  }

}


//start prototype
LingrCom.prototype = {


  createSession:function()
  {
    var ret = false;
    var httpobj = this.createXMLHttpRequest(null);
    if(httpobj){
      httpobj.open("POST", lingrcom_cgipath+"ses.cgi", false);
      httpobj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      httpobj.send("");
      if( this.httpStateCheck(httpobj) ){
        var data = txt2json(httpobj.responseText);
        if(data.status == "ok"){
          this.session_id = data.session;
          ret = true;
          displog(this.objname + ".createSession: OK, session_id=" + this.session_id);
        } else {
          displog(this.objname + ".createSession: NG (return status)");
        }
      } else {
        displog(this.objname + ".createSession: NG (http stete check)");
      }
    } else {
      displog(this.objname + ".createSession: NG (createXMLHttpRequest)");
    }
    return ret;
  },


  createSessionA:function(cb)
  {
    if(cb){
      this.ses_cb_func = cb;
    }
    var ret = false;
    this.ses_obj = this.createXMLHttpRequest(this.cb_createSessionA.bind(this));
    if(this.ses_obj){
      this.ses_obj.open("POST", lingrcom_cgipath+"ses.cgi", true);
      this.ses_obj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      this.ses_obj.send("");
      displog(this.objname + ".createSessionA: req");
      return true;
    }
    else{
      displog(this.objname + ".createSessionA: NG (createXMLHttpRequest)");
      return false;
    }
  },


  cb_createSessionA:function()
  {
    var ret = false;
    if( this.httpIsReady(this.ses_obj) ){
      if( this.httpStateCheck(this.ses_obj) ){
        var data = txt2json(this.ses_obj.responseText);
        if(data.status == "ok"){
          this.session_id = data.session;
          ret = true;
          displog(this.objname + ".cb_createSessionA: OK, session_id=" + this.session_id);
        } else {
          displog(this.objname + ".cb_createSessionA: NG (return status)");
        }
      } else {
        displog(this.objname + ".cb_createSessionA: NG (http stete check)");
      }
      if( this.ses_cb_func ){
        this.ses_cb_func(ret);
      }
    }
  },


  enterRoom:function(roomid, nickname)
  {
    var ret = false;
    var httpobj = this.createXMLHttpRequest(null);
    if(httpobj){
      httpobj.open("POST", lingrcom_cgipath+"room.cgi", false);
      httpobj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      var sendstr = 'format=json'
         + '&session=' + this.session_id
         + '&id=' + roomid;
      if(nickname){
         sendstr += '&nickname=' + nickname;
      }
      httpobj.send( sendstr );
      if( this.httpStateCheck(httpobj) ){
        var data = txt2json(httpobj.responseText);
        if(data.status == "ok"){
          this.room_counter = data.room.counter;
          this.room_ticket = data.ticket;
          this.my_id = data.occupant_id;
          this.room_max_obs_time = data.max_observe_time;
          ret = true;
          displog(this.objname + ".enterRoom: OK"
                    + ", counter=" + this.room_counter
                    + ", ticket=" + this.room_ticket
                    + ", maxtime=" + this.room_max_obs_time);
          if(data.occupants != undefined && this.ocpchange_cb_func){
            this.ocpchange_cb_func(data.occupants);
          }
        } else {
          displog(this.objname + ".enterRoom: NG (return status)");
        }
      } else {
        displog(this.objname + ".enterRoom: NG (http stete check)");
      }
    } else {
      displog(this.objname + ".enterRoom: NG (createXMLHttpRequest)");
    }
    return ret;
  },


  enterRoomA:function(roomid, nickname, cb)
  {
    if(cb){
      this.entrm_cb_func = cb;
    }
    var ret = false;
    this.entrm_obj = this.createXMLHttpRequest(this.cb_enterRoomA.bind(this));
    if(this.entrm_obj){
      this.entrm_obj.open("POST", lingrcom_cgipath+"room.cgi", true);
      this.entrm_obj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      var sendstr = 'format=json'
         + '&session=' + this.session_id
         + '&id=' + roomid;
      if(nickname){
         sendstr += '&nickname=' + nickname;
      }
      this.entrm_obj.send( sendstr );
      displog(this.objname + ".enterRoomA: req");
      return true;
    }
    else{
      displog(this.objname + ".enterRoomA: NG (createXMLHttpRequest)");
      return false;
    }
  },


  cb_enterRoomA:function()
  {
    var ret = false;
    if( this.httpIsReady(this.entrm_obj) ){
      if( this.httpStateCheck(this.entrm_obj) ){
        var data = txt2json(this.entrm_obj.responseText);
        if(data.status == "ok"){
          this.room_counter = data.room.counter;
          this.room_ticket = data.ticket;
          this.my_id = data.occupant_id;
          this.room_max_obs_time = data.max_observe_time;
          ret = true;
          displog(this.objname + ".cb_enterRoomA: OK"
                    + ", counter=" + this.room_counter
                    + ", ticket=" + this.room_ticket
                    + ", maxtime=" + this.room_max_obs_time);
          if(data.occupants != undefined && this.ocpchange_cb_func){
            this.ocpchange_cb_func(data.occupants);
          }
        } else {
          displog(this.objname + ".cb_enterRoomA: NG (return status)");
        }
      } else {
        displog(this.objname + ".cb_enterRoomA: NG (http stete check)");
      }
      if( this.entrm_cb_func ){
        this.entrm_cb_func(ret);
      }
    }
  },


  setNickname:function(nickname)
  {
    var ret = false;
    var httpobj = this.createXMLHttpRequest(null);
    if(httpobj){
      httpobj.open("POST", lingrcom_cgipath+"nick.cgi", false);
      httpobj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      httpobj.send(
           'format=json'
           + '&session=' + this.session_id
           + '&ticket=' + this.room_ticket
           + '&nickname=' + nickname
           );
      if( this.httpStateCheck(httpobj) ){
        var data = txt2json(httpobj.responseText);
        if(data.status == "ok") {
          this.nickname = nickname;
          ret = true;
          displog(this.objname + ".setNickname: OK");
        } else {
          displog(this.objname + ".setNickname: NG (return status)");
        }
      } else {
        displog(this.objname + ".setNickname: NG (http stete check)");
      }
    } else {
      displog(this.objname + ".setNickname: NG (createXMLHttpRequest)");
    }
    return ret;
  },


  say:function(str, cb)
  {
    var ret = false;
    if(cb){
      this.say_cb_func = cb;
    }
    this.say_obj = this.createXMLHttpRequest(this.cb_say.bind(this));
    if(this.say_obj){
      this.say_obj.open("POST", lingrcom_cgipath+"say.cgi", true);
      this.say_obj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      this.say_obj.send(
           'format=json'
           + '&session=' + this.session_id
           + '&ticket=' + this.room_ticket
           + '&message=' + encodeURIComponent(str)
           );
      ret = true;
      displog(this.objname + ".say: msg=" + str);
    }
    else{
      displog(this.objname + ".say: NG (createXMLHttpRequest)");
    }
    return ret;
  },


  cb_say:function()
  {
    var ret = false;
    if( this.httpIsReady(this.say_obj) ){
      if( this.httpStateCheck(this.say_obj) ){
        var data = txt2json(this.say_obj.responseText);
        if(data.status == "ok"){
          ret = true;
          displog(this.objname + ".cb_say: text=" + data.message.text);
        } else {
          displog(this.objname + ".cb_say: NG (return status)");
        }
      } else {
        displog(this.objname + ".cb_say: NG (http stete check)");
      }
      if( this.say_cb_func ){
        if(ret){
          this.say_cb_func(data.message);
        } else {
          this.say_cb_func(null);
        }
      }
    }
  },


  observe:function(cb)
  {
    if(cb){
      this.observe_cb_func = cb;
    }
    var str = 'http://' + ( g_lingrcom_prefix_cnt++ ) + '.www.lingr.com/api/room/observe?'
             + 'format=json'
             + '&session=' + this.session_id
             + '&ticket=' + this.room_ticket
             + '&counter=' + this.room_counter
             + '&callback=' + this.objname + '.cb_observe'
             ;
    //displog(this.objname + ".observe :" + str);
    this.observe_obj = this.createJSONRequest(str);
    this.obs_timer = setTimeout(this.observe_timeout.bind(this), (this.room_max_obs_time+20)*1000);
  },


  cb_observe:function(data)
  {
    //clear timer
    if(this.obs_timer){
      clearTimeout(this.obs_timer);
    }
    //status check
    if( data.status != "ok") { 
      displog(this.objname + ".cb_observe: NG (status)");
      if( this.observe_cb_func ){
        this.observe_cb_func(null);
      }
      return;
    }
    //update counter
    if( data.counter == undefined ){
      displog(this.objname + ".cb_observe: Nothing happened " + (new Date()));
      //no callback and continue observe
    } else {
      this.room_counter = data.counter;
      if( data.messages == undefined ){
        displog(this.objname + ".cb_observe: No Messages");
        //no callback and continue observe
      } else {
        displog(this.objname + ".cb_observe: OK, text0=" + data.messages[0].text);
        if( this.observe_cb_func ){
          this.observe_cb_func(data.messages, this.my_id);
        }
      }
      if( data.occupants != undefined && this.ocpchange_cb_func ){
        this.ocpchange_cb_func(data.occupants, this.my_id);
      }
    }
    //remove dynamic script
    this.deleteJSONRequest(this.observe_obj);
    //restart observe
    this.observe();
  },


  observe_timeout:function()
  {
    displog(this.objname + ".observe_timeout");
    //remove dynamic script
    this.deleteJSONRequest(this.observe_obj);
    //restart observe
    this.observe();
  },


  getMessages:function(num, cb)
  {
    var ret = false;
    if(cb){
      this.getmsgs_cb_func = cb;
    }
    this.getmsgs_obj = this.createXMLHttpRequest(this.cb_getMessages.bind(this));
    if(this.getmsgs_obj){
      this.getmsgs_obj.open("POST", lingrcom_cgipath+"msgs.cgi", true);
      this.getmsgs_obj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      this.getmsgs_obj.send('format=json'
          + '&session=' + this.session_id
          + '&ticket=' + this.room_ticket
          + '&counter=' + num
          );
      ret = true;
      displog(this.objname + ".getMessages: " + num);
    }
    else{
      displog(this.objname + ".getMessages: NG (createXMLHttpRequest)");
    }
    return ret;
  },


  cb_getMessages:function()
  {
    var ret = false;
    if( this.httpIsReady(this.getmsgs_obj) ){
      if( this.httpStateCheck(this.getmsgs_obj) ){
        var data = txt2json(this.getmsgs_obj.responseText);
        if(data.status == "ok"){
          ret = true;
          if (data.messages == undefined ){
            displog(this.objname + ".cb_getMessages: No Messages");
            this.getmsgs_cb_func(null, this.my_id, true);
          } else {
            displog(this.objname + ".cb_getMessages: OK, num=" + data.messages.length);
            this.getmsgs_cb_func(data.messages, this.my_id, true);
          }
          if( data.occupants != undefined && this.ocpchange_cb_func ){
            this.ocpchange_cb_func(data.occupants, this.my_id);
          }
        } else {
          displog(this.objname + ".cb_getMessages: NG (return status)");
          this.getmsgs_cb_func(null, null, false);
        }
      } else {
        displog(this.objname + ".cb_getMessages: NG (http stete check)");
        this.getmsgs_cb_func(null, null, false);
      }
    }
  },


  setOcupantsChangeCallback:function(cb)
  {
    this.ocpchange_cb_func = cb;
  },


  leaveRoom:function()
  {
    var ret = false;
    var httpobj = this.createXMLHttpRequest(null);
    if(httpobj){
      httpobj.open("POST", lingrcom_cgipath+"exit.cgi", false);
      httpobj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      httpobj.send(
           'format=json'
           + '&session=' + this.session_id
           + '&ticket=' + this.room_ticket
           );
      if( this.httpStateCheck(httpobj) ){
        var data = txt2json(httpobj.responseText);
        if(data.status == "ok") {
          ret = true;
          displog(this.objname + ".leaveRoom: OK");
        }
      }
      else{
        displog(this.objname + ".leaveRoom: NG");
      }
    }
    else{
      displog(this.objname + ".leaveRoom: NG (createXMLHttpRequest)");
    }
    return ret;
  },


  destroySession:function()
  {
    var ret = false;
    var httpobj = this.createXMLHttpRequest(null);
    if(httpobj){
      httpobj.open("POST", lingrcom_cgipath+"destroy.cgi", true);
      httpobj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      httpobj.send(
           'format=json'
           + '&session=' + this.session_id
           );
      ret = true;
      displog(this.objname + ".destroySession");
    }
    else{
      displog(his.objname + ".destroySession: NG (createXMLHttpRequest)");
    }
    return ret;
  },




  createJSONRequest:function(url)
  {
    if( this.isOpera ){
      var uniqid = g_lingrcom_prefix_cnt;
      var img = document.createElement('img');
      img.setAttribute("src", url + "&noCacheIE=" + uniqid );
      img.setAttribute("id", "imgreq" + uniqid);
      var obj = document.createElement("script");
      img.onerror = function(e){
        obj.setAttribute("type", "text/javascript");
        obj.setAttribute("charset", "utf-8");
        obj.setAttribute('src', url + "&noCacheIE=" + uniqid );
        obj.setAttribute("id", "jsonreq" + uniqid);
        document.body.appendChild(obj);
      };
      img.width = 0;
      img.height = 0;
      document.body.appendChild(img);
      return [img, obj];
    }
    else{
      var uniqid = g_lingrcom_prefix_cnt;
      var obj = document.createElement("script");
      obj.setAttribute("type", "text/javascript");
      obj.setAttribute("charset", "utf-8");
      obj.setAttribute("src", url + "&noCacheIE=" + uniqid );
      obj.setAttribute("id", "jsonreq" + uniqid);
      document.getElementsByTagName("head").item(0).appendChild(obj);
      return obj;
    }
  },


  deleteJSONRequest:function(obj)
  {
    if( this.isOpera ){
      for(var i=0; i<obj.length; i++){
        if(obj[i]){
          var pn = obj[i].parentNode;
          if(pn) pn.removeChild(obj[i]);
        }
      }
    }
    else{
      document.getElementsByTagName("head").item(0).removeChild(obj);
    }
  },


  createXMLHttpRequest:function(cb)
  {
    var httpobj = null;
    try{
      httpobj = new XMLHttpRequest();
    }catch(e){
      try{
        httpobj = new ActiveXObject("Msxml2.XMLHTTP");
      }catch(e){
        try{
          httpobj = new ActiveXObject("Microsoft.XMLHTTP");
        }catch(e){
          return null;
        }
      }
    }
    if (httpobj && cb) {
      httpobj.onreadystatechange = cb;
    }
    return httpobj;
  },


  httpStateCheck:function(http)
  {
    if ((http.readyState == 4) && (http.status == 200)){
      return true;
    }
    else{
      return false;
    }
  },


  httpIsReady:function(http)
  {
    if ( http.readyState == 4 ){
      return true;
    }
    else{
      return false;
    }
  }


};
//end prototype


/////// Lingr Communicasion Class //////////////////////////////////////////////
