/**
 * Jenkins JS Modules common utility functions
 */
import $ from 'jquery';
import wh from 'window-handle';
import Handlebars from 'handlebars';

var debug = false;
var jenkins = {};

// gets the base Jenkins URL including context path
jenkins.baseUrl = function() {
	var u = $('head').attr('data-rooturl');
	if(!u) {
		u = '';
	}
	return u;
};

// awful hack to get around JSONifying things with Prototype taking over wrong. ugh. Prototype is the worst.
jenkins.stringify = function(o) {
	if(Array.prototype.toJSON) { // Prototype f's this up something bad
		var protoJSON = {
			a: Array.prototype.toJSON,
			o: Object.prototype.toJSON,
			h: Hash.prototype.toJSON,
			s: String.prototype.toJSON
		};
		try {
			delete Array.prototype.toJSON;
		delete Object.prototype.toJSON;
			delete Hash.prototype.toJSON;
			delete String.prototype.toJSON;

		return JSON.stringify(o);
		}
		finally {
		if(protoJSON.a) {
			Array.prototype.toJSON = protoJSON.a;
		}
		if(protoJSON.o) {
			Object.prototype.toJSON = protoJSON.o;
		}
		if(protoJSON.h) {
			Hash.prototype.toJSON = protoJSON.h;
		}
		if(protoJSON.s) {
			String.prototype.toJSON = protoJSON.s;
		}
		}
	}
	else {
		return JSON.stringify(o);
	}
};

/**
 * redirect
 */
jenkins.goTo = function(url) {
	wh.getWindow().location.replace(jenkins.baseUrl() + url);
};

/**
 * Jenkins AJAX GET callback.
 * If last parameter is an object, will be extended to jQuery options (e.g. pass { error: function() ... } to handle errors)
 */
jenkins.get = function(url, success, options) {
	if(debug) {
		console.log('get: ' + url);
	}
	var args = {
		url: jenkins.baseUrl() + url,
		type: 'GET',
		cache: false,
		dataType: 'json',
		success: success
	};
	if(options instanceof Object) {
		$.extend(args, options);
	}
	$.ajax(args);
};

/**
 * Jenkins AJAX POST callback, formats data as a JSON object post (note: works around prototype.js ugliness using stringify() above)
 * If last parameter is an object, will be extended to jQuery options (e.g. pass { error: function() ... } to handle errors)
 */
jenkins.post = function(url, data, success, options) {
	if(debug) {
		console.log('post: ' + url);
	}

	// handle crumbs
	var headers = {};
	var wnd = wh.getWindow();
	var crumb;
	if('crumb' in options) {
		crumb = options.crumb;
	}
	else if('crumb' in wnd) {
		crumb = wnd.crumb;
	}
	
	if(crumb) {
		headers[crumb.fieldName] = crumb.value;
	}
	
	var formBody = data;
	if(formBody instanceof Object) {
		if(crumb) {
			formBody = $.extend({}, formBody);
			formBody[crumb.fieldName] = crumb.value;
		}
		formBody = jenkins.stringify(formBody);
	}
	
	var args = {
		url: jenkins.baseUrl() + url,
		type: 'POST',
		cache: false,
		dataType: 'json',
		data: formBody,
		contentType: "application/json",
		success: success,
		headers: headers
	};
	if(options instanceof Object) {
		$.extend(args, options);
	}
	$.ajax(args);
};

/**
 *  handlebars setup, done for backwards compatibility because some plugins depend on it
 */
jenkins.initHandlebars = function() {
	return Handlebars;
}

/**
 * Load translations for the given bundle ID, provide the message object to the handler.
 * Optional error handler as the last argument.
 */
jenkins.loadTranslations = function(bundleName, handler, onError) {
	jenkins.get('/i18n/resourceBundle?baseName='  +bundleName, function(res) {
		if(res.status !== 'ok') {
			if(onError) {
				onError(res.message);
			}
			throw 'Unable to load localization data: ' + res.message;
		}

		var translations = res.data;

		/* globals Proxy: true */
		if('undefined' !== typeof Proxy) {
			translations = new Proxy(translations, {
				get: function(target, property) {
					if(property in target) {
						return target[property];
					}
					if(debug) {
						console.log('"' + property + '" not found in translation bundle.');
					}
					return property;
				}
			});
		}

		handler(translations);
	});
};

/**
 * Runs a connectivity test, calls handler with a boolean whether there is sufficient connectivity to the internet
 */
jenkins.testConnectivity = function(siteId, handler) {
	// check the connectivity api
	var testConnectivity = function() {
		jenkins.get('/updateCenter/connectionStatus?siteId=' + siteId, function(response) {
			if(response.status !== 'ok') {
				handler(false, true, response.message);
			}
			
			// Define statuses, which need additional check iteration via async job on the Jenkins master
			// Statuses like "OK" or "SKIPPED" are considered as fine.
			var uncheckedStatuses = ['PRECHECK', 'CHECKING', 'UNCHECKED'];
			if(uncheckedStatuses.indexOf(response.data.updatesite) >= 0  || uncheckedStatuses.indexOf(response.data.internet) >= 0) {
				setTimeout(testConnectivity, 100);
			}
			else {
				// Update site should be always reachable, but we do not require the internet connection
				// if it's explicitly skipped by the update center
				if(response.status !== 'ok' || response.data.updatesite !== 'OK' ||
							(response.data.internet !== 'OK' && response.data.internet !== 'SKIPPED')) {
					// no connectivity, but not fatal
					handler(false, false);
				}
				else {
					handler(true);
				}
			}
		}, { error: function(xhr, textStatus, errorThrown) {
                 if (xhr.status === 403) {
                     jenkins.goTo('/login');
                 } else {
                     handler.call({ isError: true, errorMessage: errorThrown });
                 }
               }
             });
	};
	testConnectivity();
};

/**
 * gets the window containing a form, taking in to account top-level iframes
 */
jenkins.getWindow = function($form) {
	$form = $($form);
	var wnd = wh.getWindow();
	$(top.document).find('iframe').each(function() {
		var windowFrame = this.contentWindow;
		var $f = $(this).contents().find('form');
		$f.each(function() {
			if($form[0] === this) {
				wnd = windowFrame;
			}
		});
	});
	return wnd;
};

/**
 * Builds a stapler form post
 */
jenkins.buildFormPost = function($form) {
	$form = $($form);
	var wnd = jenkins.getWindow($form);
	var form = $form[0];
	if(wnd.buildFormTree(form)) {
		return $form.serialize() + "&" + $.param({
			'core:apply': '',
			'Submit': 'Save',
			'json': $form.find('input[name=json]').val()
		});
	}
	return '';
};

/**
 * Gets the crumb, if crumbs are enabled
 */
jenkins.getFormCrumb = function($form) {
	$form = $($form);
	var wnd = jenkins.getWindow($form);
	return wnd.crumb;
};

/**
 * Jenkins Stapler JSON POST callback
 * If last parameter is an object, will be extended to jQuery options (e.g. pass { error: function() ... } to handle errors)
 */
jenkins.staplerPost = function(url, $form, success, options) {
	$form = $($form);
	var postBody = jenkins.buildFormPost($form);
	var crumb = jenkins.getFormCrumb($form);
	jenkins.post(
		url,
		postBody,
		success, $.extend({
			processData: false,
			contentType: 'application/x-www-form-urlencoded',
			crumb: crumb
		}, options));
};

export default jenkins;
