"use strict"

require("simple-errors");

var path = require("path");
var winston = require("winston");
var edge = require("edge");

var kidoConnector = require("kido-connector");

// using kido connector to configure winston
kidoConnector.init("node-exchange-api", winston);

/*
* @param 'config' {object} Required. Constructor options. It can have the following properties:
*	- 'url' {string} Required. The endpoint rest that should be call at each method.
*
*	- 'authCtx' {object} Required. Authentication context to access the EWS service.
*		- 'type' {string} Optional (default: 'basic') => requires 'username' {string} & 'password' {string} 
*
*	- 'impersonate' {object} Optional. Used if the authCtx user should impersonate another user.
*		- 'claim' {string} Optional. If impersonation is used this indicates the claim value to use as source.
*		- 'regex' {string} Optional. Regex used to parse impersonation claim value and extract basic chunks to reuse.
*		- 'output' {string} Optional. Returned value if the previous parameters is used (this is the target to impersonate).
*
*	- 'debuggingEnabled' {boolean} Optional. Writes basic logging info to standard output.
*
*	- 'd1s4bl3CertificateCh3ck1ng' {boolean - hidden} Optional. Disable certificate checking at SSL handshake (for dev - should be removed for prod).
*/
function ExchangeConnector(config) {

	var ewsCall = edge.func({
			source: path.resolve(__dirname, "./lib/ews_interop.csx"),
			references: [
				path.resolve(__dirname, './dotNet/Kidozen/Kidozen.EWS.dll')
			]
	});

	var configCmd = {
		opName: "configure",
		payload: {
			disableCertificateChecking: config.d1s4bl3CertificateCh3ck1ng || false,
			debuggingEnabled: config.debuggingEnabled || false
		}
	};

	var that = this;
	ewsCall(configCmd, function (err, result) {
		if (err) throw err;

		winston.debug("connector configured");

		function resolveImpersonation(credentials, ctx) {
			delete ctx.impersonate;
			
			if (config.impersonate && credentials._kidozen && credentials._kidozen.userClaims) {
				ctx.impersonate = credentials._kidozen.userClaims[config.impersonate.claim];

				if (config.impersonate.regex && config.impersonate.output) {
					ctx.impersonate = ctx.impersonate.replace(
						new RegExp(config.impersonate.regex), config.impersonate.output);
				}

				return "<< impersonating " + ctx.impersonate + " >>";
			} else {
				return "<< principal account >>";
			}
		}

		function createSession(credentials, cb) {
			if (!credentials.authCtx) {
				throw Error.create("authCtx not found or provided");
			}

			// build session
			var session = {
				url: config.url,
				authCtx: credentials.authCtx
			};

			// should append impersonation info?
			session.details = resolveImpersonation(credentials, session.authCtx);

			return cb(null, session);
		}

		var sessionHandler = new kidoConnector.Connector({
			config: config,
			credentialProps: ["authCtx", "_kidozen"],
			createSessionCb: createSession
		});

		that.authenticate = function (options, cb) {
			sessionHandler.getSession(options, function (err, session, auth) {
				if (err) return cb(err);

				cb(null, { auth: auth, details: session.details });
			});
		};

	    that.lookupMethod = function (name, cb) {
	    	cb(null, function(options, innerCb) {
				sessionHandler.getSession(options, function (err, session, auth) {
					if (err) return innerCb(err);

					// build command
					var cmd = {
						opName: name,
						payload: options
					};

					// extend payload with session
					cmd.payload._session = session;

					// execute command
					winston.debug("command to execute: ", cmd);

					ewsCall(cmd, function (err, result) {
						innerCb(err, result);
					});
				});
	    	});
	    };

		that.close = function(cb) {
			sessionHandler.close(cb);
		};
	});
};

module.exports = ExchangeConnector;