/*
*  LibreSignage markup syntax definitions.
*/

var err = require('./error.js');
var markup_utils = require('./markup_utils.js');

/*
*  Evaluator argument type defs.
*/
const ARGTYPES = {
	'percent': {
		code: 0,
		typestr: 'percent'
	},
	'int': {
		code: 1,
		typestr: 'int'
	},
	'str': {
		code: 2,
		typestr: 'str'
	},
	'rstr': {
		code: 3,
		typestr: 'rstr'
	}
};
module.exports.ARGTYPES = ARGTYPES;

/*
*  Evaluator expression definitions.
*
*  Each entry in this object defines a valid tag of the
*  form [name][/name] where 'name' is the key in the object.
*  Each definition contains the following values:
*
*    - has:    A dictionary of required arguments. The arguments
*              are defined as key-value pairs where the key is the
*              argument name and the value is one of the argument
*              types defined in the ARGTYPES dictionary.
*    - handle: A function for generating the output corresponding
*              to the expression. The AST node that's being evaluated
*              is passed to this function as the first argument.
*              This function must return an array containing two
*              strings. The first one is the opening HTML tag and
*              the second one is the closing tag.
*
*  A definition can also contain an 'accepts' dictionary. The
*  dictionary maps arguments to sets of accepted values. See the
*  'align' tag for an example.
*/
module.exports.EXPRESSIONS = {
	__root__: { has: {}, handle: () => { return ['', '']; } },
	__inner__: {
		has: { 'text': ARGTYPES.rstr },
		handle: (node) => {
			return [ markup_utils.sanitize(node.data.text), '' ]
		}
	},
	h: {
		has: { 'size': ARGTYPES.percent },
		handle: (node) => {
			let s = node.data.size.replace('%', 'vh');
			return [
				`<h1 style="font-size: ${s};">`,
				'</h1>'
			];
		}
	},
	lead: {
		has: {},
		handle: (node) => {
			return [
				`<p class="lead">`,
				'</p>'
			]
		}
	},
	b: {
		has: {},
		handle: () => {
			return [
				'<span style="font-weight: bold;">',
				'</span>'
			];
		}
	},
	i: {
		has: {},
		handle: () => {
			return [
				'<span style="font-style: italic;">',
				'</span>'
			];
		}
	},
	img: {
		has: {
			'url': ARGTYPES.str,
			'width': ARGTYPES.percent,
			'height': ARGTYPES.percent
		},
		handle: (node) => {
			let w = node.data.width.replace('%', 'vw');
			let h = node.data.height.replace('%', 'vh');
			return [
				`<img src=${node.data.url} style="width: ${w}; height: ${h};">`,
				'</img>'
			];
		}
	},
	video: {
		has: {
			'url': ARGTYPES.str,
			'width': ARGTYPES.percent,
			'height': ARGTYPES.percent,
			'muted': ARGTYPES.int
		},
		handle: (node) => {
			let w = node.data.width.replace('%', 'vw');
			let h = node.data.height.replace('"', 'vh');
			let m = node.data.muted === '1';
			return [
				`<video src=${node.data.url} ` + 
					`style="display: block; ` +
					`width: ${w}; ` +
					`height: ${h};" ` +
					`autoplay ` +
					`${m ? 'muted' : ''}>`,
				'</video>'
			];
		}
	},
	p: {
		has: {},
		handle: () => {
			return ['<p>', '</p>'];
		}
	},
	size: {
		has: { 'size': ARGTYPES.percent },
		handle: (node) => {
			let s = node.data.size.replace('%', 'vh');
			return [
				`<span style="font-size: ${s}">`,
				'</span>'
			];
		}
	},
	color: {
		has: { 'c': ARGTYPES.rstr },
		handle: (node) => {
			/*
			*  Check that the supplied color is a valid CSS color.
			*  This prevents CSS injections.
			*/
			if (!markup_utils.is_css_color(node.data.c)) {
				throw new err.MarkupSyntaxError(
					'EVAL',
					node.lexeme,
					`Invalid color '${node.data.c}'.`
				);
			}

			return [
				`<span style="color: ${node.data.c};">`,
				'</span>'
			];
		}
	},
	font: {
		has: { 'f': ARGTYPES.str },
		handle: (node) => {
			return [
				`<span style='font-family: ${node.data.f}'>`,
				'</span>'
			];
		}
	},
	container: {
		has: {
			'top': ARGTYPES.percent,
			'right': ARGTYPES.percent,
			'bottom': ARGTYPES.percent,
			'left': ARGTYPES.percent
		},
		handle: (node) => {
			let t = node.data.top.replace('%', 'vh');
			let r = node.data.right.replace('%', 'vh');
			let b = node.data.bottom.replace('%', 'vh');
			let l = node.data.left.replace('%', 'vh');
			return [
				`<div style="
					padding: ${t} ${r} ${b} ${l};
					width: 100%;
					height: 100%;">`,
				'</div>'
			];
		}
	},
	xcenter: {
		has: {},
		handle: () => {
			return [
				`<div style="margin-left: auto;
							margin-right: auto;
							text-align: center;
							width: auto;
							height: auto;">`,
				'</div>'
			];
		}
	},
	columns: {
		has: {},
		handle: () => {
			return [
				`<div style="display: flex;
						flex-direction: row;
						width: auto;
						height: auto;">`,
				'</div>'
			];
		}
	},
	align: {
		has: { 'type': ARGTYPES.rstr },
		accept: { 'type': ['left', 'right', 'center', 'justify']},
		handle: (node) => {
			return [
				`<div style="text-align: ${node.data.type};">`,
				'</div>'
			];
		}
	},
	bgcolor: {
		has: { 'c': ARGTYPES.rstr },
		handle: (node) => {
			/*
			*  Check that the supplied color is a valid CSS color.
			*  This prevents CSS injections.
			*/
			if (!markup_utils.is_css_color(node.data.c)) {
				throw new err.MarkupSyntaxError(
					'EVAL',
					node.lexeme,
					`Invalid color '${node.data.c}'.`
				);
			}

			return [
				`<style>
					body {
						background-color: ${node.data.c} !important;
					}
				</style>`,
				``
			];
		}
	},
	bgimg: {
		has: { 'url': ARGTYPES.str },
		handle: (node) => {
			return [
				`<style>
					body {
						background-image: url(${node.data.url});
						background-position: center;
						background-size: cover;
					}
				</style>`,
				``
			];
		}
	},
	iframe: {
		has: { 
			'url': ARGTYPES.str,
			'width': ARGTYPES.percent,
			'height': ARGTYPES.percent,
		},
        handle: (node) => {
            return [
                `<iframe src=${node.data.url} width="${node.data.width}" height="${node.data.height}" frameborder="0">`,
                `</iframe>`
            ];
        }
    }
};
