/******************
 * Please read the license agreement.
 * You may not remove or change this notice.
 * Do not sell this as your own work or remove this copyright notice.
 * This script is freely distributable under the terms of 
 *    an MIT-style license (http://www.opensource.org/licenses/mit-license.php)
 * Copyright Tim Tully 2006. All rights reserved.
 * 
 * BlueBridgeAPI is a class to talk to the BlueBridge backend w/o 
 * using any middle tier logic. 
 * @author Tim Tully(tully_tim@yahoo.com)
 * @author Kristopher Tate(kris@bbridgetech.com)
 * @version 1.0
 * @constructor
 * @param {String} key This is the application key
 * @param {String} shared_secret This is the shared secret for the user
 *******/

/**
*
*  UTF-8 data encode / decode
*  http://www.webtoolkit.info/
*
**/

var Utf8 = {
  encode : function (string) {

    string = string.replace(/\r\n/g, "\n");

    var utftext = "";

    for (var n = 0; n < string.length; n++) {

      var c = string.charCodeAt(n);

      if (c < 128) {
        utftext += String.fromCharCode(c);
      }
      else if((c > 127) && (c < 2048)) {
        utftext += String.fromCharCode((c >> 6) | 192);
        utftext += String.fromCharCode((c & 63) | 128);
      }
      else {
        utftext += String.fromCharCode((c >> 12) | 224);
        utftext += String.fromCharCode(((c >> 6) & 63) | 128);
        utftext += String.fromCharCode((c & 63) | 128);
      }

    }

    return utftext;
  },

  // public method for url decoding
  decode : function (utftext) {
    var string = "";
    var i = 0;
    var c = c1 = c2 = 0;

    while ( i < utftext.length ) {

      c = utftext.charCodeAt(i);

      if (c < 128) {
        string += String.fromCharCode(c);
        i++;
      }
      else if((c > 191) && (c < 224)) {
        c2 = utftext.charCodeAt(i+1);
        string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
        i += 2;
      }
      else {
        c2 = utftext.charCodeAt(i+1);
        c3 = utftext.charCodeAt(i+2);
        string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
        i += 3;
      }

    }

    return string;
  }
}

var hexchars = "0123456789ABCDEF";

function toHex(n) {
  return hexchars.charAt(n>>4)+hexchars.charAt(n & 0xF);
}

var okURIchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";


function encodeURIComponentNew(s) {
  var s = Utf8.encode(s);
  var c;
  var enc = "";
  for (var i= 0; i<s.length; i++) {
    if (okURIchars.indexOf(s.charAt(i))==-1)
      enc += "%"+toHex(s.charCodeAt(i));
    else
      enc += s.charAt(i);
  }
  return enc;
}


function json_parse(text) {
  return (/^(\s+|[,:{}\[\]]|"(\\["\\\/bfnrtu]|[^\x00-\x1f"\\]+)*"|-?\d+(\.\d*)?([eE][+-]?\d+)?|true|false|null)+$/.test(text)) &&
            eval('(' + text + ')');
}



function BlueBridgeAPI(service_name, api_key, shared_secret, auth_hash){
  this.service_name = service_name;
  this.auth_url = '/services/auth/?';
  this.rest_url = '/services/restproxy/';

  this.offline_queue = {};
  this.offline_interval = null;

  this.CONNECTION_STATUS = -1;

  this.api_key = api_key;
  this.shared_secret = shared_secret;
  this.auth_hash = auth_hash;

  pimg = new Image();
  pimg.src = '/images/status/available.png';
  pimg.src = '/images/status/away.png';
  pimg.src = '/images/silk/clock_stop.png';
  delete pimg;

}


BlueBridgeAPI.prototype.processForm = function(method, ajax_options, form) {  
  var elements = Form.getElements($(form));
  var element_dict = {};
  
  for (var i = 0; i < elements.length; i++) {
    var element = elements[i];
    var parameter = Form.Element.Serializers[ element.tagName.toLowerCase() ]( element );
    if (parameter) {
      var key = encodeURIComponent( element.name );
      if (key.length == 0) { continue; }
      element_dict[ key ] = parameter;
    }
  }

  return this.callMethodJSON(method, element_dict, ajax_options);
};

/******************
* This method calls a bluebridge api method using the passed hash params
*****************/
BlueBridgeAPI.prototype.callMethodXML = function(method, params, options) {
  return this._call(method, params);
}

BlueBridgeAPI.prototype.callMethodJSON = function(method, params, options) {
  params['format'] = 'json';
  params['nojsoncallback'] = 1; 
  return this._call(method, params, options);
}

BlueBridgeAPI.prototype.setStatus = function(status) {
  try {
    $('#connection_status_throbber').removeClass('tx');
    var conn_indicator = 0;
    if (status == 0 && this.CONNECTION_STATUS != status) {//Okay
      $('#connection_status_throbber').attr('src', '/images/status/available.png');
      conn_indicator = $('#connection_status_condition > span.green');
      $('#status_connection_err').slideUp(300);
    } else if (status == -1 && this.CONNECTION_STATUS != status) {
      $('#status_connection_err').slideDown(300);
      $('#connection_status_throbber').attr('src', '/images/status/away.png');
      conn_indicator = $('#connection_status_condition > span.red');
    }
    if (conn_indicator != 0) {
      conn_indicator.css('display', null);
      conn_indicator.siblings().each(function(i,v) { $(v).css('display', 'none');  });
    }
    if (status == 0) $('#connection_status_lcdate').text( new Date().toLocaleString() );
    $('#connection_status_ltdate').text( new Date().toLocaleString() );
  } catch (e) {
    //console.log(e);
  }

  this.CONNECTION_STATUS = status;

}

BlueBridgeAPI.prototype.getQueue = function() {
  var a = [];
  for (api_sig in this.offline_queue) {a.push( this.offline_queue[ api_sig ] );}
  return a;
};


BlueBridgeAPI.prototype.emptyQueue = function() {
  if (this.CONNECTION_STATUS==0) {
    clearInterval(this.offline_interval);
    this.offline_interval == null;
    for (api_sig in this.offline_queue) {
      this._call( this.offline_queue[ api_sig ] );
    }
  }
};

BlueBridgeAPI.prototype.addToQueue = function( call_data ) {
  call_data['queued'] = 1;
  this.offline_queue[ call_data['api_sig'] ] = call_data;
  call_data['onqueue']();
  if (!this.offline_interval) {
    this.offline_interval = setInterval($.bind(this.emptyQueue, this), 100);
  }
  
};

BlueBridgeAPI.prototype.throb = function() {
  var ThrobFX = null;
  ThrobFX = function() {
    var $this = $(this);
    $this.fadeTo(200, 1.0, function() {
      if (!$this.hasClass('tx')) return;
      $this.fadeTo(200, 0.4, ThrobFX);
    });
  };
  $('#connection_status_throbber').addClass('tx').fadeTo(200, 0.4, ThrobFX);
};

BlueBridgeAPI.prototype._call = function(magic_param_one, params, options) {
  try {
    if (typeof(magic_param_one) == 'object') {
      options = magic_param_one;
    } else {
      params['src'] = 'js';
      params['method'] = this.service_name+'.'+magic_param_one;
      params['api_key'] = this.api_key;
      if (params['auth_token'] === undefined && this.auth_hash != "") { params['auth_token'] = this.auth_hash; }
      
      options['url'] = this.rest_url;
      options['type'] = 'POST';
      options['async'] = true;
      options['cache'] = false;
      options['evalScripts'] = true;
      options['dataType'] = 'json';

      var signed_data = this.signedUrl(params);
      options['api_sig'] = signed_data[0];
      options['data'] = signed_data[1];
      delete signed_data;
      
      options['timeout']        = ('timeout' in options ? options['timeout']:2000);
      options['onqueue']        = ('onqueue' in options ? options['onqueue']:null);
      options['onqueuesuccess'] = ('onqueuesuccess' in options ? options['onqueuesuccess']:null);
      options['queued']  = 0;
      
      var on_success = ('success' in options ? options['success']:null);
  
      var self = this;
      options['success'] = function (data, call) {
        self.setStatus(0);
        if (options['queued']) {
          delete self.offline_queue[ options['api_sig'] ];
          if (options['onqueuesuccess']) options['onqueuesuccess'](data, call);
        } else if (on_success) {
          on_success(data, call);
        }
      };
  
      var on_error = ('error' in options ? options['error']:null);
      options['error'] = function (XMLHttpRequest, textStatus, errorThrown) {
        if (options['onqueue'] || options['onqueuesuccess']) $.bind(self.addToQueue, self, options)();
        self.setStatus(-1);
        if (on_error) on_error(XMLHttpRequest, textStatus, errorThrown);
      };
    }
    
    this.throb();
    
    return $.ajax(options);
    
  } catch (e) {
    //console.log(e);
  }
}


BlueBridgeAPI.prototype.signedUrl = function (params){
  var temp_keys = [];
  var url = "";
  
  for (var p in params) {
//        params[p] = params[p];
    temp_keys.push(p);
    url += "&" + p + "=" + encodeURIComponent( params[p] );
  }

  temp_keys.sort();
  
  var cal = this.shared_secret;
  if (cal != "") {
    for (var i = 0; i < temp_keys.length; i++) {
      cal += temp_keys[i] + Utf8.encode( String(params[temp_keys[i]]) );
    }

    cal = hex_md5(cal);
    url = "api_sig=" + cal + url;
  } 
  return [cal, url];
}