class Request {
	static get POST() { return "POST"; }
	static get GET() { return "GET"; }

	/**
	 * Tries to start the next request in the queue if there is one.
	 * If a request is already running, nothing is done.
	 * This function is to be called on completion of a request and on queueing of a new request only.
	 * Do not call this function from anywhere else (it's pointless)!
	 */
	static performNextRequest() {
		if (Request.requestRunning || !Request.queue || Request.queue.length < 1) {
			return;
		}

		Request.requestRunning = true;

		var nextRequest = Request.queue[0];

		if (!nextRequest.data) {
			nextRequest.data = { };
		}

		nextRequest.data.session = Storage.get("session");

		if (nextRequest.requestType == "GET") {
			$.ajax({
				url: nextRequest.url,
				type: nextRequest.requestType,
				data: nextRequest.data,
				error: nextRequest.error.bind(nextRequest),
				success: nextRequest.response.bind(nextRequest)
			});
		}
		else {
			$.ajax({
				url: nextRequest.url,
				type: nextRequest.requestType,
				dataType: "json",
				contentType: "application/json",
				data: JSON.stringify(nextRequest.data),
				error: nextRequest.error.bind(nextRequest),
				success: nextRequest.response.bind(nextRequest)
			});
		}
	}

	/**
	 * Runs the first request in the queue again.
	 */
	static tryAgainWithSession() {
		if (!Request.requestRunning) {
			return;
		}

		Request.requestRunning = false;
		Request.performNextRequest();
	}

	/**
	 * Called upon completion of a request.
	 * Only after calling this request, a new one may be processed.
	 */
	static finishRequest() {
		Request.queue.splice(0, 1);
		Request.requestRunning = false;

		Request.performNextRequest();
	}

	constructor(url, type = Request.GET, callback = null, errorCallback = null) {
		this.url = url;
		this.requestType = type;
		this.callback = callback;
		this.errorCallback = errorCallback;
		this.ready = true;
	}

	/**
	 * Adds this request to the global request queue and tries to start the next request in the queue.
	 * There is an option to make this request the first in the queue, but this is only allowed for the login request.
	 */
	send(data = { }, logInRequest = false) {
		this.ready = false;

		if (!Request.queue) {
			Request.queue = [ ];
		}
		this.data = data;

		if (Request.queue.indexOf(this) != -1) {
			console.error("Trying to perform a request to " + this.url + " more than once at a time. This is not permitted. Wait until the request did return or create a new one instead.");
			return;
		}

		if (logInRequest) {
			Request.queue.splice(0, 0, this);
			Request.requestRunning = false;
		}
		else {
			Request.queue.push(this);
		}

		Request.performNextRequest();
	}

	response(responseData) {
		if (responseData.session) {
			Storage.set("session", responseData.session);
		}

		if (responseData.error) {
			var error = responseData.error;

			if (error.code == "invalid_session" || error.code == "not_logged_in") {
				var loginController = UIKit.getViewControllerById("login-view-controller");
				UIKit.getSceneWithViewController(loginController).showWithViewController(loginController);
				return;
			}

			if (error.code == "invalid_credentials") {
				if (this.errorCallback) {
					this.errorCallback(null, "application_error", error);
				}
				return;
			}

			this.error(null, "application_error", error);
		}
		else if (this.callback) {
			this.callback(responseData.response);
		}

		this.finish();
	}

	error(request, status, error) {
		if (this.errorCallback) {
			this.errorCallback(request, status, error);
		}

		this.finish();
	}

	finish() {
		this.ready = true;
		Request.finishRequest();
	}
}