﻿//Template strings to use for dynamic population.
var Templates = {
	infographic: "<img src='_images/photos/aha/infographics/#{image}' alt='#{title}' /><h3>#{title}</h3><p>#{caption}</p>",
	caseStudeTeaser: "<a href='#{anchor}'><img class='hover' src='#{image}' alt='#{title}' /><p style='height: 0px; display: none;' class='hover'>Read the #{client} story.</p></a><h3>#{title}</h3><p>#{caption}</p>"
};

function randomizeMasthead(imageCount) {
  var masthead = $('masthead').select('h1')[0];
  var button = $('masthead').select('a')[0];
  var imageName = Math.floor(Math.random() * imageCount); //choose random image
  var locationMap = {
    "00": [188,150],
    "01": [182,225]
  }
  
  imageName = imageName < 10 ? '0' + imageName : imageName + ''; //convert to string, prepend zero if needed
  masthead.setStyle({ backgroundImage: 'url(/images/photos/home/' + imageName + '.jpg)'}); //clear default copy, update image
  button.setStyle({ left: locationMap[imageName][0] + 'px', top: locationMap[imageName][1] + 'px' });
};

//Modalizer does two things. It lets a user know that an item can be viewed - in detail - in a modal window and it
//provides/hides the modal window.
Modalizer = Class.create();
Object.extend(Modalizer.prototype, {
  initialize: function(parent, triggerPattern, options) {
    this.parent = $(parent);
    this.triggerPattern = triggerPattern;
    this.triggers = this.parent.select(this.triggerPattern);
    this.everything = $A();
    this.images = $A();
    this.modalElements = $('modal').select('*');
    this.slides = $$('div#slides div.slide');
    this.activeSlide = null;
    this.animating = false;
    this.count = $('modal').select('p.count span').first();
    this.options = Object.extend({
      position: 'top', //where we're popping the tooltip in relation to the pointer valid values are top, bottom, left or right
      distance: 5, //distance, in pixels, the tooltip appears in relation to the pointer,
      blurSize: 15, //size, in pixels, of the copy blur that happens on click
      blurDuration: 1.5 //default duration of blurring effects.
    }, options);
    
    $$('h1,h2,h3,p,em,div#tops a,span').each(function(element) {
      if (!this.modalElements.include(element)) {
        this.everything.push(element);
      }
    }.bind(this));
    
    $$('img').each(function(image) {
      if (!this.modalElements.include(image)) {
        this.images.push(image);
      }
    }.bind(this));
    
    if (Prototype.Browser.IE) { //tweak stuff for ie
      var flower = $('flowerGoesHere').down('img');
      this.images = this.images.reject(function(r) { return r == flower });
      $('slides').addClassName('ie');
    }
    
    this.addTip();
    this.startObserving(); //intialize observer
  },
  
  addTip: function() {
    this.tip = new Element('img');
    this.tip.onload = function() {
      this.parent.insert(this.tip);
      this.tipHeight = this.tip.height;
      this.tipWidth = this.tip.width;
      this.tip.setStyle( {
        position: 'absolute',
        display: 'none',
        zIndex: 9999,
        margin: '10px',
        behavior: 'none'
      });
    }.bind(this);
    this.tip.src = '/images/interface/enlarge.png';
  },
  
  startObserving: function() {
	  this.parent.observe('mousemove', this.handleMouseMove.bind(this));
	  this.parent.observe('click', this.handleMouseClick.bind(this));
  },
  
  stopObserving: function() {
    this.parent.stopObserving('mousemove');
	  this.parent.stopObserving('click');
    this.hideTip();
  },
  
  handleSlideClick: function(event) {
    event.stop();  //prevent bubbling
    if (!this.animating) {
      this.advanceSlide(event.element().id);
    }
  },
  
  advanceSlide: function(reference) {
    var direction = "next" == reference ? 1 : -1;
    var currentSlide = this.count.innerHTML * 1;
    var newSlideIndex = currentSlide + direction;
    if ((currentSlide == 1 && direction == -1) || (currentSlide == this.slides.length && direction == 1)) { return false; } //exit if we're at a boundary
    this.count.update(newSlideIndex);
    
    var effects = $A();
    
    //hide visible slide
    effects.push( new Effect.Fade(this.slides[this.activeSlide], { sync: true, to: 0.0, from: 1.0 }) );
    
    //reveal request slide
    effects.push( new Effect.Appear(this.slides[newSlideIndex - 1], { sync: true, to: 1.0, from: 0.0 }) );
    
    //trigger effects
    new Effect.Parallel(effects, {
      duration: .3,
      transition: Effect.Transitions.Cubic.easeOut,
      beforeStart: function() {
        this.animating = true;
      }.bind(this),
      afterFinish: function() {
        this.count.update(newSlideIndex);
        this.activeSlide = newSlideIndex - 1;
        this.animating = false;
      }.bind(this)
    });
  },
  
  handleMouseMove: function(event) {
    if (this.triggers.include(event.findElement(this.triggerPattern)) || this.activeHover(event)) {
      if (!this.tip.visible()) {
        this.popTip(event, event.findElement(this.triggerPattern)); //pop the tooltip
      } else {
        this.moveTip(event); //move the tooltip
      }
    } else {
      if (this.tip.visible() && !this.activeHover(event)) {
        this.hideTip(); //hide the tooltip
      }
    }
  },
  
  handleMouseClick: function(event) {
    var img = event.findElement('img');
    if (img && this.triggers.include(img)) {
      event.stop();
      this.showModal(this.triggers.indexOf(img));
    }
  },
  
  showModal: function(index) {
    this.stopObserving(); //kill hovers
    var effects = $A();
    var blurSize = this.options.blurSize;

    //identify and reveal requested slide
    this.slides.invoke('hide'); //hide any visible slides
    this.slides[index].show(); //reveal the requested slides
    this.activeSlide = index; //cache the index of the active slide
    this.count.update(index + 1);
    
    //push modal appearance into queue
    effects.push(new Effect.Appear('modal', { sync: true }));

    //push image fades into queue
    this.images.each(function(image) {
      effects.push(new Effect.Fade(image, { sync: true, to: .2 }));
    });
    
    //push blur effects into queue
    this.everything.each(function(thing) {
      effects.push(new Effect.Blur(thing, blurSize, { sync: true }));
    });

    //activate effects
    new Effect.Parallel(effects, {
      duration: this.options.blurDuration,
      transition: Effect.Transitions.Quint.easeOut,
      beforeStart: function() {
        this.hideTip(); //hide the tooltip
        this.attachModalListeners();
      }.bind(this) 
    });
  },
  
  attachModalListeners: function() {
    $('modal').observe('click', this.closeModal.bind(this));
	  $('previous','next').invoke('observe','click',this.handleSlideClick.bind(this));
  },
  
  detachModalListeners: function() {
    $('previous','next','modal').invoke('stopObserving','click'); //stop observers
  },
  
  closeModal: function(event) {
    if (event.element().id == 'modal' || event.element().id == 'closeButton') {
      var effects = $A();
      var blurSize = this.options.blurSize * -1;
      var everything = this.everything;
      
      //prep to de-blur
      this.everything.each(function(thing) {
        effects.push(new Effect.Blur(thing, blurSize, { sync: true, blurColor: thing.originalColor }));
      });
      
      //appear the images
      this.images.each(function(image) {
        effects.push(new Effect.Appear(image, { sync: true }));
      });
      
      //fade the modal
      effects.push(new Effect.Fade('modal', { sync: true, to: 0.0 }));
      
      //activate effects
        new Effect.Parallel(effects, {
          duration: this.options.blurDuration,
          transition: Effect.Transitions.Quint.easeOut,
          afterFinish: function() {
            this.activeSlide = null;
            this.slides.invoke('hide');
      	    this.detachModalListeners();
          }.bind(this)
        });
        
      //reattach observers
      this.startObserving();
    } else {
      return true
    }
  },
  
  popTip: function(event, element) {
    this.activeElement = element;
		if (this.effect) this.effect.cancel(); // cancel last effect
    this.moveTip(event); //put the tip in place
    
		this.tip.setStyle({ display: 'block', width: 0, height: 0 }); //reset tip
		this.effect = new Effect.Parallel([
		  new Effect.Appear(this.tip, { sync: true }),
		  new Effect.Morph(this.tip, { style: { width: this.tipWidth+'px', height: this.tipHeight+'px' }, sync: true })
		],
		{
		  duration: .2,
		  afterUpdate: this.setTipMargins.bind(this)

		});
  },
  
  moveTip: function(event) {
    this.tip.setStyle({ left: event.pageX+'px', top: event.pageY+'px' });
  },
  
  hideTip: function() {
		this.effect = new Effect.Parallel([
		  new Effect.Fade(this.tip, { sync: true }),
		  new Effect.Morph(this.tip, { style: { width: 0+'px', height: 0+'px' }, sync: true })
		],
		{
		  duration: .2,
		  afterUpdate: this.setTipMargins.bind(this),
		  queue: { scope: 'tipOut', limit: 1 }
		});
  },
  
  setTipMargins: function() {
		var width = this.tip.getWidth();
	  var height = this.tip.getHeight();

		switch(this.options.position) {
			case 'top':    var style = { marginLeft: -Math.round(width/2)+'px', marginTop: -(height+this.options.distance)+'px' }; break;
			case 'bottom': var style = { marginLeft: -Math.round(width/2)+'px', marginTop: this.options.distance+'px' }; break;
			case 'left':   var style = { marginLeft: -(width+this.options.distance)+'px', marginTop: -Math.round(height/2)+'px' }; break;
			case 'right':  var style = { marginLeft: this.options.distance+'px', marginTop: -Math.round(height/2)+'px' }; break;
		}
		
		this.tip.setStyle(style);
  },
  
  activeHover: function(event) {
    if (this.activeElement) {
      var offset = this.activeElement.cumulativeOffset();
      var startX = offset.left;
      var startY = offset.top;
      var endX = offset.left + this.activeElement.getWidth();
      var endY = offset.top + this.activeElement.getHeight();
      return (event.pageX >= startX && event.pageX < endX && event.pageY >= startY && event.pageY < endY);
    } else {
      return false;
    }
  }
});

var StoryTeaser = {
  initialize: function(parent, pattern) {
    this._parent = $(parent);
    this._pattern = pattern;
    this._targets = this._parent.select(pattern);
    this._parent.observe('mousemove', this.handleMouseMove.bind(this));
  },
  
  pushTarget: function(element) {
    this._targets.push($(element));
  },
  
  handleMouseMove: function(event) {
    var element = event.findElement(this._pattern);
    if ((this._targets.include(element) || this.activeHover(event)) && !this.activeElement) {
      this.showTeaser(event);
    } else if (this.activeElement && !this.activeHover(event)) {
      this.hideTeaser(event);
    }
  },
  
  activeHover: function(event) {
    if (this.activeElement) {
      var offset = this.activeElement.cumulativeOffset();
      var startX = offset.left;
      var startY = offset.top;
      var endX = offset.left + this.activeElement.getWidth();
      var endY = offset.top + this.activeElement.getHeight();
      return (event.pageX >= startX && event.pageX < endX && event.pageY >= startY && event.pageY < endY);
    } else {
      return false;
    }
  },
  
  showTeaser: function(event) {
    var anchor = event.findElement(this._pattern);
    if (anchor) {
      this.activeElement = anchor;
      var para = anchor.down('p');
      new Effect.Morph(para, {
	      style: 'height: 36px;',
	      beforeStart: function() { para.show(); },
	      duration: 0.15,
	      transition: Effect.Transitions.Cubic.easeInOut,
	      queue: { scope: 'ins', position: 'end', limit: 1 }
	    });
    }
  },
  
  hideTeaser: function(event) {
    var para = this.activeElement.down('p');
    new Effect.Morph(para, {
      style: 'height: 0px;',
      afterFinish: function() { para.hide(); this.activeElement = null; }.bind(this),
      duration: 0.15,
      transition: Effect.Transitions.Cubic.easeInOut,
      queue: { scope: 'outs', position: 'end', limit: 1 }
    });
  }
}
