class Root
{
	static instance = null;
	
  constructor() {
  	// Init values / parse cookies
  	if (Root.instance!==null) {
  		return;
  	}
  	Root.instance = this;
    this.jwt = this.getCookie("jwt");
    this.secToken = this.getCookie("secToken");
    this.loggedIn = false;
    this.url = "https://app.fw-innenstadt.de/index_new.php/";
    this.scanner = new Scanner(this);
    this.page = "Start";
    this.routesChecksum = "";
    const _this = this;
    Root.AddEventListenerIfButtonExists("loginButton", function (event) {_this.Login();});
    Root.AddEventListenerIfButtonExists("nav_start", function (event) {_this.Open("Start");});
    Root.AddEventListenerIfButtonExists("nav_termine", function (event) {_this.Open("Termine");});
    Root.AddEventListenerIfButtonExists("nav_dienstpläne", function (event) {_this.Open("Dienstpläne");});
    Root.AddEventListenerIfButtonExists("nav_personal", function (event) {_this.Open("Personal");});
    Root.AddEventListenerIfButtonExists("nav_prozesse", function (event) {_this.Open("Prozesse");});
    Root.AddEventListenerIfButtonExists("nav_spinde", function (event) {_this.Open("Spinde");});
    Root.AddEventListenerIfButtonExists("nav_einsätze", function (event) {_this.Open("Einsätze");});
    Root.AddEventListenerIfButtonExists("nav_anwesenheiten", function (event) {_this.Open("Anwesenheiten");});
    Root.AddEventListenerIfButtonExists("nav_fahrzeuge", function (event) {_this.Open("Fahrzeuge");});
    Root.AddEventListenerIfButtonExists("nav_logout", function (event) {_this.Logout();});
    document.getElementById("navigation_select").addEventListener("change", function (event) {_this.Open(document.getElementById("navigation_select").value);});
    this.FetchRoutes(true);
  }
  
  Open(page) {
  	if ("_LOGOUT_"==page) {
  		this.Logout();
  		return;
  	}
  	this.setCookie("page", page);
  	switch (page) {
    	case "Termine":
    		//TerminePage.Open();
  			break;
    	case "Dienstpläne":
    		//DienstplänePage.Open();
  			break;
    	case "Personal":
    		PersonalPage.Open();
  			break;
    	case "Prozesse":
    		//ProzessePage.Open();
  			break;
    	case "Spinde":
    		//SpindePage.Open();
  			break;
    	case "Einsätze":
    		//EinsätzePage.Open();
  			break;
    	case "Anwesenheiten":
    		//AnwesenheitenPage.Open();
  			break;
    	case "Fahrzeuge":
    		FahrzeugePage.Open();
  			break;
    	default:
    	  //StartPage.Open();
    	  this.setCookie("page", "Start");
  	}
  }
  
  Login() {
    var button = document.getElementById("loginButton");
    button.disabled = true;
    button.className = "login disabled";
    const json = {
      "login": document.getElementById("loginUser").value,
      "password": document.getElementById("loginPassword").value/*,
      "secToken": typeof(this.secToken)!="undefined" ? this.secToken : ""*/
    };
    
    const _this = this;
    Root.SetLoadAnimation(true);
    let request = new XMLHttpRequest();
    request.open("POST", this.url, true);
    request.setRequestHeader("Content-Type", "application/json");
    request.setRequestHeader("Accept", "application/json");
    request.onreadystatechange = function() {
      if (request.readyState != 4) return;
      Root.SetLoadAnimation(false);
      const {ok, json, etag} = _this.FinishResponse(request);
      _this.changeLoginScreen(ok);
      if (ok) {
      	_this.updatePages(etag, json);
    		_this.Open(_this.getCookie("page"));
    		setTimeout(Root.instance.FetchPages, 10000, false);
      }
    };
    request.send(JSON.stringify(json));
  }
  
  Logout() {
  	const _this = this;
    let request = new XMLHttpRequest();
    Root.SetLoadAnimation(true);
    request.open("DELETE", this.url, true);
    request.setRequestHeader("Content-Type", "application/json");
    request.setRequestHeader("Accept", "application/json");
    request.onreadystatechange = function() {
      if (request.readyState != 4) return;
      Root.SetLoadAnimation(false);
      _this.FinishResponse(request);
      _this.changeLoginScreen(false);
    };
    request.send({secToken: this.secToken});
  }
  
  FetchRoutes(callOpenAfterOk = false) {
  	if (this.jwt!="") {
  		Root.SetLoadAnimation(true);
			const _this = this;
			let request = new XMLHttpRequest();
		  request.open("OPTIONS", this.url);
      request.setRequestHeader("Authorization", "Bearer " + this.jwt);
	    request.setRequestHeader("Accept", "application/json");
	    request.onreadystatechange = function() {
	      if (request.readyState != 4) return;
	      Root.SetLoadAnimation(false);
	      const {ok, json, etag} = _this.FinishResponse(request);
	      if (ok) {
	      	_this.updatePages(etag, json);
	      	if (callOpenAfterOk) {
	      		_this.Open(_this.getCookie("page"));
	      	}
	      	setTimeout(Root.instance.FetchPages, 10000, false);
    	} }
	    request.send();
    } else {
    	this.changeLoginScreen(false);
    }
  }
  
  FinishResponse(request, isHead = false) {
  	const {ok, json} = isHead ? {ok: true, json: {}} : Root.ParseJson(request.responseText);
  	if (!ok) {
  		return {ok: false, json: {}, etag: null};
  	}
    if (typeof(json.messages)!="undefined") {
		  Root.ShowMessages(json.messages);
		}
		if (typeof(json.secToken)!="undefined") {
			this.secToken = json.secToken;
			this.setCookie("secToken", json.secToken);
		}
		if (typeof(json.jwt)!="undefined") {
			this.jwt = json.jwt;
			this.setCookie("jwt", json.jwt);
		}
		if (request.status>=300) {
    	let statusString = "";
	    switch (request.status) {
	      //case 200: statusString = "OK"; break;
	      //case 201: statusString = "Erstellt"; break;
	      case 400: statusString = "Fehlerhafte Anfrage"; break;
	      case 401: statusString = "Anmeldung erforderlich"; this.changeLoginScreen(false); break;
	      case 403: statusString = "Keine Berechtigung"; break;
	      case 404: statusString = "Nicht gefunden"; break;
	      case 500: statusString = "Fehler auf Server"; break;
	      default:  statusString = "" + request.status + " = Unbekannt";
	    }
	    Root.ShowMessages(["Anfrage wurde mit Code " + request.status + " abgelehnt.<br />(" + statusString + ")"]);
	  } else {
	  	const etag = typeof(request.getResponseHeader) === 'function' ? request.getResponseHeader("ETag") : null;
	    return {ok: true, json: json, etag: etag};
	  }
		return {ok: false, json: {}, etag: null};
  }
  
  /* "Private" functions */
  
  updatePages(etag, json) {
  	if (etag!=this.routesChecksum) {
  		//StartPage.SetVisibility(true);
  		//TerminePage.SetVisibility(json.pages.includes("Termine"));
  		//DienstplänePage.SetVisibility(json.pages.includes("Dienstpläne"));
  		PersonalPage.SetVisibility(json);
  		//ProzessePage.SetVisibility(json.pages.includes("Prozesse"));
  		//SpindePage.SetVisibility(json.pages.includes("Spinde"));
  		//EinsätzePage.SetVisibility(json.pages.includes("Einsätze"));
  		//AnwesenheitenPage.SetVisibility(json.pages.includes("Anwesenheiten"));
  		FahrzeugePage.SetVisibility(json);
  		this.pagesChecksum = etag;
  } }
  
  changeLoginScreen(newStatus) {
    var s = document.getElementById('header').style;
    if (this.loggedIn==null) {
      if (!newStatus) {
        s.display = "block";
        s.opacity = 1;
      }
    } else if (newStatus) {
      (function fadeOut() {(s.opacity-=0.1)<0 ? s.display="none" : setTimeout(fadeOut, 40)})();
    } else {
      var button = document.getElementById("loginButton");
      button.disabled = false;
      button.className = "login";
      
      s.display = "block";
      (function fadeIn(){(s.opacity-=-0.1)>1 ? s.opacity=1 : setTimeout(fadeIn, 40)})();
    }
    this.loggedIn = newStatus;
  }
  
  /*updateLoginStatus(loggedIn) {
		if (loggedIn) {
		  if (loggedIn!=this.loggedIn) {
		    this.changeLoginScreen(true);
      }
      return true;
		} else {
		  this.changeLoginScreen(false);
		}
		return false;
  }*/
  
  setCookie(cname, cvalue, exdays) {
    var d = new Date();
    d.setTime(d.getTime() + (exdays*24*60*60*1000));
    var expires = "expires="+ d.toUTCString();
    document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/;SameSite=Strict;Secure";
  }
  
  getCookie(cname){
    var name = cname + "=";
    var decodedCookie = decodeURIComponent(document.cookie);
    var ca = decodedCookie.split(';');
    for(var i = 0; i <ca.length; i++) {
      var c = ca[i];
      while (c.charAt(0) == ' ') {
          c = c.substring(1);
      }
      
      if (c.indexOf(name) == 0) {
          return c.substring(name.length, c.length);
    } }
    return "";
  }
  
  /* Static functions */
  
  static ShowMessages(messages) {
    for (var i in messages) {
      Toastify({
        text: messages[i],
        duration: 3000,
        close: true,
        gravity: "top", // `top` or `bottom`
        position: "right", // `left`, `center` or `right`
        backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
        stopOnFocus: true, // Prevents dismissing of toast on hover
      }).showToast();
  } }
  
  static ToggleVisibility(idImg, idDiv) {
	  let div = document.getElementById(idDiv);
	  let img = document.getElementById(idImg);
	  if (div.style.display === "none") {
	    div.style.display = "flex";
	    img.src = "res/dark/hide.png";
	  } else {
	    div.style.display = "none";
	    img.src = "res/dark/show.png";
	  }
	}
  
	static AddEventListenerIfButtonExists(button, func) {
	  let buttonElement = document.getElementById(button);
	  if (buttonElement!==null) {
	    buttonElement.addEventListener('click', func);
	  }
	}
	
	static ParseJson(responseText) {
  	let json = {};
  	try {
	    json = JSON.parse(responseText);
  	} catch (SyntaxError) {
      Root.ShowMessages(["Parsen der Antwort gescheitert. Es folgt die Antwort!", responseText]);
      return {ok: false, json: {}};
    }
    return {ok: true, json: json};
  }
  
  static SetLoadAnimation(isLoading) {
  	var loadElement = document.getElementById("loadImage");
    if (null!=loadElement) {
    	if (isLoading) {
      	loadElement.innerHTML = "<img src='/res/loading.gif' />";
    	} else {
    		loadElement.innerHTML = "";
    	}
    }
  }
	
	/*RenderMain(root) {
    var html = "<table class='moneyplanner_accounts'>";
    
    html+= "<tr><th>" + (this.viewFrom>0 ? "<button id='view_both_left'><</button>" : "") + (this.viewTo<this.view.length-1 ? "<button id='view_both_right'>></button>" : "") + "</th>";
    for (var v=this.viewFrom; v<=this.viewTo; v++) {
      html+= "<th>"
           + (v==this.viewFrom && this.viewFrom>0 ? "<button id='view_from_left'><</button>" : "")
           + (v==this.viewTo && this.viewTo>this.viewFrom ? "<button id='view_to_left'><</button>" : "")
           + this.view[v].title
           + (v==this.viewFrom && this.viewFrom<this.viewTo ? "<button id='view_from_right'>></button>" : "")
           + (v==this.viewTo && this.viewTo<this.view.length-1 ? "<button id='view_to_right'>></button>" : "")
           + "</th>";
    }
    html+= "</tr>";
    
    for (let a in Account.byOrdering) {
      html+= Account.byOrdering[a].Render();
    }

    this.contentContainer.innerHTML = html+"</table>";

    const _this = this;
    addEventListenerIfButtonExists('view_from_left', function (event) {if (_this.viewFrom>0) {--_this.viewFrom; _this.RenderMain();}});
    addEventListenerIfButtonExists('view_from_right', function (event) {if (_this.viewFrom<_this.viewTo) {++_this.viewFrom; _this.RenderMain();}});
    addEventListenerIfButtonExists('view_to_left', function (event) {if (_this.viewTo>_this.viewFrom) {--_this.viewTo; _this.RenderMain();}});
    addEventListenerIfButtonExists('view_to_right', function (event) {if (_this.viewTo<_this.view.length-1) {++_this.viewTo; _this.RenderMain();}});
    addEventListenerIfButtonExists('view_both_left', function (event) {if (_this.viewFrom>0) {--_this.viewFrom; --_this.viewTo; _this.RenderMain();}});
    addEventListenerIfButtonExists('view_both_right', function (event) {if (_this.viewTo<_this.view.length-1) {++_this.viewFrom; ++_this.viewTo; _this.RenderMain();}});
    for (let a in Account.array) {
      let accountId = Account.array[a].id;
      addEventListenerIfButtonExists('balances_add_' + accountId, function (event) {Balance.Add(_this, _this.RenderMain, accountId);});
    }
  }*/
}

/*function ToggleEntryView(id) {api.activeRoute.ToggleEntryView(id);}
function Open(path) {api.Open(path);}
function OpenSelected() {
	let s = document.getElementById("navigation_select").value;
	if (s=="_LOGOUT_") {Logout();} else {api.Open(s);}
}
function Logout() {api.Open("/index.php/Logout");}
function FilterAdd() {api.activeRoute.FilterAdd();}
function FilterDelete(id) {api.activeRoute.FilterDelete(id);}
function FilterChange(id) {api.activeRoute.FilterChange(id);}
function Add() {api.activeRoute.Add();}
function Delete(id, data = {}) {api.Request("DELETE", data, id);}
function Edit(id) {api.activeRoute.Edit(id);}
function Cancel(id) {api.activeRoute.Cancel(id);}
function Save(id) {api.activeRoute.Save(id);}
function SubShowAdd(id, markers) {api.activeRoute.SubShowAdd(id, markers);}
function SubShowScan(id, subroute, parsers) {api.activeRoute.SubShowScan(id, subroute, parsers);}
function HideScanner() {api.scanner.Stop(); document.getElementById("qrscanner").style.display = "none";}
function SwitchCamera() {api.scanner.SwitchCamera();}
function SubAdd(id, markers, subroute) {api.activeRoute.SubAdd(id, markers, subroute);}
function SubDelete(id, subroute, subid = null) {api.Request("DELETE", {}, id, subroute, subid);}
function Request(method, data, id = null, subroute = null, subid = null) {api.Request(method, data, id, subroute, subid);}
function Print(printID, printName) {api.Request("GET", {Print: printID, PrintName: printName});}
function SelectChange(id, state) {api.activeRoute.SelectChange(id, state);}*/

document.addEventListener ("DOMContentLoaded", () => {
	var root = new Root();
});
