var Fujitsu = {};

Fujitsu.Event = Class.create({

  pageHtml: '<li class="event" id="event-#{id}">' +
            ' <h2 class="title">#{title}</h2>' +
            ' <span class="date">#{year}</span>' +
            ' <div class="content">' +
            '   <img class="image" src="#{image}" alt="#{title}" />' +
            '   <div class="description"><p>#{description}</p></div>' +
            ' </div>' +
            '</li>',
            
  linkHtml: '<p class="link"><a href="#{url}" target="_blank">#{title}</a></p>',
  
  markerHtml: '<div class="marker marker_#{markerClassName}" id="marker-#{id}" style="left: #{left}px"><div class="marker_container"><span class="year #{furtherClassName}">#{year}</span></div></div>',
  
  initialize: function(timeline, id, startsSelected, title, year, description, image, links) {
    this.timeline       = timeline;
    this.id             = id;
    this.startsSelected = startsSelected;
    this.title          = title;
    this.year           = year;
    this.description    = description;
    this.image          = image;
    this.links          = links;
    this.position       = this.calculateLeftPosition();
  },
  
  setMarkerClassName: function(name) {
    this.markerClassName = name;
  },
  
  render: function() {
    this.renderMarker();
    this.renderPage();
  },
  
  renderMarker: function() {
    var tpl = new Template(this.markerHtml)
    this.timeline.sliderElement.down(".markers").insert(tpl.evaluate({
      furtherClassName: this.startsSelected ? "selected" : "", 
      id: this.id, 
      year: this.year, 
      title: this.title, 
      left: this.position,
      markerClassName: this.markerClassName
    }));
    $("marker-" + this.id).observe("click", this.markerClickHandler.bind(this));    
  },
  
  markerClickHandler: function(event) {
    event.stop();
    this.timeline.moveHandleToClosestEvent(this.position);
  },
  
  renderPage: function() {
    this.timeline.eventsElement.insert(new Template(this.pageHtml).evaluate(this));
    this.pageElement = $("event-" + this.id);
    if (this.links) {
      this.links.each(function(link) {
        this.pageElement.down(".description").insert(new Template(this.linkHtml).evaluate(link));
      }.bind(this));      
    }
  },
  
  calculateLeftPosition: function() {
    var left = this.timeline.sliderDimensions.width * ((this.year - this.timeline.startYear) / (this.timeline.endYear - this.timeline.startYear));    
    return left;
  },
  
  select: function() {
    $("marker-" + this.id).down(".year").addClassName("selected");
  },
  
  deselect: function() {
    $("marker-" + this.id).down(".year").removeClassName("selected");
  }
});

Fujitsu.Timeline = Class.create({
    
  initialize: function(startYear, endYear) {    
    this.startYear            = startYear;
    this.endYear              = endYear;
    this.timelineElement      = $("timeline");
    this.sliderElement        = $("slider").down(".content");
    this.sliderDimensions     = this.sliderElement.getDimensions();
    this.eventsElement        = $("timeline").down(".events");
    this.slideHandleElement   = this.sliderElement.down(".handle");
    this.sliderTrackElement   = this.sliderElement.down(".track");
    this.events               = [];
  },
  
  addEvent: function(id, startsSelected, title, year, description, image, links) {
    var e = new Fujitsu.Event(this, id, startsSelected, title, year, description, image, links);    
    e.setMarkerClassName(this.events.length % 3 + 1);
    this.events.push(e);
    if (startsSelected)
      this.currentEvent = e;
  },
  
  setup: function() {
    this.eventsElement.setStyle({width: (parseInt(this.timelineElement.getStyle("width")) * this.events.length) + "px"});
    this.eventDimensions  = this.timelineElement.down(".container").getDimensions();
    this.renderEvents();    
    this.setupSlider();    
    this.timelineElement.down(".loading").hide();
    this.timelineElement.down(".welcome").show();
  },
  
  renderEvents: function() {
    this.events.each(function(item) {
      item.render();
    });
  },
  
  setupSlider: function() {
    this.handler = new Draggable("handle", {
      constraint: "horizontal",
      starteffect: null,
      endeffect: null,
      onEnd: this.onSlideChangeHandler.bind(this),
      snap: this.snapFunction.bind(this)
    });
    this.sliderTrackElement.observe("click", this.sliderTrackClickHandler.bind(this));
  },
  
  sliderTrackClickHandler: function(event) {
    event.stop();
    this.moveHandleToClosestEvent(event.pointerX() - this.sliderTrackElement.cumulativeOffset()[0])
  },
  
  snapFunction: function(x, y, draggable) {
    if (x < 0) 
      x = 0;
    if (x > this.sliderDimensions.width)
      x = this.sliderDimensions.width;
    return [x, y];
  },
    
  onSlideChangeHandler: function(handle) { 
    var position = parseInt(handle.element.getStyle("left"));    
    this.moveHandleToClosestEvent(position);
  },
  
  moveHandleToClosestEvent: function(position) {
    if (!this.started) {
      this.started = true;
      this.timelineElement.down(".welcome").hide();
      this.eventsElement.appear();
      this.sliderElement.down(".handle").appear();
    }
    var items = this.findPreviousAndNext(position);
    this.animationToClosestEvent(position, items[0], items[1])
  },
  
  animationToClosestEvent: function(position, previous, next) {
    var selectedEvent = null
    if (previous && !next){
      selectedEvent = previous;
    } else if (!previous && next) {      
      selectedEvent = next;
    } else if (previous && next) {
      var range = next.position - previous.position;
      selectedEvent = ((position - previous.position) > (range / 2)) ? next : previous;
    }        
    if (selectedEvent && selectedEvent != this.currentEvent) {
      if (this.currentEvent)
        this.currentEvent.deselect();
      this.currentEvent = selectedEvent;
      new Effect.Move(this.slideHandleElement, {y: 1, x: this.currentEvent.position, mode: "absolute", duration: 0.35, afterFinish: this.handleAnimationEndHandler.bind(this)})
    }    
  },
  
  handleAnimationEndHandler: function() {
    if (this.currentEvent) {
      this.currentEvent.select();
      this.showEvent(this.currentEvent)
    }
  },
  
  showEvent: function(event) {
    var left = event.pageElement.positionedOffset().left;
    new Effect.Move(this.eventsElement, {y: 0, x: -left, mode: "absolute"});
  },
  
  findPreviousAndNext: function(position) {
    var previous, next;
    this.events.each(function(item) {
      if (item.position <= position)
        previous = item;     
      if (!next && item.position >= position)
        next = item;
    });
    return [previous, next];
  }
});
