/**
 *
 * More info: http://globalgamejam.org/2015/games/time-machine
 * Created by: @zacharyjohnson @mawaterston @torikamal
 *
 */


/*

//// TODO?

[ ] scifi/ui sounds
[ ] more steps

*/





/**
 * Globals
 .d8888b. 888        888             888         
d88P  Y88b888        888             888         
888    888888        888             888         
888       888 .d88b. 88888b.  8888b. 888.d8888b  
888  88888888d88""88b888 "88b    "88b88888K      
888    888888888  888888  888.d888888888"Y8888b. 
Y88b  d88P888Y88..88P888 d88P888  888888     X88 
 "Y8888P88888 "Y88P" 88888P" "Y888888888 88888P' 
**/
var BASEWIDTH = 800,
	BASEHEIGHT = 600,
	WIDTH = BASEWIDTH,
	HEIGHT = BASEHEIGHT,
	SCALE = 1,
	AUDIOPATH = 'audio/',
	glitchesOff = true;


(function ($) {

	"use strict";


	//
	// Namespace
	//
	window.TM = window.TM || {};



	/**
	 * View
	888     888d8b                      
	888     888Y8P                      
	888     888                         
	Y88b   d88P888 .d88b. 888  888  888 
	 Y88b d88P 888d8P  Y8b888  888  888 
	  Y88o88P  88888888888888  888  888 
	   Y888P   888Y8b.    Y88b 888 d88P 
	    Y8P    888 "Y8888  "Y8888888P"  
	**/
	TM.View = Class.extend({
		id: null,

		container: null,

		stage: null,

		options: null,
		defaults: {},

		init: function init(options) {
			this.options = $.extend(true, {}, this.defaults, options);

			this.container = this.options.container;

			this.id = this.options.id;
		} // init()
	}); // TM.View



	//
	// Glitch shader stuff
	//
	var i,
		x, y,
		block = 0,
		blocks = [],
		effects = [],
		fx,
		rand,
		audioGlitches = [],
		visualGlitches = [[1, 0]];

	function get_effect() {
		var fx = Math.floor(1 + Math.random() * 7);
		
		// Fewer fill glitches, more offset and smear glitches
		if (fx == 3 && Math.random() > 0.33) {
			fx = 2;
		} else if (fx == 6 && Math.random() > 0.33) {
			fx = 5;
		}

		return fx;
	}

	function get_block(x, y) {
		var bw = 1 / ((240 * 4) / (8 * 4)),
			bh = 1 / ((160 * 4) / (8 * 4)),
			rw = (240 * 4) / (8 * 4);

		return Math.floor(x / bw) + Math.floor(y / bh) * rw;
	}
	//
	//
	//



	/**
	 * TimeMachine
	88888888888d8b                     888b     d888                888     d8b                 
	    888    Y8P                     8888b   d8888                888     Y8P                 
	    888                            88888b.d88888                888                         
	    888    88888888b.d88b.  .d88b. 888Y88888P888 8888b.  .d8888b88888b. 88888888b.  .d88b.  
	    888    888888 "888 "88bd8P  Y8b888 Y888P 888    "88bd88P"   888 "88b888888 "88bd8P  Y8b 
	    888    888888  888  88888888888888  Y8P  888.d888888888     888  888888888  88888888888 
	    888    888888  888  888Y8b.    888   "   888888  888Y88b.   888  888888888  888Y8b.     
	    888    888888  888  888 "Y8888 888       888"Y888888 "Y8888P888  888888888  888 "Y8888  
	**/
	TM.TimeMachine = TM.View.extend({
		ticks: 0,
		stage: null,
		renderer: null,

		glitchFilter: null,

		defaults: {
		},

		screens: {},

		activeScreen: null,

		start: Date.now(),
		timeElapsed: 0,
		lastTime: Date.now(),
		timeFactor: 0.999,

		init: function init(options) {
			TM.machine = this;

			this._super.apply(this, arguments);

			this.initGraphics();

			var self = this;
			function animate() {
				self.tick();
				requestAnimFrame(animate);
			}

			setTimeout(animate, 0);

			this.createScreens();

			this.activateScreen('headphones');
			// this.activateScreen('routines');
		}, // init()

		initGraphics: function () {
			// true = interactive
			this.stage = new PIXI.Stage(0x001100, true);

			this.renderer = new PIXI.autoDetectRenderer(WIDTH, HEIGHT);

			this.renderer.view.id = 'canvas';

			document.body.appendChild(this.renderer.view);

			var blurFilter = new PIXI.BlurFilter()
			blurFilter.blur = 2;

			this.stage.filters = [blurFilter];

			this.container = new PIXI.DisplayObjectContainer();
			this.container.width = WIDTH * 2;
			this.container.height = HEIGHT * 2;

			this.stage.addChild(this.container);

			var bulgeFilter = new PIXI.BulgeFilter();
			var vignetteFilter = new PIXI.VignetteFilter();
			this.glitchFilter = new PIXI.GlitchFilter();

			this.container.filters = [this.glitchFilter, bulgeFilter, vignetteFilter];

			this.clockObj = new PIXI.Text('13:25:00', {font: '30px Share Tech Mono', fill: '#0f0', align: 'right'});
			this.clockObj.position.x = 600;
			this.clockObj.position.y = 60;

			// this.resize();
		},

		/*
		resize: function (base) {
			var i,
				nw,
				nh,
				scale,
				scalePoint,
				vw = screenfull.isFullscreen ? screen.width : window.innerWidth,
				vh = screenfull.isFullscreen ? screen.height : window.innerHeight,
				el = document.getElementById('canvas');

			if (base) {
				nw = BASEWIDTH;
				nh = BASEHEIGHT;
				scale = 1;

			} else {
				scale = Math.min(
					Math.floor(vw / BASEWIDTH),
					Math.floor(vh / BASEHEIGHT)
				);

				if (scale < 1) {
					scale = 1;
				}

				///scale = 2;

				if (vw / vh >= 16 / 9) {
					nh = vh / scale;
					nw = Math.round(BASEWIDTH * nh / BASEHEIGHT);

				} else {
					nw = vw / scale;
					nh = Math.round(BASEHEIGHT * nw / BASEWIDTH);
				}
			}

			// this.options.width = nw;
			// this.options.height = nh;
			// this.options.scale = scale;

			WIDTH = nw;
			HEIGHT = nh;
			SCALE = scale;

			console.log(SCALE);////

			this.renderer.resize(scale * WIDTH, scale * HEIGHT);
			el.style.width = (scale * WIDTH) + 'px';
			el.style.height = (scale * HEIGHT) + 'px';

			//// TODO
			// scalePoint = new PIXI.Point(scale, scale);
			// this.bg1Graphics.scale = scalePoint;
			// this.bg2Graphics.scale = scalePoint;
			// this.playerLayer.scale = scalePoint;
			// this.scoreGraphics.scale = scalePoint;
		},
		*/

		tick: function () {
			//
			// Glitch shader stuff
			//
			if (audioGlitches.length) {
				if (audioGlitches[0][0]-- <= 0) {
					if (window.audio_node) {
						if (audioGlitches[0][1] == 'rate') {
							audio_node.playbackRate += -0.5 + Math.random() * 1.0;

						} else if (audioGlitches[0][1] == 'time') {
							audio_node.currentTime -= 0.025 + Math.random() * 0.05;

						} else {
							audio_node.playbackRate = 1.0;
						}
					}

					audioGlitches.shift();
				}
			}

			if (visualGlitches.length == 0) {
				var g = Math.floor(Math.random() * 8);
				while (g--) {
					visualGlitches.push([Math.floor(1 + Math.random() * 15), 0.4]);
				}
				g = Math.floor(Math.random() * 8);
				while (g--) {
					visualGlitches.push([Math.floor(1 + Math.random() * 15), 0.7]);
				}
				g = Math.floor(Math.random() * 8);
				while (g--) {
					visualGlitches.push([Math.floor(1 + Math.random() * 15), 0.9]);
				}
				g = Math.floor(Math.random() * 12);
				while (g--) {
					visualGlitches.push([Math.floor(1 + Math.random() * 15), 0.1]);
				}
				g = Math.floor(Math.random() * 8);
				var r = Math.random();
				while (g--) {
					visualGlitches.push([Math.floor(1 + Math.random() * 15), r]);
				}

				// rand = Math.random();
				// visualGlitches.push([5, rand]);
				// visualGlitches.push([2, rand]);
				// visualGlitches.push([8, rand]);
				// visualGlitches.push([16, rand]);

				visualGlitches.push([30, 0]);
				visualGlitches.push([60 * Math.floor(1 + Math.random() * 12), 0]);

				if (glitchesOff) {
					visualGlitches = [[30, 0]];
				}

			} else if (visualGlitches[0][0]-- <= 0) {
				// glitchCountdown = Math.floor(1 + Math.random() * 45);
				blocks.length = 0;
				effects.length = 0;

				// rand = Math.random();
				rand = visualGlitches[0][1];

				// Clear fx / no effects
				if (rand == 0) {
					effects = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

				// Full screen
				} else if (rand < 0.2) {
					block = 300;
					i = 14;
					while (i--) {
						block += Math.floor(-40 + Math.random() * 80);
						if (block < 0) {
							block = 0;
						} else if (block > 599) {
							block = 599;
						}
						blocks.push(block);
						effects.push(get_effect());
					}

				// Mostly top third
				} else if (rand < 0.6) {
					// i = 14;
					// while (i--) {
					// 	block = 600 - Math.floor(1 + Math.random() * 200);
					// 	blocks.push(block);
					// 	effects.push(get_effect());
					// }
					i = 7;
					while (i-- > 0) {
						y = 0.7 + Math.random() * 0.3;
						x = 0.0 + Math.random() * 0.7;
						blocks.push(get_block(x, y));
						blocks.push(get_block(x, y) + 1);
						fx = get_effect();
						effects.push(fx);
						effects.push(fx);

						if (fx != 1 && fx != 3 && fx != 6 && Math.random() < 0.33) {
							if (i-- > 0) {
								blocks.push(get_block(x, y) + 2);
								effects.push(fx);
							}
							if (i-- > 0) {
								blocks.push(get_block(x, y) + 3);
								effects.push(fx);
							}
						}
					}

				// Mostly middle third
				} else if (rand < 0.8) {
					i = 7;
					while (i-- > 0) {
						y = 0.4 + Math.random() * 0.3;
						x = 0.3 + Math.random() * 0.7;
						blocks.push(get_block(x, y));
						blocks.push(get_block(x, y) + 1);
						fx = get_effect();
						effects.push(fx);
						effects.push(fx);

						if (fx != 1 && fx != 3 && fx != 6 && Math.random() < 0.33) {
							if (i-- > 0) {
								blocks.push(get_block(x, y) + 2);
								effects.push(fx);
							}
							if (i-- > 0) {
								blocks.push(get_block(x, y) + 3);
								effects.push(fx);
							}
						}
					}

				// Mostly bottom
				} else {
					i = 7;
					while (i-- > 0) {
						y = 0.1 + Math.random() * 0.3;
						x = 0.4 + Math.random() * 0.5;
						blocks.push(get_block(x, y));
						blocks.push(get_block(x, y) + 1);
						fx = get_effect();
						effects.push(fx);
						effects.push(fx);

						if (fx != 1 && fx != 3 && fx != 6 && Math.random() < 0.5) {
							if (i-- > 0) {
								blocks.push(get_block(x, y) + 2);
								effects.push(fx);
							}
							if (i-- > 0) {
								blocks.push(get_block(x, y) + 3);
								effects.push(fx);
							}
						}
					}
				}
				
				if (rand && !audioGlitches.length) {
					var j = Math.floor(4 + Math.random() * 8);
					// // audioGlitches.length = 0;
					// audioGlitches.push([1, 'rate']);
					while (j--) {
						if (false && Math.random() < 0.15) {
							audioGlitches.push([Math.floor(5 + Math.random() * 60), 'rate']);
						} else {
							audioGlitches.push([Math.floor(0 + Math.random() * 6), 'time']);
						}
					}
					audioGlitches.push([40, false]);
				}

				this.glitchFilter.blocks = new Float32Array(blocks);
				this.glitchFilter.effects = new Float32Array(effects);

				visualGlitches.shift();
			}
			//
			//
			//


			//
			// Realtime Clock
			//
			this.timeFactor *= 0.9999;
			if (this.timeFactor < 0.333) {
				this.timeFactor = 0.333;
			}

			var now = Date.now(),
				delta = now - this.lastTime;
			this.lastTime = now;
			this.timeElapsed += Math.floor(delta * this.timeFactor);
			var d = new Date(this.start + this.timeElapsed);
			this.clockObj.setText(('00' + d.getHours()).slice(-2) + ':' + ('00' + d.getMinutes()).slice(-2) + ':' + ('00' + d.getSeconds()).slice(-2));
			//
			//
			//


			this.renderer.render(this.stage);

			this.ticks++;
		},

		createScreens: function createScreens() {
			var screenObj;

			_.each(this.options.screens, function (data) {
				switch (data.kind) {
					case 'screen':
						data.options.id = data.id;
						data.options.container = this.container;

						screenObj = new TM.Screen(data.options);
						break;
				}

				this.screens[data.id] = screenObj;
			}.use(this));

			if (screenfull.enabled) {
				document.addEventListener(screenfull.raw.fullscreenchange, function () {
				    console.log('Am I fullscreen? ' + (screenfull.isFullscreen ? 'Yes' : 'No'));

				    // this.resize();
				}.use(this));

				$('body').on('click', 'canvas', function () {
					if (this.activeScreen && this.activeScreen.id == 'begin' && !screenfull.isFullscreen) {
						screenfull.request();
					}
				}.use(this));
			}
		}, // createScreens()

		activateScreen: function activateScreen(id) {
			if (this.activeScreen) {
				this.activeScreen.deactivate();
			}

			this.activeScreen = this.screens[id];

			this.activeScreen.activate();
		}, // activateScreen()
	}); // TM.TimeMachine


	/**
	 * Screen
	 .d8888b.                                         
	d88P  Y88b                                        
	Y88b.                                             
	 "Y888b.   .d8888b888d888 .d88b.  .d88b. 88888b.  
	    "Y88b.d88P"   888P"  d8P  Y8bd8P  Y8b888 "88b 
	      "888888     888    8888888888888888888  888 
	Y88b  d88PY88b.   888    Y8b.    Y8b.    888  888 
	 "Y8888P"  "Y8888P888     "Y8888  "Y8888 888  888 
	**/
	TM.Screen = TM.View.extend({
		active: false,

		screenLayer: null,
		fillBox: null,
		btnsLayer: null,
		textObj: null,

		timer: null,

		defaults: {

		},

		btns: [],

		init: function init() {
			this._super.apply(this, arguments);

			this.screenLayer = new PIXI.DisplayObjectContainer();
		},

		activate: function activate() {
			this.active = true;

			this.loadSounds();

			this.loadGraphics();

			if (this.options.sounds.bg) {
				TM.soundManager.bgm(this.options.sounds.bg);
			}

			if (this.options.sounds.start) {
				TM.soundManager.play(this.options.sounds.start)
					.then(function () {

						this.setTiming();

					}.use(this));

			} else {
				this.setTiming();
			}
		}, // activate()

		deactivate: function deactivate() {
			this.active = false;

			this.unloadSounds();
			this.unloadGraphics();

			if (this.timer) {
				clearTimeout(this.timer);
				this.timer = null;
			}
		}, // deactivate()

		setTiming: function setTiming() {
			if (this.options.timed) {
				this.timer = setTimeout(function () {
					TM.machine.activateScreen(this.options.timed.target);
				}.use(this), this.options.timed.delay);
			}

			this.options.callback && this.options.callback.apply(this);
		}, // setTiming()

		loadSounds: function loadSounds() {
			_.each(this.options.sounds, function (sound, key) {
				TM.soundManager.preload(sound);
			}.use(this));			
		}, // loadSounds()

		unloadSounds: function unloadSounds() {
			//// TODO
		}, // unloadSounds()

		loadGraphics: function loadGraphics() {
			this.fillBox = new PIXI.Graphics();

			// Forces a size for the BulgeFilter
			this.fillBox.beginFill(0x001100, 1.0);
			this.fillBox.drawRect(0, 0, WIDTH, HEIGHT);

			this.screenLayer.addChild(this.fillBox);

			this.textObj = new PIXI.Text(this.wrap(this.options.text), {font: '30px Share Tech Mono', fill: '#0f0', align: (this.options.align || 'center')});

			if (this.options.align == 'left') {
				this.textObj.position.x = 100;

			} else {
				this.textObj.anchor.x = 0.5;
				this.textObj.position.x = WIDTH / 2;
			}

			this.textObj.position.y = 100;

			this.screenLayer.addChild(this.textObj);

			this.btnsLayer = new PIXI.DisplayObjectContainer();

			this.screenLayer.addChild(this.btnsLayer);

			_.each(this.options.btns, function (btn) {
				this.addBtn(btn, this.options.btns.length);
			}.use(this));

			this.screenLayer.addChild(TM.machine.clockObj);

			this.container.addChild(this.screenLayer);
		}, // initGraphics()

		unloadGraphics: function unloadGraphics() {
			this.container.removeChild(this.screenLayer);

			this.screenLayer.removeChildren();

			this.btns = [];
		}, // unloadGraphics()

		addBtn: function addBtn(btn, count) {
			var i = this.btns.length,
				width = btn.width || 200,
				pad = 25,
				btnObj;

			btn.container = this.btnsLayer;
			btn.x = (pad + (width + (pad * 2)) * i) + ((WIDTH - ((width + (pad * 2)) * count)) / 2);
			btn.width = width;

			btnObj = new TM.Btn(btn);

			this.btns.push(btnObj);
		}, // addBtn()

		wrap: function wrap(text) {
			var i,
				j,
				chunks = text.split("\n"),
				wrapped = '';

			for (i = 0; i < chunks.length; i++) {
				if (chunks[i].length > 40) {
					for (j = 0; j < chunks[i].length; j += 40) {
						console.log(chunks[i][j + 39]);
						wrapped += chunks[i].slice(j, j + 40) + (((chunks[i][j + 39]) && (chunks[i][j + 39]).match(/[a-zA-Z]/) && (!chunks[i][j + 40] || chunks[i][j + 40].match(/[a-zA-Z]/))) ? '-' : '') + "\n";
					}

				} else {
					wrapped += chunks[i] + "\n";
				}
			}

			return wrapped;
		}, // wrap()
	}); // TM.Screen


	/**
	 * Btn
	888888b.  888            
	888  "88b 888            
	888  .88P 888            
	8888888K. 88888888888b.  
	888  "Y88b888   888 "88b 
	888    888888   888  888 
	888   d88PY88b. 888  888 
	8888888P"  "Y888888  888 
	**/
	TM.Btn = TM.View.extend({
		btnObj: null,

		btnText: null,

		disabled: false,

		defaults: {
			x: WIDTH / 2,
			y: 400,
			width: 200,
			height: 80
		},

		init: function init() {
			this._super.apply(this, arguments);

			this.loadGraphics();
		},

		loadGraphics: function loadGraphics() {
			this.btnObj = new PIXI.Graphics();

			// this.btnObj.setInteractive(true); // doesn't work
			this.btnObj.interactive = true;

			this.btnObj.mouseup = this.btnObj.touchend = function (data) {
				if (this.disabled) {
					return;
				}

				setTimeout(function () {
					TM.machine.activateScreen(this.options.target);
				}.use(this), 0);
			}.use(this);

			this.btnObj.beginFill(0x000000, 0.0); // Needs fill for interactive
			this.btnObj.lineStyle(5, 0x00ff00);
			this.btnObj.drawRect(this.options.x, this.options.y, this.options.width, this.options.height);
			this.btnObj.lineStyle(1, 0x000000, 0.0); // Need extra below for clicking because of Bulge
			this.btnObj.drawRect(this.options.x, this.options.y, this.options.width, this.options.height + 50);

			this.container.addChild(this.btnObj);

			this.btnText = new PIXI.Text(this.options.text, {font: '30px Share Tech Mono', fill: '#0f0', align: 'center'});
			this.btnText.anchor.x = 0.5;
			this.btnText.anchor.y = 0.5;
			this.btnText.position.x = this.options.x + this.options.width / 2;
			this.btnText.position.y = this.options.y + this.options.height / 2;

			this.container.addChild(this.btnText);
		}, // loadGraphics()
	}); // TM.Btn


}(jQuery));