function animateBackground(element, shift, rate){
  var el = $$(element);
  shift = typeof(shift) != 'undefined' ? shift : 1;
  rate = typeof(rate) != 'undefined' ? rate : 50;
  el.store('bg-x',0);
  
  (function(){
    this.setStyle('background-position', this.retrieve('bg-x') + 'px 0px');
    this.store('bg-x', parseFloat(this.retrieve('bg-x')) + shift );
  }).periodical(rate,el);
}

function twinkle(elements){
  var minOpacity = 0.6;
  var maxOpacity = 1;
  var dur = 2200;
  elements.each(function(e){
    e.set('tween',{'duration':dur});
  });
  (function(){
    elements.each(function(e){
      e.fade(Math.random()*(maxOpacity-minOpacity) + minOpacity);
    });}).periodical(dur);
}

/******************
* CANVAS FUNCTIONS
******************/
function fillWithImage(canvas, im, offsetx){
  // offsetx = typeof(offsetx) != 'undefined' ? offsetx : 0;
  //   offsetx = ((offsetx % im.width) - im.width) % im.width;
  
  var ctx = canvas.getContext('2d');
  var pattern = ctx.createPattern(im,'repeat');
  ctx.fillStyle = pattern;
  ctx.fillRect(0,0,canvas.width,canvas.height);
  
  // for (var x = offsetx; x <= canvas.width; x+= im.width){
  //     for (var y = 0; y <= canvas.height; y+= im.height){
  //       ctx.drawImage(im, x, y, im.width, im.height);
  //     }
  //   }
}

function pixelate(canvas, blocksize, offsetx, wrapx){
  offsetx = typeof(offsetx) != 'undefined' ? offsetx : 0;
  wrapx = typeof(wrapx) != 'undefined' ? Math.round(wrapx) : canvas.width;
  offsetx = ((Math.round(offsetx) % wrapx) + wrapx) % wrapx;
  var ctx = canvas.getContext('2d');
  var imdata = ctx.getImageData(0, 0, canvas.width, canvas.height);
  for(var x = 0; x <= canvas.width; x += blocksize){
    for(var y = 0; y <= canvas.width; y += blocksize){
      var samplex = (x - offsetx + wrapx) % wrapx;
      var idx = (y*imdata.width + samplex) * 4;
      ctx.fillStyle = "rgba("+imdata.data[idx]+','+imdata.data[idx+1]+','+imdata.data[idx+2]+','+imdata.data[idx+3]+')';
      ctx.fillRect(x, y, blocksize,blocksize);
    }
  }
}

/********
* CLASSES
********/
var Showcase = new Class({
  initialize: function(element){
    this.element = $(element);
    this.sctitle = $$('.showcase-title');
    this.front = false;
    this.multi = false;
    element.addEvent('click',function(e){
      this.toggle();
    }.bind(this));
    this.element.setStyles({'z-index':'100','position':'relative' });
    this.sctitle.setStyles({'z-index':'100','position':'relative'});
    // Create new elements.
    this.overlay = new Element('div',{
      'events':{
        'click':(function(e){ this.toggle() }).bind(this)
      },
      'class':'overlay',
      'styles':{
        'width':'100%','height':'100%','z-index':'5',
        'position':'fixed', 'top':0, 'left':0
      },
    }).inject($(document.body),'top').fade('hide');
    
    this.toggleButton = new Element('a',{
      'class':'button toggle',
      'html':'show',
      'styles':{'z-index':10}
    }).inject(this.element,'top');
    
    $$([this.overlay,this.element]).addEvent('mousewheel',function(e){
      this.backward();
    }.bind(this))

    
    // If there's more than one item to show, hide the rest.
    if (this.element.getElements('ul').length > 0) {
      this.element.getElement('ul').addClass('clearfix');
      this.multi = true;     
      this.items = this.element.getElements('li'); 
      this.items.set('slide',{
        'duration':1000,
        'mode':'horizontal',
        'transition':'sine:in:out'});
      this.items.slide('hide');
      this.items.getParent().setStyle('float','left');
      this.items[0].slide('show');
      
      this.nextButton = new Element('a',{
        'events':{
          'click':(function(e){ this.shownext(); e.stopPropagation(); }).bind(this)
        },
        'class':'button next',
        'html':'next',
        'styles': {'z-index':10}
      }).inject(this.element,'top').fade('hide');
      
      this.moreCounter = new Element('span',{
        'class':'more',
        'html':('+'+(this.items.length - 1)),
        'title':'There are more images to view.'
      }).inject(this.element,'top')
    }
  },
  
  toggle: function(){
    if (!this.front){
      this.forward();
    } else {
      this.backward();
    }
  },
  
  forward: function(){
    this.front = true;
    $(document.body).setStyles({
      'overflow':'hidden',
      'padding-right': '15px'
    }).addClass('showcase-on');
    var scroll = new Fx.Scroll(window).start(0, this.element.getPosition($(document.body)).y-90);
    if (this.multi){
      this.nextButton.fade('in');
    }
    this.overlay.fade('in');
  },
  
  backward: function(){
    if ( this.front ){
      this.front = false;
      $(document.body).setStyles({
        'overflow':'auto',
        'padding-right': '0'
      }).removeClass('showcase-on');
      this.overlay.fade('out');
      if (this.multi){
         this.nextButton.fade('out');
       }
     }
  },
  
  shownext: function(){
    var cur = this.items.filter( function(item){
      return ( item.get('slide').open );
    })[0];
    cur.slide('out').fade('out');
    console.log(cur);
    var idx = this.items.indexOf(cur);
        console.log(idx);
    this.items[(idx+1) % this.items.length].slide('in').fade('in');
  }
})

/*****************
* HELPER FUNCTIONS
*****************/


/**
 * HSV to RGB color conversion
 *
 * H runs from 0 to 360 degrees
 * S and V run from 0 to 100
 * 
 * Ported from the excellent java algorithm by Eugene Vishnevsky at:
 * http://www.cs.rit.edu/~ncs/color/t_convert.html
 */
function hsvToRgb(h, s, v) {
  var r, g, b;
  var i;
  var f, p, q, t;
  
  // Make sure our arguments stay in-range
  h = ((h % 360) + 360) % 360;
  s = Math.max(0, Math.min(100, s));
  v = Math.max(0, Math.min(100, v));
  
  // We accept saturation and value arguments from 0 to 100 because that's
  // how Photoshop represents those values. Internally, however, the
  // saturation and value are calculated from a range of 0 to 1. We make
  // That conversion here.
  s /= 100;
  v /= 100;
  
  if(s == 0) {
    // Achromatic (grey)
    r = g = b = v;
    return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
  }
  
  h /= 60; // sector 0 to 5
  i = Math.floor(h);
  f = h - i; // factorial part of h
  p = v * (1 - s);
  q = v * (1 - s * f);
  t = v * (1 - s * (1 - f));

  switch(i) {
    case 0:
      r = v;
      g = t;
      b = p;
      break;
      
    case 1:
      r = q;
      g = v;
      b = p;
      break;
      
    case 2:
      r = p;
      g = v;
      b = t;
      break;
      
    case 3:
      r = p;
      g = q;
      b = v;
      break;
      
    case 4:
      r = t;
      g = p;
      b = v;
      break;
      
    default: // case 5:
      r = v;
      g = p;
      b = q;
  }
  
  return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
