/* jslint node: true, esnext: true */
'use strict';

/**
 * @module config-expander
 */

const fs = require('fs'),
	path = require('path'),
	crypto = require('crypto');

import {
	readFile, createValue
}
from './util';

import {
	expand
}
from './expander';

export const functions = {
	document: {
		arguments: ['string'],
		returns: 'blob',
		apply: (context, args) => createValue(readFile(path.resolve(context.constants.basedir, args[0].value)))
	},
	directory: {
		arguments: ['string'],
		returns: 'string',
		apply: (context, args) => createValue(path.resolve(context.constants.basedir, args[0].value))
	},
	include: {
		arguments: ['string'],
		returns: 'object',
		apply: (context, args) => {
			const file = path.resolve(context.constants.basedir, args[
				0].value);

			return createValue(expand(JSON.parse(fs.readFileSync(file)), {
				constants: {
					basedir: path.dirname(file)
				}
			}));
		}
	},
	number: {
		arguments: ['string|number'],
		returns: 'number',
		apply: (context, args) => {
			const v = args[0].value;
			return createValue(parseFloat(v) === v ? v : parseFloat(v.replace(/[a-z]+/, '')));
		}
	},
	substring: {
		arguments: ['string', 'integer', 'integer'],
		returns: 'string',
		apply: (context, args) => createValue(args[0].value.substring(args[1].value, args[2].value))
	},
	replace: {
		arguments: ['string', 'string', 'string'],
		returns: 'string',
		apply: (context, args) => createValue(args[0].value.replace(args[1].value, args[2].value))
	},
	toUpperCase: {
		arguments: ['string'],
		returns: 'string',
		apply: (context, args) => createValue(args[0].value.toUpperCase())
	},
	toLowerCase: {
		arguments: ['string'],
		returns: 'string',
		apply: (context, args) => createValue(args[0].value.toLowerCase())
	},

	encrypt: {
		arguments: ['string', 'string'],
		returns: 'string',
		/**
		 * Encrypt a plaintext value
		 * @param {String} key
		 * @param {String} plaintext
		 * @return {String} encrypted value
		 */
		apply: (context, args) => {
			const [key, plaintext] = args.map(a => a.value);
			const encipher = crypto.createCipher('aes-256-cbc', key);
			let encryptdata = encipher.update(plaintext, 'utf8', 'binary');
			encryptdata += encipher.final('binary');
			const encode_encryptdata = new Buffer(encryptdata, 'binary').toString('base64');
			return createValue(new Buffer(encryptdata, 'binary').toString('base64'));
		}
	},

	decrypt: {
		arguments: ['string', 'string'],
		returns: 'string',
		/**
		 * Decrypt a string
		 * @param {String} key
		 * @param {String} encrypted
		 * @return {String} plaintext
		 */
		apply: (context, args) => {
			let [key, encryptdata] = args.map(a => a.value);
			encryptdata = new Buffer(encryptdata, 'base64').toString('binary');
			const decipher = crypto.createDecipher('aes-256-cbc', key);
			let decoded = decipher.update(encryptdata, 'binary', 'utf8');
			decoded += decipher.final('utf8');
			return createValue(decoded);
		}
	}
};

// BACKward compatibility only
functions.file = functions.document;

@@ -798,52 +798,68 @@
 lue(
-expand(JSON.parse(fs.readFileSync(file)
+readFile(file).then(data =%3E%0A%09%09%09%09expand(JSON.parse(data
 ), %7B%0A
+%09
 %09%09%09%09
@@ -876,16 +876,17 @@
  %7B%0A%09%09%09%09%09
+%09
 basedir:
@@ -913,14 +913,21 @@
 %09%09%09%09
+%09
 %7D%0A%09%09%09
-%7D
+%09%7D)%0A%09%09%09
 ));%0A

make include() async