"use strict";

const xtend = require("xtend");
const nanoid = require("nanoid");
const immutable = require("immutable");

module.exports = function createWindowStore({onUpdated}) {
	let windows = immutable.OrderedMap([]);
	let floatingWindows = [];
	let leftSidebarWindows = [];
	let rightSidebarWindows = [];
	let activeWindow;
	let lastZIndex = 0;

	function updateWindowIndexes() {
		floatingWindows = windows.filter((window_) => window_.sidebar == null).toArray();
		leftSidebarWindows = windows.filter((window_) => window_.sidebar === "left").toArray();
		rightSidebarWindows = windows.filter((window_) => window_.sidebar === "right").toArray();
	}

	function setSide(id, side) {
		setValues(id, {
			sidebar: side
		}, () => {
			updateWindowIndexes();
		});
	}

	function setValues(id, values, postProcessing) {
		let targetWindow = windows.get(id);

		Object.assign(targetWindow, values);

		if (postProcessing != null) {
			postProcessing(targetWindow);
		}

		onUpdated();
	}

	function setValuesWithoutUpdate(id, values) {
		Object.assign( windows.get(id), values);
	}

	return {
		add: function (window_) {
			let id = nanoid();

			windows = windows.set(id, xtend(window_, {
				id: id,
				x: window_.initialX,
				y: window_.initialY,
				userX: 0,
				userY: 0,
				width: window_.initialWidth,
				height: window_.initialHeight
			}));

			updateWindowIndexes();

			this.focus(id);
			/* NOTE: We let .focus call onUpdated. QUESTION: Is this not deduplicated by React? */

			return id;
		},
		focus: function (id) {
			let targetWindow = windows.get(id);

			windows.forEach((window_) => {
				window_.isActive = false;
			});

			targetWindow.zIndex = lastZIndex++;
			targetWindow.isActive = true;
			activeWindow = targetWindow;

			onUpdated();
		},
		setUserPosition: function (id, x, y) {
			setValues(id, {
				userX: x,
				userY: y,
				x: x,
				y: y
			});
		},
		setCurrentPosition: function (id, x, y) {
			setValuesWithoutUpdate(id, {
				x: x,
				y: y
			});
		},
		setDimensions: function (id, width, height) {
			setValues(id, {
				width: width,
				height: height
			});
		},
		markMoving: function (id, isMoving) {
			setValues(id, {
				isMoving: isMoving
			});
		},
		markResizing: function (id, isResizing) {
			setValues(id, {
				isResizing: isResizing
			});
		},
		moveToSidebar: function (id, side) {
			setSide(id, side);
		},
		makeFloating: function (id) {
			setSide(id, null);
		},
		close: function (id) {
			windows = windows.delete(id);
			updateWindowIndexes();
			onUpdated();
		},
		get: function (id) {
			return windows.get(id);
		},
		getAll: function () {
			return windows;
		},
		getFloating: function () {
			return floatingWindows;
		},
		getLeftSidebar: function () {
			return leftSidebarWindows;
		},
		getRightSidebar: function () {
			return rightSidebarWindows;
		},
		getActiveWindow: function () {
			return activeWindow;
		}
	};
};
