
var Try = {
  these: function() {
    var returnValue;

    for (var i = 0, length = arguments.length; i < length; i++) {
      var lambda = arguments[i];
      try {
        returnValue = lambda();
        break;
      } catch (e) {}
    }
    return returnValue;
  }
}

function newConn() {
  return Try.these(
    function() {return new XMLHttpRequest()},
    function() {return new ActiveXObject('Msxml2.XMLHTTP')},
    function() {return new ActiveXObject('Microsoft.XMLHTTP')}
  ) || false;
}

function doConnStateChange(){
  for (var i=0; i<conns.length; ++i){
    if (conns[i].conn.readyState == 4){
      if (conns[i].conn.status == 200){
        if (typeof conns[i].callback != 'undefined')
          conns[i].callback(conns[i].conn.responseText,conns[i].url);
      }
      conns.splice(i,1); --i;
    }
  }
}

var conns=new Array();

function connGet(_url,_callback){
  if (document.location.href.substr(0,4)=="file"){ lerror("local documents cannot listen on connections"); return; }
  var sconn;
  try {
    sconn = {conn: newConn(), callback: _callback, url: _url };
    if (sconn.conn===false){ lerror("unable to create connection"); return; }
    conns[conns.length]=sconn;
    sconn.conn.onreadystatechange = doConnStateChange;
    sconn.conn.open("GET",_url,true);
    sconn.conn.send("");
  } catch(e) {
    lerror("unable to setup connection");
  }
}

function connPost(_url,_data,_callback){
  if (document.location.href.substr(0,4)=="file"){ lerror("local documents cannot listen on connections"); return; }
  var sconn;
  try {
    sconn = {conn: newConn(), callback: _callback, url: _url };
    if (sconn.conn===false){ lerror("Unable to create connection"); return; }
    conns[conns.length]=sconn;
    sconn.conn.onreadystatechange = doConnStateChange;
    sconn.conn.open("POST",_url,true);

    sconn.conn.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    sconn.conn.setRequestHeader("Content-length", _data.length);
    sconn.conn.setRequestHeader("Connection", "close");

    sconn.conn.send(_data);
  } catch(e) {
    lerror("unable to setup connection");
  }
}

var listenConn=null;

function doConnListenStateChange(){
  if (listenConn.conn.readyState == 4){
    if (listenConn.conn.status == 200)
      listenConn.callback(listenConn.conn.responseText,listenConn.url);

    if (listenConn.conn.status != 0 && listenConn.conn.status != 404 && listenConn.conn.status != 12029){
      if (listenConn.conn.status != 200) 
        linfo("connection info, listenConn.status="+listenConn.conn.status);
      connListen(listenConn.callback);
    } else {
      lerror("connection failed, listenConn.status="+listenConn.conn.status);
    }
  }
}

function connListen(_callback){
  if (typeof _callback == 'undefined'){ lerror("undefined callback in connListen()"); return; }
  if (document.location.href.substr(0,4)=="file"){ lerror("local documents cannot listen on connections"); return; }

  var dte=new Date();

  try {
    listenConn = {conn: newConn(), callback: _callback, url: "/server.php?"+dte.valueOf()+"&sid="+sid+"&channel="+channel };
    if (listenConn.conn===false){ lerror("unable to create connection"); return; }
    listenConn.conn.onreadystatechange = doConnListenStateChange;
    listenConn.conn.open("GET","/server.php?"+dte.valueOf()+"&sid="+sid+"&channel="+channel,true);
    listenConn.conn.send("");
  } catch(e) {
    lerror("unable to setup listening connection: "+e);
  }
}


var sendConnections=0;
var sendConns=new Array();
var sendBuffer="";

function doConnSendStateChange(){
  for (var i=0; i<sendConns.length; ++i){
    if (sendConns[i].conn.readyState == 4){
/*
      if (sendConns[i].conn.status == 200){
        sendConns[i].callback(sendConns[i].conn.responseText,sendConns[i].url);
      }
*/
      --sendConnections;
      if (sendConns[i].conn.status != 200)
        connResendData(sendConns[i].data);
      sendConns.splice(i,1); --i;
    }
  }
  if (sendConnections<=1 && sendBuffer.length>0){
    ++sendConnections;
    connSendData();
  }
}

function connSendData(){
  if (sendBuffer.length==0) return;

  var sconn;
  var dte=new Date();

  try {
    sconn = {conn: newConn(), url: "/server.php?"+dte.valueOf()+"&sid="+sid+"&channel="+channel, data: sendBuffer };
    if (sconn.conn===false){ lerror("unable to create connection"); return; }
    sendConns[sendConns.length]=sconn;
    sconn.conn.onreadystatechange = doConnSendStateChange;
    sconn.conn.open("POST","/server.php?"+dte.valueOf()+"&sid="+sid+"&channel="+channel,true);
    sconn.conn.send(sendBuffer);
    sendBuffer="";
  } catch(e) {
    --sendConnections;
    lerror("DEVELTODO: look for connection to delete! unable to setup connection");
  }
}

function connResend(_data){
  lwarn("got error sending data (retrying): "+_data);

  if (sendBuffer.length>0)
    sendBuffer+=_data+";";
  else
    sendBuffer=_data;

  if (sendConnections<=1){
    ++sendConnections;
    connSendData();
//    setTimeout("connSendData();",25);
  }
}

function connSend(_data){
  if (document.location.href.substr(0,4)=="file"){ lerror("local documents cannot listen on connections"); return; }

  if (sendBuffer.length>0)
    sendBuffer+=";"+_data;
  else
    sendBuffer=_data;

  if (sendConnections<=1){
    ++sendConnections;
    setTimeout("connSendData();",25);
  }
}


function connStatus(_callback){
  var dte=new Date();
  connGet("/status.php?"+dte.valueOf()+"&sid="+sid+"&channel="+channel,_callback);
}



