/*=========================================================
	MODULE zJsNemu
	----------------------------------------------------
	Bibliothèque de gestion des menus
=========================================================*/
import * as zLib from "./zJsLibrary.js";

export class MenuManager {

	#shortcutMap = new Map();

	//===========================================================================================
	//		Constructor
	//===========================================================================================
	constructor(objMenuStructure) {
		zLib.getXmlRoot(objMenuStructure)
		.then(xmlRoot => {
			//console.log(xmlRoot);
			const parseError = xmlRoot.getElementsByTagName('parsererror');
			if(parseError.length) console.error('Error parsing XML layout:\n',parseError[0].innerText);
			
			let parent = null;
			// Identification du conteneur parent
			if(xmlRoot.hasAttribute('containerId')) parent = document.getElementById(xmlRoot.getAttribute('containerId'));
			// En l'absence de parent, une div dédiée est crée
			if(!parent) parent = document.createElement('div');
			
			// Analyse de la structure pour construction
			this.#elmIterator(xmlRoot, parent)
			// Variable internes à la classe
			this.html = parent;
			this.structure = xmlRoot;
			this.uploadIndex = 0;

			// Ajout du listener pour les raccourcis
			if(this.#shortcutMap) {
				document.addEventListener('keydown', (event) => {
					this.#shortcutMap.forEach((shortcut, id) =>{
						if (
							event.ctrlKey	=== shortcut.ctrl &&
							event.shiftKey	=== shortcut.shift &&
							event.altKey	=== shortcut.alt &&
							event.key.toLowerCase() === shortcut.key
						) {
							console.log(id);
							let optionPath=this.#getOptionPath(id.substring(1));
							console.log(id);
							window.postMessage({ action: "menu", payload:{optionId: id, optionPath:optionPath}}, "*");
							event.preventDefault();
						}
					})
				})
				
			}
		})
		.catch(err => console.error(err))
	}

	//===========================================================================================
	//		Iterator
	//===========================================================================================
	#elmIterator(xmlNode, parentDomNode, level=0) {
		//console.log('iterator:',xmlNode);
		
		// On ignore les noeuds texte ou commentaire
		if(xmlNode.nodeType !== 1) return;
		// On cérupère le nom de la balise
		const tagName = xmlNode.tagName;
		//console.log('tagName:', tagName);

		let domNode = null;
		// Test si la balise correspond à une fonction de construction
		let fn = "_build"+tagName[0].toUpperCase()+tagName.slice(1);
		//console.log(`> function to call [${fn}]`);

		if(this[fn]) {
			domNode = this[fn](xmlNode, parentDomNode);
			if(parentDomNode && domNode) parentDomNode.appendChild(domNode);
		}

		// Parcourt récursivement les enfants
		for(let child of xmlNode.children) {
			this.#elmIterator(child, domNode || parentDomNode, level+1);
		}
	}
	//===========================================================================================
	//		Menu Standard
	//===========================================================================================
	_buildMenu(obj, parent) {
		//console.log('_buidMenu:', obj, parent);
		
		// Conteneur principal du Menu
		const container = document.createElement('div');
		container.classList = "zObj zContainer zMenuContainer unselectable";

		if(obj.id) container.id = obj.id;

		if(obj.hasAttribute('icon')) {
			const icon = document.createElement("img");
			img.style.height = zLib.getCssRootVariable("--genericField-height");
			img.src = obj.getAttribute('icon');
			container.appendChild(icon);
		}

		// Intégration du conteneur principal dans le "parent"
		parent.appendChild(container);

		// Fermeture du menu si click à l'extérieur
		document.addEventListener("click", (event) => {
			if(container.opened)	if(!container.contains(event.target)) this.#closeMenu(container);
		})

		// Renvoi du conteneur principal
		return container;
	}

	_buildMenuOption(obj, parent) {
		//console.log("BuildMenuOption:", obj);

		// Récupération de Niveau du parent
		var level = parent.level ?? "";
		var index = parent.childElementCount;
		const objLevel = level+index;

		// Conteneur principal du Menu
		const container = document.createElement("div");

		const optionContainer = document.createElement("div");
		optionContainer.id = "O"+objLevel;
		optionContainer.level = objLevel;

		const label = obj.childNodes[0].textContent;

		if(parent.classList.contains("zMenuContainer")) {
			optionContainer.classList.add("zPrimaryOption");
			optionContainer.innerHTML = label;
		} else {
			optionContainer.classList.add("zMenuOption");
			if(obj.hasAttribute('class')) {
				const classlist = zLib.parseArray(obj.getAttribute('class'));
				for(const newClass of classlist) optionContainer.classList.add(newClass);
			}

			// icon
			const iconContainer =  document.createElement("div");
			iconContainer.classList.add("zOptIcon");
			if(obj.hasAttribute('icon')) {
				const icon = document.createElement("img")
				icon.src = obj.getAttribute('icon');
				iconContainer.appendChild(icon);
			}

			// label
			const labelContainer = document.createElement("div");
			labelContainer.classList.add("zOptLabel");
			labelContainer.innerHTML = label;

			// shortcut
			const shortcutContainer = document.createElement('div');
			shortcutContainer.classList.add("zOptShortcut");
			if(obj.hasAttribute('shortcut')) shortcutContainer.innerHTML = obj.getAttribute('shortcut');
			if(obj.childElementCount) shortcutContainer.innerHTML = "▷";

			// Intégration des éléments dans le conteneur principal
			optionContainer.appendChild(iconContainer);
			optionContainer.appendChild(labelContainer);
			optionContainer.appendChild(shortcutContainer);

			// on Click
			if(obj.hasAttribute('onClick')) optionContainer.setAttribute("onclick", obj.getAttribute('onClick'));
		}
		container.appendChild(optionContainer);

		// Intégration du conteneur principal dans le "parent"
		parent.appendChild(container);

		// Ajout du raccourci à la table des raccourcis
		if(obj.hasAttribute('shortcut')) this.#shortcutMap.set(optionContainer.id, this.#parseShortcut(obj.getAttribute('shortcut')));

		// Récupération du conteneur à la racine du menu
		const rootContainer = container.closest(".zMenuContainer");

		var subMenuContainer;
		//console.log(obj.childElementCount);
		if(obj.childElementCount){
			// L'option à un sous-menu
			//--------------------------------------
			// Conteneur du sous-menu
			subMenuContainer = document.createElement("div");
			subMenuContainer.id = "M"+objLevel;
			subMenuContainer.level = objLevel;
			subMenuContainer.classList.add("zSubMenuContainer");
			container.appendChild(subMenuContainer);
		}

		// Click sur l'option (ouverture du sous-menu ou sélection option)
		optionContainer.addEventListener("click",(e) => {
			if(!optionContainer.classList.contains('disabled')) {
				if(!rootContainer.opened) {
					//console.log("Open menu:", "M"+optionContainer.level);
					// Mémorisation du menu ouvert
					rootContainer.opened = subMenuContainer.level;
					// Menu actif
					optionContainer.classList.add("active");
					// Positionnement du menu
					const rootRect		= rootContainer.getBoundingClientRect();
					const parentRect	= parent.getBoundingClientRect();
					const anchorRect	= optionContainer.getBoundingClientRect();
					const padding		= zLib.sizingToPxFloat(zLib.getCssRootVariable("--spacing_small"));

					if(objLevel.length==1) {
						subMenuContainer.style.top = rootRect.height + 'px';
						subMenuContainer.style.left = anchorRect.left - rootRect.left + 'px';
					}
					// Affichage du conteneur des options
					subMenuContainer.classList.add("visible");
				} else if(!obj.childElementCount) {
					//console.log("> Option selected:",container.id);
					if(!obj.hasAttribute('onClick')) window.postMessage({ action: "menu", payload:{optionId:optionContainer.id, optionPath:this.#getOptionPath(optionContainer.level)}}, "*");
					// Fermeture du menu
					this.#closeMenu(rootContainer)
				}
			}
		});

		// Parcours des options du menu
		optionContainer.addEventListener("mouseover",(e) => {
			if(!optionContainer.classList.contains('disabled')) {
				e.stopPropagation();
			
				var timerId;
				if(rootContainer.opened) {
					const selected = objLevel;
					const active	= rootContainer.opened;
					//console.log("active:", active, " - selected:",selected);

					// Si changement
					if(selected!=active) {
						// changement dans le même niveau ou niveau invérieur
						if(active.length>=selected.length) {
							// Désactivation des menus actifs jusqu'au nouveau niveau sélectionné
							var activeChain = active
							while(activeChain.length>=selected.length) {
								const subMenu = document.getElementById("M"+activeChain)
								if(subMenu) subMenu.classList.remove("visible");
								document.getElementById("O"+activeChain).classList.remove("active");
								activeChain = activeChain.slice(0, activeChain.length-1);
							}
							rootContainer.opened = selected;
						}
						// Si l'option dispose d'un sous-menu
						if(subMenuContainer) {
							//timerId = setTimeout(() => {
								optionContainer.classList.add("active");
								rootContainer.opened = selected;
								// Positionnement du menu
								//console.log("active:",active,"selected:",selected)
								const rootRect		= rootContainer.getBoundingClientRect();
								//console.log("rootRect.top:",rootRect.top)
								const parentRect	= parent.getBoundingClientRect();
								//console.log("parentRect.top:",parentRect.top)
								const anchorRect	= optionContainer.getBoundingClientRect();
								//console.log("anchorRect.top:",anchorRect.top)
								var padding = zLib.sizingToPxFloat(zLib.getCssRootVariable("--spacing_small"));

								if(objLevel.length==1) {
									subMenuContainer.style.top = rootRect.height + 'px';
									subMenuContainer.style.left = anchorRect.left -rootRect.left + 'px';
								} else {
									//subMenuContainer.style.top = anchorRect.top - parentRect.top - padding + 'px';
									subMenuContainer.style.top = anchorRect.top - parentRect.top - (4.8+0.668*2) + 'px';
									subMenuContainer.style.left = parentRect.width + 'px';
								}
								// Affichage du conteneur des options
								subMenuContainer.classList.add("visible");
							//}, (selected.length==1)? 0 : 500);
						}
					} else clearTimeout(timerId);
				}
			}
		});
 
		if(obj.hasAttribute('disabled')) optionContainer.classList.add("disabled");

		// Renvoi du conteneur de sous-menu
		if(subMenuContainer) return subMenuContainer;
		else return container;

	}

	_buildSeparator(obj, parent){
		const container = document.createElement('div');
		container.classList.add("zSeparator");
		parent.appendChild(container);
		return container;
	}

	#closeMenu(menuContainer) {
		var levelPath = menuContainer.opened;
		while(levelPath.length>0) {
			//console.log("levelPath:",levelPath)
			const menu = document.getElementById("M"+levelPath);
			if(menu) menu.classList.remove("visible");
			const option = document.getElementById("O"+levelPath);
			if(option) option.classList.remove("active");
			levelPath = levelPath.slice(0, levelPath.length-1);
		}
		menuContainer.opened = false;
	}

	onMenu(handler) {
		window.addEventListener("message", (event) => {
			//console.log("onMenu:",event.data);
			const { action, payload } = event.data;
			if ( action === "menu") handler(payload);
		});
	}
	optionEnable(objOption, enable=true) {
		//console.log('> optionEnable:', objOption);
		//console.log('... html:', this.html);
		if(!this.html) return
		var optContainer = null;
		// Traitement par class
		if(objOption.class) {
			let options = this.html.querySelectorAll(`div.${objOption.class}`);
			options.forEach(optContainer => {
				if(enable) optContainer.classList.remove('disabled');
				else optContainer.classList.add('disabled')
			})
		} else {
			// Traitement par ID
			if(objOption.id) 	optContainer = this.html.querySelector(`#${id}`);
			// Traitement par label
			if(objOption.label)	{
				let options = this.html.querySelectorAll('div.zOptLabel');
				let optMatch = Array.from(options).find(el => el.innerHTML === objOption.label);
				if(optMatch) optContainer = optMatch.parentElement;
			}
			// Ajout de la class 'disabled'
			if(optContainer) {
				if(enable) optContainer.classList.remove('disabled');
				else optContainer.classList.add('disabled')
			}
		}
	}

	#parseShortcut(shortcutStr) {
		const parts = shortcutStr.toUpperCase().split('+');
		return {
			ctrl:		parts.includes('CTRL'),
			shift:	parts.includes('SHIFT'),
			alt:		parts.includes('ALT'),
			key:		parts.find(p => !['CTRL', 'SHIFT', 'ALT'].includes(p)).toLowerCase()
		};
	}

	#getOptionPath(levelPath) {
		console.log(levelPath);
		var optPath = [];
		while(levelPath.length>0) {
			let filter = `#O${levelPath}`;
			const optContainer = document.querySelector(filter);
			const optLabel = optContainer.querySelector("div.zOptLabel");
			optPath.push((optLabel)? optLabel.innerHTML : optContainer.innerHTML);
			levelPath = levelPath.slice(0, levelPath.length-1);
		}
		return optPath;
	}



/* END OF CLASS */
}