'use strict';

/** 
 * @module @wider/utils_where-am-i
 * 
 * @copyright Copyright (C) 1985..2021 Martin Baker -YDR. {@link https://y-d-r.co.uk}
 * @author Martin W Baker
 * @license ISC 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.
 */

const $moduleName = "@wider/utils_where-am-i";
const $objectName = "whereAmI";

/* jshint -W117*/

/**
 * The structure of the object returned by this module.
 * 
 * In the event that any of these properties cannot be determined, they will contain the value `unknown`
 * 
 * Please feed back to us additional environments or values we might also detect
 * @typedef {Object} whereAmI_result
 * @property {RegExp} _genres a regular expression that returns true when testing against a string that contains any one of the possible values of `genre`
 * @property {NCName} genre the genre or general category of processor engine of the environment on which the code is running.  This version will contain one of the following `["unknown", "server", "browser", "script"]`
 * @property {NCName} engine the engine that is running the code at the moment.  This may contain various values as reported by the engine about itself. Some values include `["unknown", "node", "Firefox", "Edg", "Chrome", "Trident","WScript", "aspClassic"]`
 * @property {String} version the version of the engine in the format that is used by that engine
 * @property {NCName} [os the name of the operating system coerced to lower case. Some values include `["unknown", "linux", "sunos", "openbsd", "freebsd", "darwin", "aix", "win16", "win32", "win64"]`.  
 *     Important - nodejs reports `win32` even when on a 64 bit machine with 64 bit os.  The value responded here is the true version of the operating system so on node on a 64 window machine AND with 64 bit os you get ***win64*** just as you would on a windows script running on the same machine
 * @property {String} computerName the name of the computer on which your code is running.  This is not discoverable in all environments
 */

/**
 *  Provide a standard json object response that indicates to the caller the nature of the environment on which it is running
 * 
 * This can be required or imported and the result is a plain javascript object.
 * 
 * See [Examples](/./tutorial-Examples.html) for the JSON objects returned.
 * @returns {whereAmI_result} 
 */
function whereAmI() {
	function wshell() {
		var hell = new ActiveXObject("WScript.Shell");
		var sys = hell.Environment("SYSTEM");

		return {
			os: "win" + sys("PROCESSOR_ARCHITECTURE").replace(/[a-z]+/i, ""),
			computerName: hell.Environment("COMPUTERNAME")
		};
	}

	var where;

	if ((typeof process === "object") && (process.release && process.release.name === "node")) {
		var platform = process.platform.toLowerCase();
		where = {
			genre: "server",
			engine: "node",
			version: process.version,
			computerName: process.env.COMPUTERNAME,
			os: /^win/.test(platform) && process.env.ProgramW6432 ? "win64" : platform
		};
	}

	/* jshint -W117*/
	else if (typeof Window === "function" && window.document) {
		var engine;
		var version;

		try {
			for (var key in $.browser) {
				if (Object.hasOwnProperty.call($.browser, key)) {
					var element = $.browser[key];
					if (typeof element === "boolean" && key != "webkit") {
						engine = key;
						version = $.browser.version;
						break;
					}
				}
			}
		} catch (err) {}

		if (!engine) {
			engine = (navigator.mozGetUserMedia) ?
				"Firefox" :
				window.Bing ?
				"Edg" :
				/Google/.test(navigator.vendor) ?
				"Chrome" :
				/Trident/.test(navigator.userAGent) ?
				"Trident" : navigator.vendor.split(/ /)[0];

			var items = window.navigator.userAgent.replace(/(\w+\/)/g, "\u400d$1").split(/\u400d/);

			for (var index = 0; index < items.length; index++) {
				var item = items[index];
				details = items.split(/[ \/]/);
				if (details[0] === engine) {
					version = item.split(/[ \/]/)[1];
					return true;
				}
			}
		}

		where = {
			genre: "browser",
			os: (window.navigator.platform || "").toLowerCase(),
			engine: engine || window.navigator.userAgent.toLowerCase(),
			version: version || "unknown"
		};
	} else if (typeof WScript === "object") {

		wshShell = new ActiveXObject("WScript.Shell");

		where = Object.assign(
			wshell(), {
				genre: "script",
				engine: "WScript",
				version: WScript.Version
			});

	} else if (typeof Server === "object") {
		var serverSoftware = Request.ServerVariables("SERVER_SOFTWARE") + "";

		where = Object.assign(
			wshell(), {
				genre: "server",
				engine: serverSoftware.split(/\//)[0].split(/-/)[1] + "/aspClassic",
				version: serverSoftware.split(/\//)[1]
			});
	}

	var unknown = "unknown";
	return Object.assign({
		$moduleName: $moduleName,
		$objectName: $objectName,
		"_genres": /unknown|server|browser|script/,
		"genre": unknown,
		"engine": unknown,
		"version": unknown,
		"computerName": unknown,
		"os": unknown
	}, where);
}

module.exports = whereAmI();
/* jshint -W030 */