class Scene {
	constructor(id) {
		this.id = id;

		this.viewControllers = [ ];

		this.modalContainer = document.createElement("DIV");
		this.modalContainer.className = "modal-container";
		document.body.appendChild(this.modalContainer);

		//Create the vertical centerer helper line.
		var verticalCenterer = document.createElement("DIV");
		verticalCenterer.className = "vertical-centerer";
		this.modalContainer.appendChild(verticalCenterer);

		this.popoverContainer = document.createElement("DIV");
		this.popoverContainer.className = "popover-container";
		document.body.appendChild(this.popoverContainer);

		this.tooltipContainer = document.createElement("DIV");
		this.tooltipContainer.className = "tooltip-container";
		document.body.appendChild(this.tooltipContainer);
	}

	addViewController(viewController) {
		if (viewController.scene) {
			viewController.scene.removeViewController(viewController);
		}
		viewController.scene = this;

		this.viewControllers.push(viewController);
	}

	removeViewController(viewController) {
		var index = this.viewControllers.indexOf(viewController);
		if (index != -1) {
			this.viewControllers.splice(index, 1);
		}
	}

	/**
	 * Shows the active view controller of this scene.
	 * If no view controller is active, the default view controller is shown.
	 * If a view controller is passes as a parameter, it is used as the view controller to show the scene with.
	 */
	show(viewControllerToShow = null) {
		this.hide();

		var newLastViewController = this.activeViewController;
		if (viewControllerToShow) {
			this.activeViewController = viewControllerToShow;
		}
		this.lastViewController = newLastViewController;

		viewControllerToShow = this.activeViewController;

		if (!viewControllerToShow) {
			viewControllerToShow = this.initialViewController;
		}

		if (!viewControllerToShow) {
			console.error("Attempted to show a scene that has no initial view controller whatsoever.");
			return;
		}

		UIKit.activeScene = this;

		this.showViewControllerInternal(viewControllerToShow);
	}

	/**
	 * Shows this scene and the given view controller.
	 */
	showWithViewController(viewController) {
		this.show(viewController);
	}

	/**
	 * Hides the active view controller of this scene.
	 */
	hide() {
		if (this.activeViewController) {
			this.hideViewControllerInternal(this.activeViewController);
		}

		if (UIKit.activeScene == this) {
			UIKit.activeScene = null;
		}
	}

	/**
	 * Activates and shows the given view controller inside the scene, given the fact that it is actually a view controller of this scene.
	 */
	showViewController(viewController) {
		var controllerIndex = this.viewControllers.indexOf(viewController);
		if (controllerIndex == -1) {
			return;
		}

		for (var i = 0; i < this.viewControllers.length; i++) {
			var thisViewController = this.viewControllers[i];
			if (i == controllerIndex) {
				this.showViewControllerInternal(thisViewController);
			}
			else {
				this.hideViewControllerInternal(thisViewController);
			}
		}

		var newLastViewController = this.activeViewController;
		this.activeViewController = viewController;
		this.lastViewController = newLastViewController;
	}

	showViewControllerModally(viewController) {
		var controllerIndex = this.viewControllers.indexOf(viewController);
		if (controllerIndex == -1) {
			return;
		}

		if (this.modalViewController) {
			this.dismissModalViewController();
		}
		this.modalViewController = viewController;

		this.previousParent = viewController.view.parentNode;
		this.modalContainer.appendChild(viewController.view);
		this.modalContainer.className = "modal-container visible";

		this.showViewControllerInternal(viewController);
	}

	dismissModalViewController() {
		if (this.modalViewController) {
			if (this.previousParent) {
				this.previousParent.appendChild(this.modalViewController.view);
			}

			//Clear the hash if is the modal view controller's hash.
			if ("#" + this.modalViewController.hash == window.location.hash) {
				window.location.hash = "";
			}
		}

		this.hideViewControllerInternal(this.modalViewController);

		this.modalViewController = null;
		this.modalContainer.className = "modal-container";
	}

	/**
	 * Shows the given popover in this scene's popover layer.
	 * Will hide any other popover that could be opened.
	 */
	showPopover(popover) {
		if (this.activePopover) {
			this.activePopover.dismiss();
		}

		this.activePopover = popover;

		this.activePopover.viewWillAppear();
		this.popoverContainer.appendChild(this.activePopover.element);
		this.popoverContainer.className = "popover-container visible";
		this.activePopover.viewDidAppear();
	}

	/**
	 * Hides the currently visible popover, if one is visible.
	 */
	dismissPopover() {
		if (!this.activePopover) {
			return;
		}

		this.activePopover.viewWillDisappear();
		this.popoverContainer.removeChild(this.activePopover.element);
		this.popoverContainer.className = "popover-container";
		this.activePopover.viewDidDisappear();
		this.activePopover = null;
	}

	/**
	 * Shows the given tooltip in this scene's tooltip layer.
	 * Will hide any other tooltip that could be visible.
	 */
	showTooltip(tooltip) {
		if (this.activeTooltip) {
			this.activeTooltip.dismiss();
		}

		this.activeTooltip = tooltip;

		this.activeTooltip.viewWillAppear();
		this.tooltipContainer.appendChild(this.activeTooltip.element);
		this.tooltipContainer.className = "tooltip-container visible";
		this.activeTooltip.viewDidAppear();
	}

	/**
	 * Hides the currently visible tooltip, if one is visible.
	 */
	dismissTooltip() {
		if (!this.activeTooltip) {
			return;
		}

		this.activeTooltip.viewWillDisappear();
		this.tooltipContainer.removeChild(this.activeTooltip.element);
		this.tooltipContainer.className = "tooltip-container";
		this.activeTooltip.viewDidDisappear();
		this.activeTooltip = null;
	}

	showViewControllerInternal(viewController) {
		if (!viewController.visible) {
			viewController.view.style.visibility = "hidden";
			if (viewController.view.className.indexOf("visible") == -1) {
				viewController.view.classList.add("visible");
			}
			viewController.viewWillAppear();
			viewController.subviewsWillAppear();
			viewController.view.style.visibility = "";
			viewController.visible = true;
			viewController.viewDidAppear();
			viewController.subviewsDidAppear();
		}
	}

	hideViewControllerInternal(viewController) {
		if (viewController.visible) {
			viewController.viewWillDisappear();
			viewController.subviewsWillDisappear();
			viewController.view.classList.remove("visible");
			viewController.visible = false;
			viewController.viewDidDisappear();
			viewController.subviewsDidDisappear();
		}
	}

	showLastViewController() {
		if (this.lastViewController) {
			this.showViewController(this.lastViewController);
		}
	}

	/**
	 * Returns true if this scene contains the given view controller, false otherwise.
	 */
	containsViewController(viewController) {
		for (var i = 0; i < this.viewControllers.length; i++) {
			if (this.viewControllers[i] == viewController) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Looks for any view controller inside this scene that has the given hash and returns it.
	 */
	getViewControllerWithHash(hash) {
		for (var i = 0; i < this.viewControllers.length; i++) {
			if (this.viewControllers[i].hash == hash) {
				return this.viewControllers[i];
			}
		}

		return null;
	}

	/**
	 * Looks for any view controller inside this scene that has the given request path and returns it.
	 */
	getViewControllerWithRequestPath(requestPath) {
		for (var i = 0; i < this.viewControllers.length; i++) {
			if (this.viewControllers[i].requestPath == requestPath) {
				return this.viewControllers[i];
			}
		}

		return null;
	}
}