/* 
 * Copyright 2017, Emanuel Rabina (http://www.ultraq.net.nz/)
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

const StandardTextAttributeProcessor = require('./processors/StandardTextAttributeProcessor');

const Promise                    = require('bluebird');
const {jsdom, serializeDocument} = require('jsdom');

const fs = require('fs');


const XML_NAMESPACE_ATTRIBUTE = 'xmlns:th';

// List of supported attribute processors, limits what we can do but lets me
// impose basic ordering as per the behaviour in main Thymeleaf.
const ATTRIBUTE_PROCESSORS = [
	new StandardTextAttributeProcessor()
];

/**
 * Process a DOM element.
 * 
 * @param {Element} element
 * @param {Object} context
 */
function processNode(element, context) {

	// Process the current element
	ATTRIBUTE_PROCESSORS.forEach(attributeProcessor => {
		let attribute = `${attributeProcessor.prefix}:${attributeProcessor.name}`;
		if (!element.hasAttribute(attribute)) {
			attribute = `data-${attributeProcessor.prefix}-${attributeProcessor.name}`;
			if (!element.hasAttribute(attribute)) {
				return;
			}
		}
		let attributeValue = element.getAttribute(attribute);
		attributeProcessor.process(element, attribute, attributeValue, context);
	});

	// Process this element's children
	Array.from(element.children).forEach(child => {
		processNode(child, context);
	});
}

/**
 * Process the Thymeleaf template data, returning the processed template.
 * 
 * @param {String} template
 * @param {Object} context
 * @return {Promise}
 *   Bluebird promise resolved with the processed template, or rejected with an
 *   error message.
 */
function process(template, context) {

	return new Promise((resolve, reject) => {
		try {
			let document = jsdom(template, {
				features: {
					FetchExternalResources: false,
					ProcessExternalResources: false
				}
			});

			let htmlElement = document.documentElement;
			processNode(htmlElement, context);

			// TODO: Special case, remove the xmlns:th namespace from the document.
			//       This should be handled like in main Thymeleaf where it's just
			//       another processor that runs on the document.
			if (htmlElement.hasAttribute(XML_NAMESPACE_ATTRIBUTE)) {
				htmlElement.removeAttribute(XML_NAMESPACE_ATTRIBUTE);
			}

			let documentAsString = serializeDocument(document);
			resolve(documentAsString);
		}
		catch (exception) {
			reject(exception);
		}
	});
}

exports.process = process;

/**
 * Process the Thymeleaf template at the given path, returning a promise of the
 * processed template.
 * 
 * @param {String} filePath
 * @param {Object} context
 * @return {Promise}
 *   Bluebird promise resolved with the processed template, or rejected with an
 *   error message.
 */
function processFile(filePath, context) {

	return new Promise(function(resolve, reject) {
		fs.readFile(filePath, function(error, data) {
			if (error) {
				reject(error);
			}
			else {
				resolve(process(data, context));
			}
		});
	});
}

exports.processFile = processFile;

/**
 * Export for integration w/ Express.
 * 
 * @param {String} filePath
 * @param {Object} options
 * @param {Function} callback
 */
exports.__express = function(filePath, options, callback) {

	processFile(filePath, options).then(callback);
};

@@ -3311,24 +3311,16 @@
 Promise(
-function
 (resolve
@@ -3328,16 +3328,19 @@
  reject)
+ =%3E
  %7B%0A%09%09fs.
@@ -3358,24 +3358,16 @@
 lePath, 
-function
 (error, 
@@ -3371,16 +3371,19 @@
 r, data)
+ =%3E
  %7B%0A%09%09%09if
@@ -3561,24 +3561,90 @@
 xpress.%0A * %0A
+ * TODO: Should this be a separate module, express-thymeleaf?%0A * %0A
  * @param %7BS
@@ -3724,36 +3724,35 @@
  */%0A
-exports.__express = function
+function processFileExpress
 (fil
@@ -3779,17 +3779,16 @@
 back) %7B%0A
-%0A
 %09process
@@ -3814,24 +3814,159 @@
 ons)
+%0A%09%09
 .then(
-callback);%0A%7D
+template =%3E %7B%0A%09%09%09callback(null, template);%0A%09%09%7D)%0A%09%09.catch(error =%3E %7B%0A%09%09%09callback(error);%0A%09%09%7D);%0A%7D%0A%0Aexports.processFileExpress = processFileExpress
 ;%0A

Rename __express - it's for a package and template extension match