(function($) {
  jQuery.extend(jQuery.easing,{
    easeInOutExpo: function (x, t, b, c, d) {
      if (t==0) return b;
      if (t==d) return b+c;
      if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
      return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
    }
  });


  $.fn.actAsInlineLabel = function(options){
    var opts = $.extend({}, $.fn.actAsInlineLabel.defaults, options);

    return this.each(function(){
      var wrapper = $(this)
      ,   input   = wrapper.find(':input:first')
      ,   label   = wrapper.find('.inline_example');

      if(!label.length){ label = wrapper.find('label:first'); }

      label.addClass('inline').click(function() { input.focus(); });
      if(input.val()){ wrapper.addClass('value_entered'); }

      input
      .focus(function(){
        wrapper.addClass('entering_text');
      })
      .blur(function(){
        wrapper.removeClass('entering_text');
        if(!input.val()){ wrapper.removeClass('value_entered'); }
      })
      .keypress(function(){
        wrapper.addClass('value_entered');
      })
      .keyup(function(){
        if(!input.val()){ wrapper.removeClass('value_entered'); }
      });
    });
  };


  // Adapted from Jonathan Snook
  $.fn.actAsSlideshow = function(options) {
    var opts = $.extend({}, $.fn.actAsSlideshow.defaults, options);

    return this.each(function() {
      var container = $(this);
      container.find('img:gt(0)').hide();
      setInterval(function(){
        container.find(':first-child').fadeOut()
                 .next('img').fadeIn(350)
                 .end().appendTo(container);
      }, opts.speed);
    });
  };

  $.fn.actAsSlideshow.defaults = { speed: 3500 };


  $.fn.actAsMailTo = function(options) {
    var opts = $.extend({}, $.fn.actAsMailTo.defaults, options);

    return this.each(function() {
      var address   = $(this).text().replace(opts.atCharacter, '@').replace(opts.dotCharacter, '.')
      ,   emailLink = '<a href="mailto:' + address + '">' + address + '</a>';

      $(this).replaceWith(emailLink);
    });
  };

  $.fn.actAsMailTo.defaults = {
     atCharacter: ' [at] ', // <space>[at]<space>
    dotCharacter: ' [dot] ' // <space>[dot]<space>
  };


  $.fn.scrollBody = function(duration) {
    return this.live('click',function(e) {
      var target = $($(this).attr('href'));

      $('body, html').animate({scrollTop: target.offset().top}, duration, 'easeInOutExpo');
      e.preventDefault();
    });
  };


  $.fn.safeFadeIn = function(duration) {
    return this.each(function() {
      $(this).animate({opacity: 0}, 0).animate({opacity: 1}, duration);
    });
  };


  $.fn.inlineNavigation = function(childrenSelector) {
    return this.each(function() {
      var parent = $(this);

      parent.find(childrenSelector).hide();
      parent.find(childrenSelector).first().show();
      parent.find('nav a').click(function(e) {
        e.preventDefault();
        var link   = $(this),
            target = $(link.attr('href'));

        parent.find(childrenSelector).hide();
        target.css({ left: '-20px', opacity: '0' }).show().animate({ left: '0', opacity: '1' }, 400);

        parent.find('nav a').removeClass('active');
        link.addClass('active');
      });
    });
  };
})(jQuery);


(function($) {
  $.fn.tweet = function(o){
    var s = {
      username: ['edgecase'], // [string]   required
      list: null,             // [string]   optional name of list belonging to username
      count: 6,               // [integer]  how many tweets to display?
      intro_text: null,       // [string]   do you want text BEFORE your your tweets?
      outro_text: null,       // [string]   do you want text AFTER your tweets?
      loading_text: null,     // [string]   optional loading text, displayed while tweets load
      query: null,            // [string]   optional search query
      refresh_interval: null  // [integer]  optional number of seconds after which to reload tweets
    };

    if(o){ $.extend(s, o); }

    $.fn.extend({
      linkUrl: function() {
        var returning = [];
        var regexp = /((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi;
        this.each(function() {
          returning.push(this.replace(regexp,"<a href=\"$1\" target=\"_blank\">$1</a>"));
        });
        return $(returning);
      },
      linkUser: function() {
        var returning = [];
        var regexp = /[\@]+([A-Za-z0-9-_]+)/gi;
        this.each(function() {
          returning.push(this.replace(regexp,"<a href=\"http://twitter.com/$1\" target=\"_blank\">@$1</a>"));
        });
        return $(returning);
      },
      linkHash: function() {
        var returning = [];
        var regexp = /(?:^| )[\#]+([A-Za-z0-9-_]+)/gi;
        this.each(function() {
          returning.push(this.replace(regexp, ' <a target="_blank" href="http://search.twitter.com/search?q=&tag=$1&lang=all&from='+s.username.join("%2BOR%2B")+'">#$1</a>'));
        });
        return $(returning);
      }
    });

    function parse_date(date_str) {
      // The non-search twitter APIs return inconsistently-formatted dates, which Date.parse
      // cannot handle in IE. We therefore perform the following transformation:
      // "Wed Apr 29 08:53:31 +0000 2009" => "Wed, Apr 29 2009 08:53:31 +0000"
      return Date.parse(date_str.replace(/^([a-z]{3})( [a-z]{3} \d\d?)(.*)( \d{4})$/i, '$1,$2$4$3'));
    }

    function relative_time(time_value) {
      var parsed_date = parse_date(time_value);
      var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
      var delta = parseInt(((relative_to.getTime() - parsed_date) / 1000), 10);
      var r = '';
      if (delta < 60) {
        r = delta + ' seconds ago';
      } else if(delta < 120) {
        r = 'a minute ago';
      } else if(delta < (45*60)) {
        r = (parseInt(delta / 60, 10)).toString() + ' minutes ago';
      } else if(delta < (2*60*60)) {
        r = 'an hour ago';
      } else if(delta < (24*60*60)) {
        r = '' + (parseInt(delta / 3600, 10)).toString() + ' hours ago';
      } else if(delta < (48*60*60)) {
        r = 'a day ago';
      } else {
        r = (parseInt(delta / 86400, 10)).toString() + ' days ago';
      }
      return 'about ' + r;
    }

    function build_url() {
      var proto = ('https:' == document.location.protocol ? 'https:' : 'http:');
      if (s.list) {
        return proto+"//api.twitter.com/1/"+s.username[0]+"/lists/"+s.list+"/statuses.json?per_page="+s.count+"&callback=?";
      } else if (s.query === null && s.username.length == 1) {
        return proto+'//api.twitter.com/1/statuses/user_timeline.json?screen_name='+s.username[0]+'&count='+s.count+'&include_rts=1&callback=?';
      } else {
        var query = (s.query || 'from:'+s.username.join(' OR from:'));
        return proto+'//search.twitter.com/search.json?&q='+encodeURIComponent(query)+'&rpp='+s.count+'&callback=?';
      }
    }

    return this.each(function(i, widget){
      var list    = $('<div class="tweet_list">').appendTo(widget);
      var intro   = '<p class="tweet_intro">'+s.intro_text+'</p>';
      var outro   = '<p class="tweet_outro">'+s.outro_text+'</p>';
      var loading = $('<p class="loading">'+s.loading_text+'</p>');

      if(typeof(s.username) == 'string'){
        s.username = [s.username];
      }

      if (s.loading_text){ $(widget).append(loading);}
      $(widget).bind("load", function(){
        $.getJSON(build_url(), function(data){
          if (s.loading_text){ loading.remove(); }
          if (s.intro_text){ list.before(intro); }
          list.empty();
          var tweets = (data.results || data);
          $.each(tweets, function(i,item){
            var from_user = item.from_user || item.user.screen_name;
            var profile_image_url = item.profile_image_url || item.user.profile_image_url;
            var date = '<span class="tweet_time"><a target="_blank" href="http://twitter.com/'+from_user+'/statuses/'+item.id+'" title="view tweet on twitter">'+relative_time(item.created_at)+'</a></span>';
            var text = '<p class="tweet_text"><span class="quo">&#147;</span>' +$([item.text]).linkUrl().linkUser().linkHash()[0]+ '&#148;</p>';

            // until we create a template option, arrange the items below to alter a tweet's display.
            list.append('<div class="span-3">' + date + text + '</div>');

            list.children(':odd').addClass('last');
          });
          if (s.outro_text){ list.after(outro); }
          $(widget).trigger("loaded").trigger((tweets.length === 0 ? "empty" : "full"));
          if (s.refresh_interval) {
            window.setTimeout(function() { $(widget).trigger("load"); }, 1000 * s.refresh_interval);
          }
        });
      }).trigger("load");
    });
  };
})(jQuery);

/*****************************************
 * Flickr API (in jQuery)
 * version: 1.0 (02/23/2009)
 * written for jQuery 1.3.2
 * by Ryan Heath (http://rpheath.com)
 *****************************************/
(function($) {
  // core extensions
  $.extend({
    // determines if an object is empty
    // $.isEmpty({})             // => true
    // $.isEmpty({user: 'rph'})  // => false
    isEmpty: function(obj) {
      for (var i in obj) { return false; }
      return true;
    }
  });

  // base flickr object
  $.flickr = {
    // the actual request url
    // (constructs extra params as they come in)
    url: function(method, params) {
      return 'http://api.flickr.com/services/rest/?method=' + method + '&format=json' + '&api_key=' + $.flickr.settings.api_key + ($.isEmpty(params) ? '' : '&' + $.param(params)) + '&jsoncallback=?';
    },
    // translate plugin image sizes to flickr sizes
    translate: function(size) {
      switch(size) {
        case 'sq': return '_s'; // square
        case 't' : return '_t'; // thumbnail
        case 's' : return '_m'; // small
        case 'm' : return '';   // medium
        default  : return '';   // medium
      }
    },
    // determines what to do with the links
    linkTag: function(text, photo, href) {
      if (href === undefined) { href = ['http://www.flickr.com/photos', photo.owner, photo.id].join('/'); }
      return '<a class="photo span-1" href="' + href + '" title="' + photo.title + '" target="_blank">' + text + '</a>';
    }
  };

  // helper methods for thumbnails
  $.flickr.thumbnail = {
    src: function(photo, size) {
      if (size === undefined) { size = $.flickr.translate($.flickr.settings.thumbnail_size); }
      return 'http://farm' + photo.farm + '.static.flickr.com/' + photo.server +  '/' + photo.id + '_' + photo.secret + size + '.jpg';
    },
    imageTag: function(image) {
      return '<img src="' + image.src + '" alt="' + image.alt + '" />';
    }
  };

  // accepts a series of photos and constructs
  // the thumbnails that link back to Flickr
  $.flickr.thumbnail.process = function(photos) {
    var thumbnails = $.map(photos.photo, function(photo) {
      var image     = new Image(), html = '', href = undefined;
          image.src = $.flickr.thumbnail.src(photo);
          image.alt = photo.title;

      var size = $.flickr.settings.link_to_size;
      if (size !== undefined && size.match(/sq|t|s|m|o/)) {
        href = $.flickr.thumbnail.src(photo, $.flickr.translate(size));
      }

      html = $.flickr.linkTag($.flickr.thumbnail.imageTag(image), photo, href);

      return html;
    }).join("\n");

    return thumbnails;
  }

  // handles requesting and thumbnailing photos
  $.flickr.photos = function(method, options) {
    var options  = $.extend($.flickr.settings, options || {}),
        elements = $.flickr.self, photos;

    return elements.each(function() {
      $.getJSON($.flickr.url(method, options), function(data) {
        photos = (data.photos === undefined ? data.photoset : data.photos);
        elements.append($.flickr.thumbnail.process(photos));
      });
    });
  };

  // namespace to hold available API methods
  // note: options available to each method match that of Flickr's docs
  $.flickr.methods = {
    // http://www.flickr.com/services/api/flickr.photos.getRecent.html
    photosGetRecent: function(options) {
      $.flickr.photos('flickr.photos.getRecent', options);
    },
    // http://www.flickr.com/services/api/flickr.photos.getContactsPublicPhotos.html
    photosGetContactsPublicPhotos: function(options) {
      $.flickr.photos('flickr.photos.getContactsPublicPhotos', options);
    },
    // http://www.flickr.com/services/api/flickr.photos.search.html
    photosSearch: function(options) {
      $.flickr.photos('flickr.photos.search', options);
    },
    // http://www.flickr.com/services/api/flickr.photosets.getPhotos.html
    photosetsGetPhotos: function(options) {
      $.flickr.photos('flickr.photosets.getPhotos', options);
    }
  };

  // the plugin
  $.fn.flickr = function(options) {
    $.flickr.self = $(this);

    // base configuration
    $.flickr.settings = $.extend({
      api_key: 'YOUR API KEY',
      thumbnail_size: 'sq'
    }, options || {});

    return $.flickr.methods;
  };
})(jQuery);

