$.fn.section = function() {
  var element = $(this[0]);
  var section = element.data('section');
  return section ? section : element.data('section', new Section(element));
};

$(document).ready(function() {
  Accordion.init($('#page'));
});

var Accordion = {
  speed: 0.66,
  init: function(root) {
    this.root = root;
    $('.section').each(function() { $(this).section(); })
    $('h2').click(function() {
      $('#' + this.id + ' + .section').section().toggle();
    });
  },
  open: function() {
    this.root.animate({ paddingTop: 0 }, 500);
  },
  close: function() {
    this.root.animate({ paddingTop: 120 }, 500);
  }
}

var Section = function(element) {
  Section.all.push(this);

  this.element = element;
  this.slideshows = $('.gallery', this.element).map(function() {
    var type = $(this).hasClass('slideshow') ? Slideshow : Gallery;
    var gallery = new type($(this));
    if(type == Slideshow) return gallery;
  }).filter(function() { return this; });

  this.height = element.height();
  this.speed = this.height / Accordion.speed;
  this.state = 'closed';
  this.element.css({ height: 0 });
};
$.extend(Section, {
  all: [],
  allSectionsClosed: function() {
    for(var i = 0; i < Section.all.length; i++) {
      if(Section.all[i].state == 'open') return false;
    }
    return true;
  }
})
Section.prototype = {
  toggle: function() {
    this.state == 'closed' ? this.open() : this.close();
  },
  open: function() {
    this.element.animate({ height: this.height, paddingBottom: '3em', color: '#777' }, this.speed);
    this.state = 'open';
    Accordion.open();
    $.each(this.slideshows, function() { this.start(); });
  },
  close: function() {
    this.element.animate({ height: 0, paddingBottom: 0, color: '#fff' }, this.speed);
    this.state = 'closed';
    if(Section.allSectionsClosed()) {
      Accordion.close();
    }
    $.each(this.slideshows, function() { this.stop(); });
  }
};

var Gallery = function(element) {
  if(!element) return;

  this.element = element;
  this.current = this.first();

  element.css({ height: $(element).attr('data-height') + 'px'});
  $('li', element).each(function(index) {
    if(index != 0) $(this).hide();
    $(this).css({ position: 'absolute' });
  });
  if(!element.hasClass('slideshow')) {
    this.initLinks();
  }
}
$.extend(Gallery, {
  options: {
    transition: {
      duration: 1000
    }
  }
});
Gallery.prototype = {
  initLinks: function() {
    $('img', this.element).after(
      '<div class="tools">' +
      '  <a class="prev"><span></span></a>' +
      '  <a class="next"><span></span></a>' +
      '</div>'
    );
    this.initLink('.prev', this.prev);
    this.initLink('.next', this.next);
  },
  initLink: function(selector, image) {
    var gallery = this;
    $(selector, this.element).click(function(event) {
      gallery.activate(image.apply(gallery));
      event.preventDefault();
    });
  },
  activate: function(image) {
    this.deactivate();
    this.current = image;
    $(image).fadeIn(Gallery.options.transition.duration);
  },
  deactivate: function() {
    this.current.fadeOut(Gallery.options.transition.duration);
  },
  prev: function() {
    var prev = this.current.prev();
    return prev.length == 0 ? this.last() : prev;
  },
  next: function() {
    var next = this.current.next();
    return next.length == 0 ? this.first() : next;
  },
  first: function() {
    return $('li:first-child', this.element);
  },
  last: function() {
    return $('li:last-child', this.element);
  }
};

Slideshow = function(element) {
  Gallery.call(this, element);
};
$.extend(Slideshow, {
  started: [],
  paused: false,
  options: {
    transition: {
      duration: 1500
    }
  }
});
Slideshow.prototype = $.extend(new Gallery, {
  start: function() {
    Slideshow.started.push(this);
    this.state = 'running';
    this.animate();
  },
  stop: function() {
    this.state = 'stopped';
  },
  animate: function() {
    if(this.state == 'stopped') return;
    
    var slideshow = this;
    setTimeout(function() {
      if(!Slideshow.paused) {
        slideshow.activate(slideshow.next());
      }
      slideshow.animate();
    }, Slideshow.options.transition.duration);
  }
});

// animate colors from JQuery UI Effects
jQuery.effects || (function($) {
  $.each(['color'], function(i,attr){
    $.fx.step[attr] = function(fx) {
      if (fx.state == 0) {
        fx.start = getColor(fx.elem, attr);
        fx.end = getRGB(fx.end);
      }
      fx.elem.style[attr] = "rgb(" + [
        Math.max(Math.min(parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0],10), 255), 0),
        Math.max(Math.min(parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1],10), 255), 0),
        Math.max(Math.min(parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2],10), 255), 0)
      ].join(",") + ")";
    };
  });
  function getRGB(color) {
    var result;
    if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))
      return [parseInt(result[1],10), parseInt(result[2],10), parseInt(result[3],10)];
    if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))
      return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];
    return colors[$.trim(color).toLowerCase()];
  }
  function getColor(elem, attr) {
    var color;
    do {
      color = $.curCSS(elem, attr);
      if (color != '' && color != 'transparent' || $.nodeName(elem, "body")) break;
      attr = "backgroundColor";
    } while (elem = elem.parentNode);
    return getRGB(color);
  };
})(jQuery);