/*!
 * Baxxon 
 * Copyright(c) 2000-2026 Lorne Taylor
 * MIT Licensed
 */

// Templates
// minimal template engine

export default class Templates {

	defaultTemplates = {
		root: `<!doctype html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<meta content="width=device-width" name="viewport">
		<meta name="generator" content="Baxxon">
		{head}
	</head>
	<body>
		{body}
	</body>
</html>`,
		head: `<title>{title}</title>`,
		body: `{content}`
	}

	constructor(templates){

		this.templates = {};
		if(templates === undefined){
			templates = this.defaultTemplates;
		}
		this.init(templates);
	}

	init(templates){

		for(const name of Object.keys(templates)){
			const tpl = templates[name];
			this.templates[name] = new Template(tpl);
		}
	}

	merge(name){

		const tplVars = this.templates[ name ].getVars(); 
		for(const tplVar of tplVars){
			if(this.templates.hasOwnProperty(tplVar)){
				let output = this.merge(tplVar); 
				this.templates[name].setVar(tplVar, output);
			}
		}

		return this.templates[name].merge();
	}

	get(name){

		if(name === undefined){

			return this.templates;
		}
		else{

			return this.templates[ name ];
		}
	}

}

class Template {

	constructor(tpl){

		this.template = '';
		this.data = {};
		this.set(tpl);
	}
	
	set(tpl){

		if(typeof tpl === 'string'){
			this.template = tpl.trim();
			this.initVars();
		}
	}
	
	get(){

		return this.template;
	}

	// Securely merge variables into the template string.
	merge(){

		return this.template.replace(/{(.*?)}/g, (match, key)=>{

			return this.data.hasOwnProperty(key) ? String(this.data[key]) : match;
		});
	}

	// template vars
	initVars(){

		const regx = /(?<={)[^}]+/mg
		const names = this.template.match(regx);
		if(Array.isArray(names)){
			names.forEach((name) => {
				this.setVar(name, ``);
			})
		}
	}

	setVars(vars){

		if(typeof vars === 'object' && !Array.isArray(vars)){
			for(const name in vars){
				this.setVar(name, vars[name]);
			}
		}
	}

	pushVars(vars){

		if(typeof vars === 'object' && !Array.isArray(vars)){
			for(const name in vars){
				this.pushVar(name, vars[name]);
			}
		}
	}

	getVars(){

		return Object.keys(this.data);
	}

	setVar(name, val){

		if(typeof val === 'string' || typeof val === 'number'){
			this.data[name] = String(val);
		}
	}

	pushVar(name, val){

		if(typeof val === 'string' || typeof val === 'number'){
			const current = this.data[name] || '';
			this.data[name] = current.concat(String(val));
		}
	}

	getVar(name){

		return this.data[name];
	}
}
