var dragEngaged = false;
var carouselRatio = 0;
var offset = 0;
var imgWidth = 420;
var carouselPadding = 240;
var keyMoveLocked = false;

function initialiseCarousel()
{
  new Ajax.Request('carousel.json', { onSuccess: function(transport){
    data = transport.responseText.evalJSON();
    
    // Calculate the width of the inner container
    $('carousel-inner').style.width = (data.length * imgWidth) + 'px';
    
    // Calculate the length of the scroller (proportional to width of the scrollable region)
    carouselRatio = ((data.length * imgWidth) + imgWidth) / $('carousel').getWidth();
    $('scroller').style.width = ($('carousel').getWidth() / carouselRatio) + 'px';
    
    // Add the images to the scrollable region
    for (var i=0; i<data.length; i++)
      Element.insert('carousel-inner', '<div class="carousel-item"><a href="' + data[i].url + '"><img src="' + data[i].image + '" class="carousel-item-image" /></a></div>');
    
    // Add the Scroll event handlers
    Event.observe('carousel', 'mousewheel', handleScrollWheel);
    Event.observe('scroller-container','click',handleCarouselJump);
    Event.observe('scroller','mousedown',handleCarouselDragStart);
    Event.observe('scroller','click',function(e){
      e = e || window.event;
      Event.stop(e);
    });
    Event.observe(document.body,'mouseup',handleCarouselDragStop);
    Event.observe(document.body,'mousemove',handleCarouselDrag);
    Event.observe(document,'keydown',handleCarouselKeyPress);
  }});
}

function constrainMovement(dest, offset)
{
  dest += offset;
  
  if (dest < 0) dest = 0;
  
  maxWidth = $('scroller-container').getWidth() - $('scroller').getWidth();
  if (dest > maxWidth) dest = maxWidth;
  
  return dest;
}

function handleScrollWheel(e)
{
  e = e || window.event;
  dest = constrainMovement($('scroller').positionedOffset()[0] + ((-1 * e.wheelDelta) / 50), 0);
  $('scroller').style.left = dest + 'px';
  $('carousel-inner').style.left = -1 * (carouselRatio * dest)  + 'px';
  Event.stop(e);
}

function handleCarouselJump(e)
{
  e = e || window.event;
  if (!dragEngaged)
  {
    hScrlWidth = $('scroller').getWidth() / 2;
    dest = (Event.pointerX(e) - $('scroller-container').cumulativeOffset()[0]);
    
    // Impose constraints on where click can send scroller
    maxWidth = $('scroller-container').getWidth() - hScrlWidth;
    if (dest < hScrlWidth) dest = hScrlWidth;
    if (dest > maxWidth) dest = maxWidth;
    
    // Calculate position of nearest image and centre view on that
    dest = (dest * carouselRatio) - ((imgWidth / 2) + carouselPadding);
    tmp = dest % imgWidth;
    dest += (tmp < imgWidth / 2) ? (-1 * tmp) : imgWidth - tmp;
    
    // Animate the transition of scroller and viewport
    new Effect.Move ('scroller', { x: dest / carouselRatio,
                                   y: 0,
                                   mode: 'absolute'});
    new Effect.Move ('carousel-inner', { x: -1 * dest,
                                   y: 0,
                                   mode: 'absolute'});
  }
  Event.stop(e);
}

function handleCarouselDragStart(e)
{
  e = e || window.event;
  offset = -1 * ((Event.pointerX(e) - $('scroller').cumulativeOffset()[0]) - ($('scroller').getWidth() / 2));
  dragEngaged = true;
  Event.stop(e);
}

function handleCarouselDragStop(e)
{
  e = e || window.event;
  if (dragEngaged)
  {
    dragEngaged = false;
    dest = $('scroller').positionedOffset()[0] + ($('scroller').getWidth() / 2);
    dest = (dest * carouselRatio) - ((imgWidth / 2) + carouselPadding);
    tmp = dest % imgWidth;
    dest += (tmp < imgWidth / 2) ? (-1 * tmp) : imgWidth - tmp;
    
    new Effect.Move ('scroller', { x: dest / carouselRatio,
                                   y: 0,
                                   mode: 'absolute'});
    new Effect.Move ('carousel-inner', { x: -1 * dest,
                                   y: 0,
                                   mode: 'absolute'});
  }
  Event.stop(e);
}

function handleCarouselDrag(e)
{
  if (dragEngaged)
  {
    e = e || window.event;
    dest = constrainMovement((Event.pointerX(e) - $('scroller-container').cumulativeOffset()[0]) - ($('scroller').getWidth() / 2), offset);
    $('scroller').style.left = dest + 'px';
    Event.stop(e);
  }
}

function handleCarouselKeyPress(e)
{
  if ((e.keyCode == 39 || e.keyCode == 63235) && !keyMoveLocked)
  {
    keyMoveLocked = true;
    dest = constrainMovement($('scroller').positionedOffset()[0] + (imgWidth / carouselRatio), 0);
    new Effect.Move ('scroller', { x: dest,
                                   y: 0,
                                   mode: 'absolute'});
    new Effect.Move ('carousel-inner', { x: -1 * dest * carouselRatio,
                                         y: 0,
                                         mode: 'absolute',
                                         afterFinish: function(){ keyMoveLocked = false; }});
  }
  else if ((e.keyCode == 37 || e.keyCode == 63234) && !keyMoveLocked)
  {
    keyMoveLocked = true;
    dest = constrainMovement($('scroller').positionedOffset()[0] - (imgWidth / carouselRatio), 0);
    new Effect.Move ('scroller', { x: dest,
                                   y: 0,
                                   mode: 'absolute'});
    new Effect.Move ('carousel-inner', { x: -1 * dest * carouselRatio,
                                         y: 0,
                                         mode: 'absolute',
                                         afterFinish: function(){ keyMoveLocked = false; }});
  }
}


Event.observe(window,'load',initialiseCarousel);