(function($) {
  var listeners = {}
    ,last_ids = {}
    ,polling = {}
    ,access_id
    ,post_url = 'http://www.mobjet.com/rts'
    ,socket = new io.Socket(null, {port: 8124});

  if (io) {
    socket = new io.Socket(null, {port: 8124});
    socket.connect();
    socket.on('connect',function(evts) {
      $.each(listeners,function(type_key,listener) {
        $.each(listener||{},function(i,handler) {
          makeRequest(handler.poll_obj, type_key);
        });
      });
    });
    socket.on('message',function(evts) {
      var new_events = JSON.parse(evts);
      var type_key = new_events.shift();
      processNewEvents(new_events,type_key.orig_type);
    });
    socket.on('disconnect',function() {
      setTimeout(function() {
        socket.connect();
      },3000);
    });
  }

  var processNewEvents = function(new_events,type_key) {
    $.each(new_events,function(i,item) {
      var new_event = JSON.parse(item);
      if (!new_event['timeout']) { // if the event type is not a timeout event
        last_ids[type_key] = new_event.id;
        $.each(listeners[type_key]||{},function(i,handler) {
          handler.callback(new_event);
        });
        $(document).trigger( 'rtern.'+new_event.type, new_event );
      }
    });
  };

  var poll = function(match_evt,type_key) {
    var timer = null;
    var handleRtern = function(new_events) {
      clearTimeout( timer ); // kill the retry timer

      if (listeners[type_key] && listeners[type_key].length > 0) { // if there are listeners for this event type

        processNewEvents(new_events,type_key);

        delete polling[type_key];
        poll(match_evt,type_key);
      } else {
        delete polling[type_key];
      }
    };

    // see if we are already polling for that event
    if (!polling[type_key]) {
      // we are not so lets start a jsonp request
      polling[type_key] = true;
      var post_data = $.extend({aid: access_id, lid: last_ids[type_key]},match_evt);
      var poll_request = makeRequest( post_data, handleRtern );

      // try to re-connect if the connection never returned
      timer = setTimeout(function() {
        // if we haven't heard back in 10 seconds, try again
        poll_request.cancel();
        poll(match_evt,type_key);
      },70000);

    } else {
      //console.log('request is already running');
    }
  };

  var requestMethods = {
    json: function(post_data,callback) {
      var conn = $.ajax({ url: post_url, type: 'POST', data: post_data, dataType: 'json', success: callback});
      return {
        cancel: function() {
          conn.abort();
        }
      };
    },
    jsonp: function(post_data,callback) {
      $.ajax({ url: post_url, type: 'GET', data: post_data, dataType: 'jsonp', success: callback});
      return {
        cancel: function() {
          $('head script:first').remove();
        }
      };
    },
    socket_io: function(match_evt,type_key) {
      var post_data = $.extend({aid: access_id, lid: last_ids[type_key]},match_evt);
      socket.send(post_data);
      return { cancel: $.noop };
    }
  };

  var makeRequest = requestMethods.json;
  if (post_url.split(':').length > 2) {
    // if there is a port specified, lets assume we need jsonp
    makeRequest = requestMethods.jsonp;
  }

  var methods = {
    init: function(options) {
      if (options['request_method'] && requestMethods[options['request_method']]) {
        makeRequest = requestMethods[options['request_method']];
      }
      return this;
    },
    setAccessId: function(aid) {
      access_id = aid;
      return this;
    },
    bind: function(check,callback) {
      var type = check;
      var data = null;
      var type_key = check;
      if (typeof(check) == 'object') {
        type = check['type'];
        type_key = JSON.stringify(check);
        if (check['data']) data = check['data'];
      }
      if (!listeners[type_key]) listeners[type_key] = [];
      var poll_obj = {type: type};
      listeners[type_key].push({ callback: callback, poll_obj: poll_obj });
      if (data) poll_obj['data'] = data;
      if (makeRequest == requestMethods.socket_io) {
        makeRequest(poll_obj,type_key);
      } else {
        poll(poll_obj,type_key); // start the long poller
      }
      return this;
    },
    unbind: function(check) {
      var type_key = check;
      if (typeof(check) == 'object') {
        type_key = JSON.stringify(check);
      }
      delete last_ids[type_key];
      delete listeners[type_key];
      if (makeRequest == requestMethods.socket_io) {
        socket.send({ del: type_key });
      }
      return this;
    }
  };

  $.fn.rtern = function( method ) {
    // Method calling logic
    if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.rtern' );
    }    
  };

})(jQuery);

