'use strict';
/**
 * This plugin accumulates data chunks from the client into an array
 * property on the request or response, concats them on end. Then  
 * transforms the request or response based on 'accept' or 'content-type' 
 * headers. 
 * 
 * If the HTTP verb is GET and the Accept type does not match the 
 * response type, the plugin will attempt to transform it (from 
 * xml to json or vice versa).
 *
 * If the HTTP verb is NOT GET then the content-type is used. If the
 * content-type is set to 'json', then an attempt is made to transform to
 * 'xml' and vice-versa.
 *
 * This plugin can be disabled by sending the 'x-apigee-json2xml' http
 * header.
 *
 * Users should be aware that buffering large requests or responses in
 * memory can cause Apigee Edge Microgateway to run out of memory under
 * high load or with a large number of concurrent requests. So this plugin
 * should only be used when it is known that request/response bodies are small.
 */

var debug = require('debug')('plugin:json2xml');
//library to convert json to xml
var js2xmlparser = require("js2xmlparser");
//library to convert xml to json
var parseString = require("xml2js").parseString;
var util = require("util");

module.exports.init = function (config, logger, stats) {

	//initialize the variables to false

	//variables to control whether request and/or response transformation should take place
	var requestXML = false;
	var requestJSON = false;
	var responseJSON = false;
	var responseXML = false;
	//use these variables to determine the content type of response sent by target server
	var responseIsXML = false;
	var responseIsJSON = false;
	//flag to control whether transfornation should take place
	var disable = false;

	//method to accumulate responses
	function accumulateResponse(res, data) {
		debug('plugin accumulateResponse');
		if (!res._chunks) res._chunks = [];
		res._chunks.push(data);
	}

	//method to accumulate requests
	function accumulateRequest(req, data) {
		debug('plugin accumulateRequest');
		if (disable) return;
		if (!req._chunks) req._chunks = [];
		req._chunks.push(data);
	}
	
	return {

		onrequest: function(req, res, next) {
			debug('plugin onrequest');
			var method  = req.method.toLowerCase();
			var acceptType = req.headers['accept'];
			var contentType = req.headers['content-type'];

			if (req.headers['x-apigee-json2xml-disable']) disable = true;

			debug("accept header: " + acceptType);
			debug("content-type header: " + contentType);

			//if plugin is disabled don't process headers.
			if (!disable) {
				if (method === "get" && acceptType.indexOf("application/xml") > -1) {
					responseXML = true;
				} else if (method === "get" && acceptType.indexOf("application/json") > -1) {
					responseJSON = true;
				} else if (method !== "get" && contentType.indexOf("application/json") > -1) {
					requestJSON = true;
					responseJSON = true;
				} else if (method !== "get" && contentType.indexOf("application/xml") > -1) {
					requestXML = true;
					responseXML = true;
				}
			}
			
			debug("requestJSON flag is " + requestJSON);
			debug("responseJSON flag is " + responseJSON);

			debug("requestXML flag is " + requestXML);
			debug("responseXML flag is " + responseXML);

			debug("plugin disabled: " + disable);

			next();
		},
		// indicates start of target response
		// response headers and status code should be available at this time
		onresponse: function(req, res, next) {
			debug('plugin onresponse');
			//nothing to do on response
			next();
		},
		//
		ondata_request: function(req, res, data, next) {
			debug('plugin ondata_request');
			if (data && data.length > 0 && disable == false) accumulateRequest(req, data);
			next(null, null);
		},
		//
		//
		ondata_response: function(req, res, data, next) {
			debug('plugin ondata_response');
			if (data && data.length > 0 && disable == false) accumulateResponse(res, data);
			next(null, null);
		},
		//
		onend_request: function(req, res, data, next) {
			debug('plugin onend_request');
			if (data && data.length > 0 && disable == false) accumulateRequest(res, data);
			var content = null;
			if(req._chunks && req._chunks.length) {
				content = Buffer.concat(req._chunks);
			}
			delete req._chunks;

			//if pugin is disabled, don't do anything
			if (!disable) {
				if (requestJSON) {
					//the request needs to be transformed to xml before sending to 
					//the target server.

					//set request content type.
					req.setHeader('Content-Type', 'application/xml');
					next(null, js2xmlparser.parse("Root",JSON.parse(content)));
				} else if (requestXML) {
					//set request content type.
					req.setHeader('Content-Type', 'application/json');
					parseString(content.toString(), function(err, js){
						if (err) next (err);
						next(null, JSON.stringify(js));
					});
				} else { //do nothing
					next(null, content);
				}
			} else {
				next(null, content);
			}
		},
		//
		onend_response: function(req, res, data, next) {
			debug('plugin onend_request');
			if (data && data.length > 0 && disable == false) accumulateResponse(res, data);

			var contentType = res.getHeader('content-type');
			if (contentType && contentType.indexOf("application/xml") > -1) {
				responseIsXML = true;
			} else if (contentType && contentType.indexOf("application/json") > -1) {
				responseIsJSON = true;
			}

			debug("responseIsJSON flag is " + responseIsJSON);
			debug("responseIsXML flag is" + responseIsXML);


			var content = null;
			if(res._chunks && res._chunks.length) {
				content = Buffer.concat(res._chunks);
			}
			delete res._chunks;

			//if disabled don't do anything.
			if (!disable) {
				if (responseXML && responseIsJSON) {
					res.setHeader('Content-Type', 'application/xml');
					next(null, js2xmlparser.parse("Root",JSON.parse(content)));
				} else if (responseJSON && responseIsXML) {
					res.setHeader('Content-Type', 'application/json');
					parseString(content.toString(), function(err, js){
						if (err) next (err);
						next(null, JSON.stringify(js));
					});
				} else {
					next(null, content);
				}
			} else {
				next(null, content);
			}
		}		
	};
}
