/// <reference path="../../release/monaco.d.ts" />

(function () {
	'use strict';

	var isMac = /Mac/i.test(navigator.userAgent);
	window.onload = function () {
		require(['vs/editor/editor.main'], function () {
			xhr('playground/monaco.d.ts.txt').then(function (response) {
				monaco.languages.typescript.javascriptDefaults.addExtraLib(
					response.responseText,
					'ts:monaco.d.ts'
				);
				monaco.languages.typescript.javascriptDefaults.addExtraLib(
					[
						'declare var require: {',
						'	toUrl(path: string): string;',
						'	(moduleName: string): any;',
						'	(dependencies: string[], callback: (...args: any[]) => any, errorback?: (err: any) => void): any;',
						'	config(data: any): any;',
						'	onError: Function;',
						'};'
					].join('\n'),
					'ts:require.d.ts'
				);
			});

			var loading = document.getElementById('loading');
			loading.parentNode.removeChild(loading);
			load();
		});
	};

	var editor = null;
	var data = {
		js: {
			model: null,
			state: null
		},
		css: {
			model: null,
			state: null
		},
		html: {
			model: null,
			state: null
		}
	};

	function load() {
		function layout() {
			var GLOBAL_PADDING = 20;

			var WIDTH = window.innerWidth - 2 * GLOBAL_PADDING;
			var HEIGHT = window.innerHeight;

			var TITLE_HEIGHT = 110;
			var FOOTER_HEIGHT = 80;
			var TABS_HEIGHT = 20;
			var INNER_PADDING = 20;
			var SWITCHER_HEIGHT = 30;

			var HALF_WIDTH = Math.floor((WIDTH - INNER_PADDING) / 2);
			var REMAINING_HEIGHT = HEIGHT - TITLE_HEIGHT - FOOTER_HEIGHT - SWITCHER_HEIGHT;

			playgroundContainer.style.width = WIDTH + 'px';
			playgroundContainer.style.height = HEIGHT - FOOTER_HEIGHT + 'px';

			sampleSwitcher.style.position = 'absolute';
			sampleSwitcher.style.top = TITLE_HEIGHT + 'px';
			sampleSwitcher.style.left = GLOBAL_PADDING + 'px';

			typingContainer.style.position = 'absolute';
			typingContainer.style.top = GLOBAL_PADDING + TITLE_HEIGHT + SWITCHER_HEIGHT + 'px';
			typingContainer.style.left = GLOBAL_PADDING + 'px';
			typingContainer.style.width = HALF_WIDTH + 'px';
			typingContainer.style.height = REMAINING_HEIGHT + 'px';

			tabArea.style.position = 'absolute';
			tabArea.style.boxSizing = 'border-box';
			tabArea.style.top = 0;
			tabArea.style.left = 0;
			tabArea.style.width = HALF_WIDTH + 'px';
			tabArea.style.height = TABS_HEIGHT + 'px';

			editorContainer.style.position = 'absolute';
			editorContainer.style.boxSizing = 'border-box';
			editorContainer.style.top = TABS_HEIGHT + 'px';
			editorContainer.style.left = 0;
			editorContainer.style.width = HALF_WIDTH + 'px';
			editorContainer.style.height = REMAINING_HEIGHT - TABS_HEIGHT + 'px';

			if (editor) {
				editor.layout({
					width: HALF_WIDTH - 2,
					height: REMAINING_HEIGHT - TABS_HEIGHT - 1
				});
			}

			runContainer.style.position = 'absolute';
			runContainer.style.top = GLOBAL_PADDING + TITLE_HEIGHT + SWITCHER_HEIGHT + TABS_HEIGHT + 'px';
			runContainer.style.left = GLOBAL_PADDING + INNER_PADDING + HALF_WIDTH + 'px';
			runContainer.style.width = HALF_WIDTH + 'px';
			runContainer.style.height = REMAINING_HEIGHT - TABS_HEIGHT + 'px';

			runIframeHeight = REMAINING_HEIGHT - TABS_HEIGHT;
			if (runIframe) {
				runIframe.style.height = runIframeHeight + 'px';
			}
		}

		function changeTab(selectedTabNode, desiredModelId) {
			for (var i = 0; i < tabArea.childNodes.length; i++) {
				var child = tabArea.childNodes[i];
				if (/tab/.test(child.className)) {
					child.className = 'tab';
				}
			}
			selectedTabNode.className = 'tab active';

			var currentState = editor.saveViewState();

			var currentModel = editor.getModel();
			if (currentModel === data.js.model) {
				data.js.state = currentState;
			} else if (currentModel === data.css.model) {
				data.css.state = currentState;
			} else if (currentModel === data.html.model) {
				data.html.state = currentState;
			}

			editor.setModel(data[desiredModelId].model);
			editor.restoreViewState(data[desiredModelId].state);
			editor.focus();
		}

		// create the typing side
		var typingContainer = document.createElement('div');
		typingContainer.className = 'typingContainer';

		var tabArea = (function () {
			var tabArea = document.createElement('div');
			tabArea.className = 'tabArea';

			var jsTab = document.createElement('span');
			jsTab.className = 'tab active';
			jsTab.appendChild(document.createTextNode('JavaScript'));
			jsTab.onclick = function () {
				changeTab(jsTab, 'js');
			};
			tabArea.appendChild(jsTab);

			var cssTab = document.createElement('span');
			cssTab.className = 'tab';
			cssTab.appendChild(document.createTextNode('CSS'));
			cssTab.onclick = function () {
				changeTab(cssTab, 'css');
			};
			tabArea.appendChild(cssTab);

			var htmlTab = document.createElement('span');
			htmlTab.className = 'tab';
			htmlTab.appendChild(document.createTextNode('HTML'));
			htmlTab.onclick = function () {
				changeTab(htmlTab, 'html');
			};
			tabArea.appendChild(htmlTab);

			var runLabel = 'Press ' + (isMac ? 'CMD + return' : 'CTRL + Enter') + ' to run the code.';
			var runBtn = document.createElement('button');
			runBtn.className = 'action run';
			runBtn.setAttribute('role', 'button');
			runBtn.setAttribute('aria-label', runLabel);
			runBtn.appendChild(document.createTextNode('Run'));
			runBtn.onclick = function () {
				run();
			};
			tabArea.appendChild(runBtn);

			return tabArea;
		})();

		var editorContainer = document.createElement('div');
		editorContainer.className = 'editor-container';

		typingContainer.appendChild(tabArea);
		typingContainer.appendChild(editorContainer);

		var runContainer = document.createElement('div');
		runContainer.className = 'run-container';

		var sampleSwitcher = document.createElement('select');
		var sampleChapter;
		PLAY_SAMPLES.forEach(function (sample) {
			if (!sampleChapter || sampleChapter.label !== sample.chapter) {
				sampleChapter = document.createElement('optgroup');
				sampleChapter.label = sample.chapter;
				sampleSwitcher.appendChild(sampleChapter);
			}
			var sampleOption = document.createElement('option');
			sampleOption.value = sample.id;
			sampleOption.appendChild(document.createTextNode(sample.name));
			sampleChapter.appendChild(sampleOption);
		});
		sampleSwitcher.className = 'sample-switcher';

		var LOADED_SAMPLES = [];
		function findLoadedSample(sampleId) {
			for (var i = 0; i < LOADED_SAMPLES.length; i++) {
				var sample = LOADED_SAMPLES[i];
				if (sample.id === sampleId) {
					return sample;
				}
			}
			return null;
		}

		function findSamplePath(sampleId) {
			for (var i = 0; i < PLAY_SAMPLES.length; i++) {
				var sample = PLAY_SAMPLES[i];
				if (sample.id === sampleId) {
					return sample.path;
				}
			}
			return null;
		}

		function loadSample(sampleId, callback) {
			var sample = findLoadedSample(sampleId);
			if (sample) {
				return callback(null, sample);
			}

			var samplePath = findSamplePath(sampleId);
			if (!samplePath) {
				return callback(new Error('sample not found'));
			}

			samplePath = 'playground/new-samples/' + samplePath;

			var js = xhr(samplePath + '/sample.js').then(function (response) {
				return response.responseText;
			});
			var css = xhr(samplePath + '/sample.css').then(function (response) {
				return response.responseText;
			});
			var html = xhr(samplePath + '/sample.html').then(function (response) {
				return response.responseText;
			});
			Promise.all([js, css, html]).then(
				function (_) {
					var js = _[0];
					var css = _[1];
					var html = _[2];
					LOADED_SAMPLES.push({
						id: sampleId,
						js: js,
						css: css,
						html: html
					});
					return callback(null, findLoadedSample(sampleId));
				},
				function (err) {
					callback(err, null);
				}
			);
		}

		sampleSwitcher.onchange = function () {
			var sampleId = sampleSwitcher.options[sampleSwitcher.selectedIndex].value;
			window.location.hash = sampleId;
		};

		var playgroundContainer = document.getElementById('playground');

		layout();
		window.onresize = layout;

		playgroundContainer.appendChild(sampleSwitcher);
		playgroundContainer.appendChild(typingContainer);
		playgroundContainer.appendChild(runContainer);

		data.js.model = monaco.editor.createModel('console.log("hi")', 'javascript');
		data.css.model = monaco.editor.createModel('css', 'css');
		data.html.model = monaco.editor.createModel('html', 'html');

		editor = monaco.editor.create(editorContainer, {
			model: data.js.model,
			minimap: {
				enabled: false
			}
		});

		var currentToken = 0;
		function parseHash(firstTime) {
			var sampleId = window.location.hash.replace(/^#/, '');
			if (!sampleId) {
				sampleId = PLAY_SAMPLES[0].id;
			}

			if (firstTime) {
				for (var i = 0; i < sampleSwitcher.options.length; i++) {
					var opt = sampleSwitcher.options[i];
					if (opt.value === sampleId) {
						sampleSwitcher.selectedIndex = i;
						break;
					}
				}
			}

			var myToken = ++currentToken;
			loadSample(sampleId, function (err, sample) {
				if (err) {
					alert('Sample not found! ' + err.message);
					return;
				}
				if (myToken !== currentToken) {
					return;
				}
				data.js.model.setValue(sample.js);
				data.html.model.setValue(sample.html);
				data.css.model.setValue(sample.css);
				editor.setScrollTop(0);
				run();
			});
		}
		window.onhashchange = parseHash;
		parseHash(true);

		function run() {
			doRun(runContainer);
		}

		editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter, run);
		window.addEventListener('keydown', function keyDown(ev) {
			if ((isMac && !ev.metaKey) || !ev.ctrlKey) {
				return;
			}

			if (ev.shiftKey || ev.altKey || ev.keyCode !== 13) {
				return;
			}

			ev.preventDefault();
			run();
		});
	}

	var runIframe = null,
		runIframeHeight = 0;
	function doRun(runContainer) {
		if (runIframe) {
			// Unload old iframe
			runContainer.removeChild(runIframe);
		}

		// Load new iframe
		runIframe = document.createElement('iframe');
		runIframe.id = 'runner';
		runIframe.src = 'playground/playground-runner.html';
		runIframe.className = 'run-iframe';
		runIframe.style.boxSizing = 'border-box';
		runIframe.style.height = runIframeHeight + 'px';
		runIframe.style.width = '100%';
		runIframe.style.border = '1px solid lightgrey';
		runIframe.frameborder = '0';
		runContainer.appendChild(runIframe);

		var getLang = function (lang) {
			return data[lang].model.getValue();
		};

		runIframe.addEventListener('load', function (e) {
			runIframe.contentWindow.load(getLang('js'), getLang('html'), getLang('css'));
		});
	}

	var preloaded = {};
	(function () {
		var elements = Array.prototype.slice.call(document.querySelectorAll('pre[data-preload]'), 0);

		elements.forEach(function (el) {
			var path = el.getAttribute('data-preload');
			preloaded[path] = el.innerText || el.textContent;
			el.parentNode.removeChild(el);
		});
	})();

	function xhr(url) {
		if (preloaded[url]) {
			return Promise.resolve({
				responseText: preloaded[url]
			});
		}

		var req = null;
		return new Promise(
			function (c, e) {
				req = new XMLHttpRequest();
				req.onreadystatechange = function () {
					if (req._canceled) {
						return;
					}

					if (req.readyState === 4) {
						if ((req.status >= 200 && req.status < 300) || req.status === 1223) {
							c(req);
						} else {
							e(req);
						}
						req.onreadystatechange = function () {};
					}
				};

				req.open('GET', url, true);
				req.responseType = '';

				req.send(null);
			},
			function () {
				req._canceled = true;
				req.abort();
			}
		);
	}
})();
