var app, mouse;

var vimeo = "<object width=\"500\" height=\"384\"><param name=\"allowfullscreen\" value=\"true\" /><param name=\"allowscriptaccess\" value=\"always\" /><param name=\"movie\" value=\"http://vimeo.com/moogaloop.swf?clip_id=3794595&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=0&amp;show_portrait=0&amp;color=ffffff&amp;fullscreen=1\" /><embed src=\"http://vimeo.com/moogaloop.swf?clip_id=3794595&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=0&amp;show_portrait=0&amp;color=ffffff&amp;fullscreen=1\" type=\"application/x-shockwave-flash\" allowfullscreen=\"true\" allowscriptaccess=\"always\" width=\"500\" height=\"384\"></embed></object>";

function check_browser(callback) {
	BrowserDetect.init();
	var bd = BrowserDetect;
	if ((bd.version >= 4 && bd.browser == 'Safari') || (bd.browser == 'Chrome') || (document.location.href.indexOf("anyway") >= 0)) {
		callback();
	} else {
		$('incompatible').style.display = 'block';
		$('vimeo').innerHTML = vimeo;
	}
}

function $(id) {
	return document.getElementById(id);
}

function particle(e, x_, y_) {
	this.element = e;
	this.x = x_;
	this.y = y_;
	this.mass = 6;
	this.inv_mass = 1/6;
	this.px = x_;
	this.py = y_;
	
	this.update = function(force) {
		var ty = this.y, dy;
		
		dy = (this.y - this.py) * force;
		this.y += dy;
		this.py = ty;
		
		this.update_scroll();
	};
	
	this.update_scroll = function() {
		app.set(this.element, this.y);
	};
}

function spring(a_, b_) {
	this.a = a_;
	this.b = b_;
	this.rest_length = app.scrollbar_size;
	this.strength = 0.55;
	this.mamb = a_.inv_mass * b_.inv_mass;
	
	this.update = function(constrain) {
		var delta, dist, inv_mass_a, inv_mass_b, norm_dist_strength;
		
		delta = {x: this.b.x - this.a.x, y: this.b.y - this.a.y};
		dist = Math.sqrt(delta.x*delta.x + delta.y*delta.y) + 1;
		norm_dist_strength = (dist - this.rest_length) / (dist * (this.mamb)) * this.strength;
		
		if (!this.a.fixed) {
			this.a.y += delta.y*(norm_dist_strength*this.a.inv_mass) / 5;
			this.a.y = app.constrain(this.a.y, app.min_point, app.max_point);
		}
		
		if (!this.b.fixed) {
			this.b.y += delta.y*(-norm_dist_strength*this.b.inv_mass) / 5;
			this.b.y = app.constrain(this.b.y, app.min_point, app.max_point);
		}
	};
}

app = {
	initialize: function() {
		this.container = $('application');
		this.body_dimensions = {width: window.innerWidth, height: window.innerHeight};
		this.scrollbar_size = this.get_scrollbar_size();
		
		this.elements = [];
		this.particles = [];
		this.springs = [];
		this.make_all();
		
		this.friction = 0.9;
		this.timestep = 0.01;
		this.iterations = 2;
		
		this.mouse = mouse.initialize();
		this.reset();
		
		this.tick = setInterval(function() {
			app.update();
		}, 40);
	},
	update: function() {
		var force = 1 - this.friction * this.timestep * this.timestep, i, j, len;
		
		for (i=0, len=this.particles.length; i<len; i++) {
			this.particles[i].update(force);
		}
		
		for (i=this.iterations; i>0; i--) {
			for (j=0, len=this.springs.length; j<len; j++) {
				this.springs[j].update(i == 1);
			}
		}
	},
	make_all: function() {
		var size = Math.ceil(this.body_dimensions.width / this.scrollbar_size),
			elements = [], e, particles = [], p, previous, springs = [], s;
			
		for (var i=0; i<size; i++) {
			e = this.new_element();
			elements.push(e);
			
			p = new particle(e, i*this.scrollbar_size, this.body_dimensions.height/2);
			p.fixed = i === 0 || i == size-1;
			particles.push(p);
			
			if (previous != null) {
				s = new spring(previous, p);
				springs.push(s);
			}
			previous = p;
		}
		
		this.elements = elements;
		this.particles = particles;
		this.springs = springs;
	},
	reset: function() {
		this.container.style.width = this.elements.length * this.scrollbar_size + 'px';
		
		this.max = this.set(this.elements[0], this.body_dimensions.height-10).placeholder.offsetHeight;
		this.min = this.set(this.elements[0], 1).placeholder.offsetHeight;
		this.max_point = app.body_dimensions.height-10;
		this.min_point = 10;
		
		for (var i=0, len=this.elements.length; i<len; i++) {
			var element = this.elements[i];
			element.scrollbar.style.width = this.scrollbar_size + 'px';
			element.scrollbar.style.height = this.body_dimensions.height + 'px';
			this.set(element, 0);
		}
	},
	set: function(element, value) {
		var height = this.body_dimensions.height * this.body_dimensions.height / (value + 1);
		if (this.max && this.min) {
			height = this.constrain(height, this.max, this.min);
		}
		element.placeholder.style.height = height + 'px';
		element.scrollbar.scrollTop = element.scrollbar.scrollHeight;
		return element;
	},
	new_element: function() {
		var scrollbar, placeholder;
		scrollbar = document.createElement('div');
		scrollbar.className = 'scrollbar';
		placeholder = document.createElement('div');
		placeholder.className = 'placeholder';
		scrollbar.appendChild(placeholder);
		this.container.appendChild(scrollbar);
		return {scrollbar: scrollbar, placeholder: placeholder};
	},
	get_scrollbar_size: function() {
		var body = document.getElementsByTagName('body')[0];	
		body.style.overflow = 'hidden';
		var width = body.clientWidth;		
		body.style.overflow = 'scroll';
		width -= body.clientWidth;
		if (!width) {width = body.offsetWidth - body.clientWidth;}
		body.style.overflow = 'hidden';
		width += 1;
		return Math.floor(width/2) * 2;
	},
	constrain: function(value, min, max) {
		return value > max ? max : value < min ? min : value;
	}
};

mouse = {
	initialize: function() {
		window.addEventListener("mousemove", function(e) {
			mouse.catch_wave(e);
		}, false);
		return this;
	},
	catch_wave: function(e) {
		var i = Math.floor(e.clientX * app.particles.length / app.body_dimensions.width),
			reverse_y = app.body_dimensions.height - e.clientY;
		var range = app.body_dimensions.height / 10;
		var particle = app.particles[i], left = app.particles[i-1], right = app.particles[i+1];
		
		if (!particle.fixed && reverse_y + range > particle.y && reverse_y - range < particle.y) {
			particle.y += reverse_y - particle.y;
			if (!left.fixed) left.y += (reverse_y - left.y) / 2;
			if (!right.fixed) right.y += (reverse_y - right.y) / 2;
		}
	}
};

if (window.addEventListener) {
	window.addEventListener("load", function() {
		check_browser(function() {
			app.initialize();
		});
	}, false);
}