//
// config
//

var external_jquery_path = "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js";

//
// TwitterNology
//

function TwitterNology(update_interval_in_minutes){
  this.update_interval  = update_interval_in_minutes*1000*60 || false;
  this.mode             = null;
  this.callback         = this.log;
  this.params           = {};
  this.tweets           = [];
  return true;
};

TwitterNology.prototype.update = function(params){
  if(typeof this.mode == 'function'){
    this.updating = true;
    this.mode(this.params, this.callback);
  }else{
    return false;
  }
};


TwitterNology.prototype.get = function(url, params, callback){
  if(this.jquery_failed == true) return false;
  obj = this;
  params = params || this.params;
  this.request(url, params);
  
  // if(obj.update_interval && typeof obj.update_timer == 'undefined'){
  //   obj.update_timer = setInterval(obj.update, obj.update_interval);
  // }
  return true;
};

TwitterNology.prototype.request = function(url){
  var jsc = new Date().getTime();
  // Build temporary JSONP function
  jsonp = "jsonp" + jsc++;

  url = url + '?'+ this.obj_to_querystring(this.params) + '&callback='+jsonp;

  // Handle JSONP-style loading
  obj_callback_context = this;
  window[ jsonp ] = window[ jsonp ] || function( data ) {
    //if(typeof obj_callback_context.process_tweets !== "undefined"){
      obj_callback_context.process_tweets(data);
    //}
    
    // Garbage collect
    window[ jsonp ] = undefined;

    try {
      delete window[ jsonp ];
    } catch(e) {}

    if ( head ) {
      head.removeChild( script );
    }
    
  };
  
  // If we're requesting a remote document
	// and trying to load JSON or Script with a GET
	var head = document.getElementsByTagName("head")[0] || document.documentElement;
	var script = document.createElement("script");
	script.src = url;


	// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
	head.insertBefore( script, head.firstChild );

	// We handle everything using the script element injection
	return undefined;
  
};

TwitterNology.prototype.process_tweets = function(tweets){
  if(this.mode == this.search) tweets = tweets.results;
  if(this.updating){
      this.tweets = this.tweets.reverse();
      tweets.reverse();
  }
  if(tweets && tweets.length > 0){
    this.params.since_id=tweets[0].id;
    for (var i=0; i < tweets.length; i++) {
      tweets[i].text_processed = this.autolink(tweets[i].text);
      tweets[i].relative_time = this.relative_time(tweets[i].created_at);
      tweets[i].screen_name = tweets[i].from_user || tweets[i].user.screen_name;
      this.tweets.push(tweets[i]);
      //this.log(tweets[i]);
    }
    if(this.updating){
      this.tweets.reverse();
      tweets.reverse();
      this.updating = false;
    }
    
    if(this.callback){
      this.executeFunctionByName(this.callback, window, tweets);
    }
  }
  return tweets;
};

TwitterNology.prototype.process_params = function(params, mode, callback){
  this.params = params || {};

  //switching modes... ?
  if(this.mode != mode){
    this.mode = mode;
    //... so let's remove the since_id.
    delete(this.params.since_id);
    clearInterval(this.twitter_updater);
  }
  if(this.mode == this.search){
    this.params.rpp = '20';
  }
  if(this.callback != callback)
    this.callback = callback || false;
  
  return params;
};

TwitterNology.prototype.list = function(params, callback){
  //http://api.twitter.com/1/user/lists/list_id/statuses.format
  this.process_params(params, this.list, callback);
  this.get('http://api.twitter.com/1/'+this.params.screen_name+'/lists/'+this.params.list+'/statuses.json');
};

TwitterNology.prototype.user = function(params, callback){
  //http://api.twitter.com/1/statuses/user_timeline.format
  this.process_params(params, this.user, callback);
  this.get('http://api.twitter.com/1/statuses/user_timeline.json');
};

TwitterNology.prototype.search = function(params, callback){
  //http://search.twitter.com/search.format
  //max_id, q, rpp, page, since, since_id
  this.process_params(params, this.search, callback);
  this.get('http://search.twitter.com/search.json');
};

TwitterNology.prototype.get_tweets = function(callback){
  params = this.querystring_to_obj();
  
  if(params.q){
    this.search({q: params.q}, callback);
  }else if(params.u){
    this.user({screen_name: params.u}, callback);
  
  }else if(params.l){
    list = params.l.split('/');
    this.list({screen_name: list[0], list: list[1]}, callback);
  }
  
};

TwitterNology.prototype.relative_time = function(time_value) {
  var values = time_value.split(" ");
  time_value = values[2] + " " + values[1] + ", " + values[3] + " " + values[4] + " " + values[5];
  var parsed_date = Date.parse(time_value);
  var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
  var offset = relative_to.getTimezoneOffset() * 60000;
  var delta = parseInt((relative_to.getTime()-offset - parsed_date) / 1000, 10);
  delta = delta + (relative_to.getTimezoneOffset() * 60);
  
  if (delta < 60) {
    return 'Less than a minute ago';
  } else if(delta < 120) {
    return 'About a minute ago';
  } else if(delta < (60*60)) {
    return (parseInt(delta / 60, 10)).toString() + ' minutes ago';
  } else if(delta < (120*60)) {
    return 'About an hour ago';
  } else if(delta < (24*60*60)) {
    return 'About ' + (parseInt(delta / 3600, 10)).toString() + ' hours ago';
  } else if(delta < (48*60*60)) {
    return '1 day ago';
  } else {
    return (parseInt(delta / 86400, 10)).toString() + ' days ago';
  }
};

TwitterNology.prototype.autolink = function(text){
  var url_pattern = new RegExp(/\b(([\w-]+:\/\/?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|\/|\b)))/gi);
  var twitter_username_pattern = new RegExp(/@([A-Za-z0-9_]{1,15})(\s|$)/gi);
  var twitter_hash = new RegExp(/#(\w+)/gi);
  autolinked_text = text.replace(url_pattern, '<a href="$1" target="_blank">$1</a>').replace(/href="www/, 'href="http://www')
                        .replace(twitter_username_pattern,'<a href="http://twitter.com/$1" target="_blank">@$1</a>$2' )
                        .replace(twitter_hash, '<a href="http://search.twitter.com/search?q=%23$1" target="_blank">#$1</a>');

  return autolinked_text;
};

TwitterNology.prototype.obj_to_querystring = function(obj, forPHP, parentObject){
   if( typeof obj != 'object' ) return '';

   var rv = '';
   for(var prop in obj) if (obj.hasOwnProperty(prop) ) {
      var qname = parentObject
         ? parentObject + '.' + prop
         : prop;
       
      // Expand Arrays
      if (obj[prop] instanceof Array)
         for( var i = 0; i < obj[prop].length; i++ )
            if( typeof obj[prop][i] == 'object' )
               rv += '&' + obj2query( obj[prop][i], forPHP, qname );
            else
               rv += '&' + encodeURIComponent(qname) + (forPHP ? '[]' : '')
					+ '=' + encodeURIComponent( obj[prop][i] );

      // Expand Dates
      else if (obj[prop] instanceof Date)
         rv += '&' + encodeURIComponent(qname) + '=' + obj[prop].getTime();

      // Expand Objects
      else if (obj[prop] instanceof Object)
         // If they're String() or Number() etc
         if (obj.toString && obj.toString !== Object.prototype.toString)
            rv += '&' + encodeURIComponent(qname) + '=' + encodeURIComponent( obj[prop].toString() );
         // Otherwise, we want the raw properties
         else
            rv += '&' + obj2query(obj[prop], forPHP, qname);

      // Output non-object
      else
         rv += '&' + encodeURIComponent(qname) + '=' + encodeURIComponent( obj[prop] );

   }
   return rv.replace(/^&/,'');
};

TwitterNology.prototype.querystring_to_obj = function() {
  var q = location.search;
  var obj = {};
  
  if (q.length > 1){
    q = q.substring(1, q.length);
  }else{
    return {};
  }
  
  params = q.split('&');

  for (var i=0; i < params.length; i++) {
    params[i] = params[i].split('=');
  }

  for (var i=0; i < params.length; i++) {
    obj[ params[i][0] ] = decodeURIComponent(params[i][1]);
  }

  return obj;
};


TwitterNology.prototype.log = function(log){ if(typeof(console) != 'undefined') console.log(log); };

TwitterNology.prototype.executeFunctionByName = function(functionName, context, args ) {
  
  var args = Array.prototype.slice.call(arguments);
  args = Array(args[2]);
  var namespaces = functionName.split(".");
  var func = namespaces.pop();
  for(var i = 0; i < namespaces.length; i++) {
    context = context[namespaces[i]];
  }
  return context[func].apply(context, args);
};


function TwitterRiver(selector, config){
  config = config || {};
  this.jquery_loaded        = false;
  this.tweet_container      = selector;
  this.time_between_tweets  = config.time_between_tweets  || 10000;
  this.display_single_tweet = config.display_single_tweet || false;
  this.init();

  return true;
}

TwitterRiver.prototype.init = function(jquery_init_time){
  if(typeof(jquery_init_time) == 'undefined') jquery_init_time = 0;
  
  if (typeof(jQuery) !== 'undefined' && this.jquery_loaded === false) {
    this.jquery_loaded = true;
    
    this.tweet_container = jQuery(this.tweet_container);
    this.tweet_container.empty();
    
    this.tweet_list = jQuery('<ul class="twitter_river"></ul>');
    this.tweet_list.css({position:'relative'});

    this.tweet_container.append(this.tweet_list);
    

    this.tweet_list.css({margin:0,padding:0,listStyleType:'none'});
  } else {
    //create jquery script element
    var jqueryjs = document.createElement('script');
        jqueryjs.setAttribute("type","text/javascript");
        jqueryjs.setAttribute("src", external_jquery_path);
    document.getElementsByTagName("head")[0].appendChild(jqueryjs);
    
    // watch for it to load but don't wait forever
    if (jquery_init_time <= 5000) { 
      var obj = this;
      setTimeout(function(){obj.init(jquery_init_time + 200);}, 200); 
    } else {
      this.jquery_failed = true;
    }
  }
};

TwitterRiver.prototype.render_tweet = function(tweet){
  $tweet = jQuery('<li id=tweet_'+tweet.id+' class="tweet"></li>');

  $avatar = jQuery('<a href="http://twitter.com/'+tweet.screen_name+'" class="avatar"><img src="http://twitteravatar.appspot.com/users/avatar/'+tweet.screen_name+'" border="0"/></a>');
  
  $content = jQuery('<blockquote>'+tweet.text_processed+'</blockquote>');

  $cite = jQuery('<cite>'+tweet.screen_name+'</cite>');

  $time = jQuery('<span class="timestamp">'+tweet.relative_time+'</span>');
  
  $twitter_tools = jQuery('<ul class="tools"></ul>');
  
  retweet_text = encodeURI('RT @'+tweet.screen_name+': '+tweet.text);
  $retweet_link = jQuery('<li><a href="http://twitter.com/home/?status='+retweet_text+'">retweet</a></li>');

  $follow_link = jQuery('<li><a href="http://twitter.com/'+tweet.screen_name+'">follow</a></li>');

  $twitter_tools.append($retweet_link).append($follow_link);
  
  // $tweet.append($content).append($cite).append($avatar).append($time).append($twitter_tools);
  // removed cite because it was redundant for now.
  // removed time because it's busted in IE for some weird reason
  
  $tweet.append($content).append($avatar).append($twitter_tools);
  return $tweet;
};


TwitterRiver.prototype.auto_scroll = function(){
  obj = this;
  var current_tweet = 0;
  var total = obj.tweet_list.children('li').length;

  scroll_tweets = function(){
    if( current_tweet + 1 > total ) current_tweet = 0;
    targetOffset = jQuery( obj.tweet_list.children('li')[ current_tweet ] ).position().top;
    
    if(obj.display_single_tweet){
      animate_to = {scrollTop: targetOffset, height:jQuery(obj.tweet_list.children('li')[ current_tweet ]).height()};
    }else{
      animate_to = {scrollTop: targetOffset};
    }
    
    obj.tweet_container.animate(animate_to, 1000 );
    
    current_tweet++;
  };
  scroll_tweets();
  this.scroller_timer = setInterval( scroll_tweets, obj.time_between_tweets);
  
};

TwitterRiver.prototype.display_tweets = function(tweets){
  obj = this;
  if(this.jquery_loaded || typeof(jQuery) != 'undefined'){
    if(tweets){
      for (var i=0; i < tweets.length; i++) {
        this.tweet_list.append(this.render_tweet(tweets[i]));
      }
      this.auto_scroll();
    }
  }else{
    setTimeout(function(){obj.display_tweets(tweets);}, 200);
  }
};




TwitterRiver.prototype.scroll_to = function(tweet){
  targetOffset = tweet.position().top;
  this.tweet_container.animate({scrollTop: targetOffset}, 1000 );
};
//scroll to bottom:
//this.tweet_container.scrollTop(this.tweet_container.children('.twitter_river').height());



