// KimiStrip.js
// based on Posta.Strip.js, copyright 2007 Posta Inc.
// used with permission

var KimiStrip = new Class({

  options: {
    enlargeFromCenter: true,
    leftDisplacementDuration: 250, // ms
    activeWidth: 100,
    activeHeight: 75,
    inactiveWidth: 74,
    inactiveHeight: 56,
    kimiSpacing: 6  // don't set this in the stylesheet since we need to use the value in code (and parsing it doesn't work in all browsers)
  },

  initialize: function(container, options)
  {
    this.container = container;
    this.parseContainerContents();

    this.options = Object.extend(this.options, options || {});
    this.width = this.container.getSize().size.x;
    this.height = this.options.activeHeight;

    this.container.addClass('KimiStripContainer');
    this.container.setStyles({ height: this.height + 1, visibility: 'visible' });

    this.mouseIsOver = false;

    this.strip = KimiCore.createElement('div', 'KimiStrip');
    this.strip.setStyle('height', this.height + 2);
    this.strip.addEvent('mouseover', this.mouseOver.bindWithEvent(this));
    this.strip.addEvent('mouseleave', this.mouseLeave.bindWithEvent(this));
    this.strip.addEvent('mousemove', this.mouseMove.bindWithEvent(this));

    this.kimiWidth = this.getKimiWidth();
    this.zoomDisplacementLeft = 0 - ((this.options.activeWidth - this.options.inactiveWidth) / 2);

    //this.fxLeftDisplacement = new Fx.Styles(this.strip, { duration: this.options.leftDisplacementDuration, transition: Fx.Transitions.linear });
    this.fxLeftDisplacement = new Fx.Virtual({fps:80, duration: this.options.leftDisplacementDuration, transition: Fx.Transitions.Sine.easeOut, onSetStyle: this.updateLeftDisplacement.bind(this)});

    this.kimis = [];
    for (var i=0; i<this.kimiCount; i++)
    {
      var kimi = new KimiStripImage(this, this.options);
      kimi.inject(this.strip);
      this.kimis.push(kimi);
    }

    this.loadKimis();

    // nasty IE eternal loading glitch... we can't simply set this.container.innerHTML = '' here
    this.container.getChildren().each(function(child) {
        child.remove();
    });

    this.container.appendChild(this.strip);

    this.setLeft((KimiStrip.lastX > (this.scrollParams.viewPortWidth / 2)) ? this.scrollParams.stripScrollDistance : 0);
    if (typeof KimiPage != 'undefined') KimiPage.kimiThumbsMakeDraggable();
    
    window.addEvent('resize', this.handleResize.bind(this));
  },

  loadKimis: function()
  {
    for (var i=0; i<this.kimiCount; i++)
    {
      this.kimis[i].load(this.data[i]);
    }

    this.setScrollParams();
  },

  parseContainerContents: function()
  {
    // grab all kimi data from the container
    this.data = [];

    var aElements = this.container.getElements('a');
    aElements.each(function(a)
    {
      var img = a.getElement('img');
      var className = img.getAttribute('className') || img.getAttribute('class');
      this.data.push({ cursor: a.getStyle('cursor'), title: a.title, href: a.href, src: img.src, kp_animated: img.getAttribute('kp_animated') ? true : false, kp_img_url: img.getAttribute('kp_img_url'), className: className });
    }.bind(this));

    this.kimiCount = this.data.length;
  },

  getKimiWidth: function()
  {
    return this.options.inactiveWidth + this.options.kimiSpacing + 2 /* border-left + border-right */; // adjust these if settings in style.css#KimiStripImage change
  },

  handleResize: function(e)
  {
    try
    {
      this.setScrollParams();
    }
    catch(e)
    {
    
    }
  },

  setScrollParams: function(e)
  {
    var sw = this.kimiCount * this.kimiWidth;
    var containerSize = this.container.getSize();

    this.scrollParams = {
      stripWidth: sw,
      viewPortWidth: containerSize.size.x,
      scrollPortWidth: containerSize.size.x - this.kimiWidth,
      stripScrollDistance: (sw - containerSize.size.x) + this.options.kimiSpacing,
      containerPosX: this.container.getPosition().x
    };

    this.scrollParams.scrollPortX = this.scrollParams.containerPosX + (this.kimiWidth / 2);
    if (this.scrollParams.stripScrollDistance < 0) this.scrollParams.stripScrollDistance = 0;

    this.scrollParams.baseRate = this.scrollParams.stripScrollDistance / this.scrollParams.scrollPortWidth;
    this.scrollParams.enableLeftDisplacement = (this.scrollParams.stripWidth >= this.scrollParams.viewPortWidth);
    
    /*
    for (var i in this.scrollParams)
    {
      console.log(i + ':' + this.scrollParams[i]);
    }
    */
  },

  mouseMove: function(e)
  {
    if (this.dragIsActive) return;  // don't respond to mouse motions if a drag is active

    if (!this.mouseIsOver)
    {
      // IE7 handles a mouseMove event before the mouseOver event, so ignore this if it occurs
      this.mouseOver(e);
      return;
    }

    var x = this.calculateX(e);
    //console.log('x is ' + x);

    // if we're outside the scroll port to either side, jump to the terminal position
    if (x <= 0)
    {
      this.setLeft(0);
      this.fxLeftDisplacement.clearTimer();
      this.fxLeftDisplacement.set(0);
      return;
    }
    if (x >= this.scrollParams.scrollPortWidth)
    {
      this.setLeft(this.scrollParams.stripScrollDistance);
      if (!this.fxLeftDisplacement.isActive())
      {
        this.fxLeftDisplacement.clearTimer();
        this.fxLeftDisplacement.set(2 * this.zoomDisplacementLeft);
      }
      return;
    }

    var lx = KimiStrip.lastX;
    if (x == lx) return;

    var dx = x - lx;
    KimiStrip.lastX = x;

    var ssd = this.scrollParams.stripScrollDistance;
    var sl = this.stripLeft;

    // move the strip according to the (ratio of dx to total remaining x) over the total distance the strip has left to move
    var remainingScrollPortDistance;
    var remainingStripDistance;
    if (dx > 0)
    {
      remainingScrollPortDistance = (this.scrollParams.scrollPortWidth - lx);
      remainingStripDistance = (ssd - sl) + (-1 * this.zoomDisplacementLeft);
    }
    else if (dx < 0)
    {
      remainingScrollPortDistance = lx;
      remainingStripDistance = sl - this.zoomDisplacementLeft;
    }

    // if the ratio of remainingStripDistance to remainingScrollPortDistance is low, the strip will move slowly.  Limit this.
    var moveX;
    if (remainingStripDistance < remainingScrollPortDistance)
    {
      // move at the "base rate" of the PostaStrip
      moveX = dx * this.scrollParams.baseRate; // (dx * ssd) / this.scrollParams.scrollPortWidth;
    }
    else
    {
      moveX = (dx * remainingStripDistance) / remainingScrollPortDistance;
    }

    sl += moveX;
    this.setLeft(sl);
  },

  setLeft: function(left)
  {
    //console.log('setLeft: ' + left);
    if (!this.scrollParams.enableLeftDisplacement)
    {
      this.strip.style.left = '0px';
      return;
    }

    var ld = this.fxLeftDisplacement.get();

    // limit how far in each direction left can be set
    if (left < ld)
    {
      left = ld;
    }
    else
    {
      var rightLimit = this.scrollParams.stripScrollDistance;
      if (left > rightLimit)
      {
        left = rightLimit;
      }
    }

    this.stripLeft = left;
    this.strip.style.left = ((left * -1) + ld) + 'px';
  },

  calculateX: function(e)
  {
    var x = e.page.x - this.scrollParams.scrollPortX;
    var spw = this.scrollParams.scrollPortWidth;

    if (x < 0) x = 0;
    if (x > spw) x = spw;

    return x;
  },


  animateToLeftDisplacement: function()
  {
    if (this.options.enlargeFromCenter && this.scrollParams && (this.scrollParams.stripWidth > this.scrollParams.scrollPortWidth))
    {
      var targetLeft = 0;

      if (this.mouseIsOver)
      {
        targetLeft = this.zoomDisplacementLeft;
        if (this.kimis[0].isActive) targetLeft = 0;
        else if (this.kimis[this.kimiCount - 1].isActive)
        {
          targetLeft = (2 * this.zoomDisplacementLeft);
        }
      }

      this.fxLeftDisplacement.clearTimer();
      this.fxLeftDisplacement.custom(this.fxLeftDisplacement.get(), targetLeft);
    }
  },

  updateLeftDisplacement: function()
  {
    this.setLeft(this.stripLeft);
  },

  mouseOver: function(e)
  {
    if (this.dragIsActive) return;  // don't respond to mouseovers if a drag is active

    this.mouseIsOver = true;

    // set lastX to whatever X the event occurred at, to avoid a jump when mouseover happens
    KimiStrip.lastX = this.calculateX(e);

    this.animateToLeftDisplacement();
  },

  mouseLeave: function(e)
  {
    if (!this.dragIsActive)
    {
      this.mouseIsOver = false;
      this.shrinkActiveKimis();
      this.animateToLeftDisplacement();
    }
  },

  shrinkActiveKimis: function()
  {
    this.kimis.each(function(kimi)
    {
      if (kimi.isActive)
      {
        kimi.onMouseLeave();
      }
    });
  },

  notifyDragStarted: function()
  {
    // the page at large has notified us that a drag has started.  Suspend mouseLeave and mouseOut events
    this.dragIsActive = true;
  },

  notifyDragEnded: function()
  {
    // the page at large has notified us that a drag has ended.  Complete mouseLeave and mouseOut events
    this.dragIsActive = false;
    this.mouseLeave();

    this.kimis.each(function(kimi)
    {
      if (kimi.isActive)
      {
        kimi.onMouseLeave();
      }
    });
  }
});


// a moo.fx that is "Virtual" - that is, it doesn't move anything in the DOM, but provides current values and events to anyone who asks.
Fx.Virtual = Fx.Base.extend({

	initialize: function(options){
		this.element = {style: {virtual: 0}};
		this.setOptions(options);
		this.property = 'virtual';
	},

	increase: function(){
		this.setStyle(this.element, this.property, this.now);
	},

	setStyle: function(e, p, v){
		e.style[p] = v;
    if (this.options.onSetStyle) this.options.onSetStyle(v);
	},

  set: function(v){
    this.element.style.virtual = v;
  },

  doSetNow: function(v){
    this.setStyle(this.element, this.property, v);
  },

  get: function(){
    return this.element.style.virtual;
  },

  isActive: function() {
    return (this.now != this.to);
  }
});



// global init function
initKimiStrip = KimiStrip.init = function()
{
  // init the KimiStrip
  var elem = $$('.kimi_bag_area')[0];
  if (elem) KimiStrip.instance = new KimiStrip(elem);
};
