class Page
{
	constructor(groupName, json, route, array, groups, subs, selects, globalAdmin) {
    this.group = groups[groupName];
    this.groupName = groupName;
    this.ID = json.ID;
    this.route = route;
    this.array = array;
    this.groups = groups;
    this.subs = subs;
    this.selects = selects;
    this.admin = globalAdmin || false;//json.admin; // Local admin rights
    
    this.init(json);
    this.initSubs(json);
  }
  
  /* Static functions */
  
  static Open() {
  	document.getElementById("nav_" + Root.instance.page.toLowerCase()).classList.remove("current");
  	document.getElementById("nav_" + this.route.toLowerCase()).classList.add("current");
  	Root.instance.page = this.route;
  	document.getElementById("navigation_select").value = this.route;
    //this.FetchOptions();
  	this.Load();
  }
  
  static SetVisibility(visible) {
  	this.visible = visible;
  	document.getElementById("nav_"+this.route.toLowerCase()).style.display = visible ? "inline" : "none";
  	document.getElementById("nav_sel_"+this.route.toLowerCase()).style.display = visible ? "inline" : "none";
  }
  
  static UpdateData(json) {
  	//this.meta = json.meta;
    this.prints = json.prints;
  	this.admin = json.admin;
  	for (let sub in this.subs) {
  		this.subs[sub].entries = json.options[sub.toUpperCase()];
  	}
  	for (let sel in this.selects) {
  		this.selects[sel] = json.options[sel.toUpperCase()];
  	}
    this.visible = true;
    /*this.selected = [];
    if ("undefined"!=typeof(json.selected)) {
      this.selected = json.selected;
    }*/
    for (var k in this.filter) {
      delete this.filter[k];
    }
    this.filter = [];
    for (var l in json.filter) {
      this.filter.push(new APIFilter(json.filter[l], "none"!=json.filter[l].field ? this.mainFields[json.filter[l].field].type : "none"));
    }
    return true;
  }
  
  static Render() {
  	let html = "";
  	if (this.admin) {
  		html+= "<article id='" + this.route + "/Add'>" + this.RenderAdd() + "</article>";
  	}
  	for (const group in this.groups) {
  		const groupHtml = this.RenderGroup(group);
  		html+= groupHtml.begin;
  		
  		
  		for (const e in this.groups[group]) {
  			const entry = this.groups[group][e];
  			html+= entry.renderContainer()/*Entry(false, true)*/;
  		}
  		html+= "</article>";
  	}
  	document.getElementById("content").innerHTML = html;
    for (const ID in this.array) {
      this.array[ID].renderEntry();
  		this.array[ID].addEntryEvents();
  		this.array[ID].renderSubs();
  		this.array[ID].addSubEvents();
  	}
  	const _this = this;
  	Root.AddEventListenerIfButtonExists(this.route + "/Add/Add", function (event) {_this.Add();});
  }
  
  static Value(id, name) {
  	const e = document.getElementById(this.route+"/"+id+"/"+name);
  	return (e!==null ? e.value : null);
  }
  
  static Add(contextId = null) {
    let request = new XMLHttpRequest();
    let json = this.Collect("Add", contextId);
    json.secToken = Root.instance.secToken;
    const _this = this;
    
    request.open("POST", Root.instance.url + this.route);
    request.setRequestHeader("Authorization", "Bearer " + Root.instance.jwt);
    request.setRequestHeader("Content-Type", "application/json");
		request.setRequestHeader("Accept", "application/json");
		request.onreadystatechange = function() {
      if (request.readyState != 4) return;
      const {ok, json} = Root.instance.FinishResponse(request);
      if (ok) {
      	//_this.UpdateData(json);
      	if (typeof(_this.groups[json.content.GROUP])=="undefined") {
      		_this.groups[json.content.GROUP] = [];
      		const groupHtml = _this.RenderGroup(json.content.GROUP);
      		document.getElementById("content").insertAdjacentHTML("beforeend", groupHtml.begin + groupHtml.end);
      	}
      	const group = _this.groups[json.content.GROUP];
      	_this.array[json.content.ID] = _this.New(json.content.GROUP, json.content);
	      group.push(_this.array[json.content.ID]);
	      // Add html
	      var elList = document.getElementById("Group/" + json.content.GROUP);
      	elList.insertAdjacentHTML("beforeend", _this.array[json.content.ID].renderEntry(false, true));
				_this.array[json.content.ID].addEntryEvents();
    } };
    
    request.send(JSON.stringify(json));
  }
  
  static Load(id = null) {
    let request = new XMLHttpRequest();
    const _this = this;
    let path = Root.instance.url + this.route + (id !== null ? "/"+id : "");
    
    if (this.filter.length>0) {
      path += "?filter="+encodeURI(JSON.stringify(this.getFilter()));
    }
    
    request.open("GET", path);
    request.setRequestHeader("Authorization", "Bearer " + Root.instance.jwt);
    request.setRequestHeader("Accept", "application/json");
    request.onreadystatechange = function() {
      if (request.readyState != 4) return;
      const {ok, json} = Root.instance.FinishResponse(request);
      if (ok) {
    		if (id!==null) {
    			_this.array[id].init(json.content);
    			_this.Reset();
    		} else {
    			_this.UpdateData(json);
    			for (let g in json.content) {
    				const groupID = json.content[g].ID;
    				_this.groups[groupID] = [];
    				let group = _this.groups[groupID];
	          for (let i in json.content[g].ENTRIES) {
	          	_this.array[json.content[g].ENTRIES[i].ID] = _this.New(groupID, json.content[g].ENTRIES[i]);
	          	group.push(_this.array[json.content[g].ENTRIES[i].ID]);
			}	} } }
    	_this.Render();
    }
    request.send();
  }
  
  /* Public functions */
  
  Save() {
    const _this = this;
    let request = new XMLHttpRequest();
    
    const json = this.collect();
    json.secToken = Root.instance.secToken;
    request.open("PATCH", Root.instance.url + this.marker());
    request.setRequestHeader("Authorization", "Bearer " + Root.instance.jwt);
    request.setRequestHeader("Content-Type", "application/json");
		request.setRequestHeader("Accept", "application/json");

    request.onreadystatechange = function() {
      if (request.readyState != 4) return;
      const {ok, json} = Root.instance.FinishResponse(request);
      if (ok) {
    		//_this.UpdateData(json);
    		if (typeof(_this.groups[json.content.GROUP])=="undefined") {
    			_this.groups[json.content.GROUP] = [];
    			const groupHtml = _this.RenderGroup(json.content.GROUP);
      		document.getElementById("content").insertAdjacentHTML("beforeend", groupHtml.begin + groupHtml.end);
    		}
    		if (_this.groupName!=json.content.GROUP) {
    			_this.removeFromGroup();
    			let element = document.getElementById(_this.marker());
        	let groupel = document.getElementById("Group/" + json.content.GROUP);
        	_this.groups[json.content.GROUP].push(_this);
        	groupel.appendChild(element);
    		}
    		_this.init(json.content);
    		_this.Show(false);
		}	};
    request.send(JSON.stringify(json));
  }
  
  Delete() {
    const _this = this;
    let request = new XMLHttpRequest();
    
    request.open("DELETE", Root.instance.url + this.marker());
    request.setRequestHeader("Authorization", "Bearer " + Root.instance.jwt);
    request.setRequestHeader("Content-Type", "application/json");
		request.setRequestHeader("Accept", "application/json");
		
    request.onreadystatechange = function() {
      if (request.readyState != 4) return;
      const {ok, json} = Root.instance.FinishResponse(request);
      if (ok) {
      	_this.removeFromGroup();
        delete _this.array[_this.ID];
        let element = document.getElementById(_this.marker());
        element.parentNode.removeChild(element);
    } };
    
    request.send(JSON.stringify({secToken: Root.instance.secToken}));
  }
  
  Show(edit = false) {
  	this.renderEntry(edit, false);
  	this.addEntryEvents(edit);
  }
  
  SubShow(sub, edit) {
  	document.getElementById(this.marker(sub, "Add")).innerHTML = this.renderSubAdd(sub, edit);
  	this.addSubEvents(edit);
  }
  
  SubAdd(sub) {
  	const id = document.getElementById(this.marker(sub, "Add", sub)).value;
  	let request = new XMLHttpRequest();
    const _this = this;
    
    request.open("POST", Root.instance.url + this.marker(sub, id));
    request.setRequestHeader("Authorization", "Bearer " + Root.instance.jwt);
    request.setRequestHeader("Content-Type", "application/json");
		request.setRequestHeader("Accept", "application/json");
		request.onreadystatechange = function() {
      if (request.readyState != 4) return;
      const {ok, json} = Root.instance.FinishResponse(request);
      if (ok) {
        _this.updateSubs(sub, json.content.SUB[sub.toUpperCase()]);
    } };
    request.send(JSON.stringify({secToken: Root.instance.secToken}));
  }
  
  SubDelete(sub, id) {
  	let request = new XMLHttpRequest();
    const _this = this;
    
    request.open("DELETE", Root.instance.url + this.marker(sub, id));
    request.setRequestHeader("Authorization", "Bearer " + Root.instance.jwt);
    request.setRequestHeader("Content-Type", "application/json");
		request.setRequestHeader("Accept", "application/json");
		request.onreadystatechange = function() {
      if (request.readyState != 4) return;
      const {ok, json} = Root.instance.FinishResponse(request);
      if (ok) {
        _this.updateSubs(sub, json.content.SUB[sub.toUpperCase()]);
    } };
    request.send(JSON.stringify({secToken: Root.instance.secToken}));
  }
  
  /* "Private" functions */
  
  initSubs(json) {
  	for (const s in this.subs) {
    	this[s] = new Set();
    	for (let i in json.SUB[s.toUpperCase()]) {
    		this[s].add(json.SUB[s.toUpperCase()][i].ID);
  } } }
  
  updateSubs(sub, newSubList) {
    this[sub].clear();
    for (let i in newSubList) {
      this[sub].add(newSubList[i].ID);
    }
    this.renderSubs(sub);
  	this.addSubEvents(sub);
  }
  
  // first = action or subroute, second = subID, third = subAction
  marker(firstAppend = null, secondAppend = null, thirdAppend = null) {
    let id = this.route + "/" + this.ID;
    if (firstAppend!==null) {
      id+= "/" + firstAppend;
      if (secondAppend!==null) {
        id+= "/" + secondAppend;
        if (thirdAppend!==null) {
          id+= "/" + thirdAppend;
    } } }
    return id;
  }
  
  renderContainer() {
    let html = "<div id='" + this.marker() + "' class='list_entry'>"
             + "<div id='" + this.marker("Main") + "' class='list_entry_title'></div>";
    if (Object.keys(this.subs).length>0) {
      html+= "<div class='list_entry_row'>";
	    for (let s in this.subs) {
	  	  html+= "<ul id='" + this.marker(s) + "'></ul>";
	    }
	    html+= "</div>";
    }
	  html+= "</div>";
	  return html;
  }
  
  renderField(icon, value) {
    return "<li><img src='/res/dark/" + icon + "' />" + value + "</li>";
  }
  
  renderInput(name, value, width = 8, maxLength = null) {
    return "<input id='" + this.marker(name) + "' value='" + value + "' " 
         + (maxLength!==null ? " maxlength=" + maxLength : "")
         + " style='width:"+ width + "em;'/>";
  }
  
  renderButton(icon, name, title) {
    return "<li id='" + this.marker(name) + "' class='button' title='" + title + "'><img src='/res/dark/" + icon + "' /></li>"
  }
  
  renderSelect(name, selected, width = 8) {
  	let html = "<select id='" + this.marker(name) + "' style='width: " + width + "em;'>";
  	for (const e in this.selects[name]) {
  		const entry = this.selects[name][e];
  		html+= "<option value='" + entry.ID + "'" + (entry.ID==selected ? " selected" : "") + ">" + (typeof(entry.KÜRZEL)!="undefined" ? entry.KÜRZEL : entry.NAME) + "</option>";
  	}
  	return html+"</select>";
  }
  
  renderSubs(onlyOneSub = null) {
	  // TODO: SUBS
	  let subs = {};
	  if (onlyOneSub===null) {
	    subs = this.subs;
	  } else {
	    subs[onlyOneSub] = this.subs[onlyOneSub];
	  }
	  for (let s in subs) {
	    let html = "";
	    if (typeof(this.subs[s])!="undefined") {
  	    for (let e in this.subs[s].entries) {
  	  	  const entry = this.subs[s].entries[e];
  	  	  if (this[s].has(entry.ID)) {
  		  	  html+= "<li class='" + this.subs[s].color + "' title='" + entry.NAME + "'><img src='/res/dark/" + this.subs[s].icon + "' />"
  		  	       + (typeof(entry.KÜRZEL)!="undefined" ? entry.KÜRZEL : entry.NAME)
  		  	       + (this.admin ? " <img id='" + this.marker(s, entry.ID, "Delete") + "' src='/res/dark/delete.png' class='button' />" : "")
  		  	       + "</li>";
  	  	} }
  	    if (this.admin) {
    		  html+= "<li class='" + this.subs[s].color + "' id='" + this.marker(s, "Add") + "'>" + this.renderSubAdd(s, false) + "</li>";
    	  }
  	    document.getElementById(this.marker(s)).innerHTML = html;
	} } }
  
  renderSubAdd(sub, add) {
  	let html = "<img src='/res/dark/" + this.subs[sub].icon + "' />";
  	if (add) {
  		html+= "<select id='" + this.marker(sub, "Add", sub) + "'>";
  		for (let i in this.subs[sub].entries) {
  			const entry = this.subs[sub].entries[i];
  			if (!this[sub].has(entry.ID)) {
  				html+= "<option value='" + entry.ID + "'>" + entry.NAME + "</option>";
  		} }
  		html+= "</select>";
  		html+= "<img class='button' id='" + this.marker(sub, "Add/Add") + "' src='/res/dark/save.png' />";
  		html+= "<img class='button' id='" + this.marker(sub, "Add/Reset") + "' src='/res/dark/cancel.png' />";
  	} else {
  		html+= "<img class='button' id='" + this.marker(sub, "Add/Show") + "' src='/res/dark/add.png' />";
  	}
  	return html;
  }
  
  addSubEvents() {
  	const _this = this;
  	for (let sub in this.subs) {
  		for (const id of this[sub]) {
  			Root.AddEventListenerIfButtonExists(this.marker(sub, id, "Delete"), function (event) {_this.SubDelete(sub, id);});
			}
  		Root.AddEventListenerIfButtonExists(this.marker(sub, "Add/Show"), function (event) {_this.SubShow(sub, true);});
  		Root.AddEventListenerIfButtonExists(this.marker(sub, "Add/Add"), function (event) {_this.SubAdd(sub);});
  		Root.AddEventListenerIfButtonExists(this.marker(sub, "Add/Reset"), function (event) {_this.SubShow(sub, false);});
  } }
  
  removeFromGroup() {
  	for (let i in this.groups[this.group]) {
  		if (this.groups[this.group][i].ID==this.ID) {
  			delete _this.groups[this.group][i];
  			break;
  } } }
  
  addEntryEvents(edit) {
  	const _this = this;
  	if (edit) {
			Root.AddEventListenerIfButtonExists(this.marker("Save"), function (event) {_this.Save();});
			Root.AddEventListenerIfButtonExists(this.marker("Delete"), function (event) {_this.Delete();});
    	Root.AddEventListenerIfButtonExists(this.marker("Reset"), function (event) {_this.Show(false);});
		} else {
			Root.AddEventListenerIfButtonExists(this.marker("Edit"), function (event) {_this.Show(true);});
	} }
}
