function validateZabbixParams(requiredParams, allParams) {
	requiredParams.forEach(function (field) {
		if (typeof allParams !== 'object' || typeof allParams[field] === 'undefined' || allParams[field] === '') {
			throw 'Required param is not set: ' + field + '.';
		}
	});
}

function OCI(service, action, params) {
	this.zabbixLogPrefix = '[ OCI ] [ ' + service + ' ] [ ' + action + ' ]';
	this.request = new HttpRequest();

	this.hash = function (string) {
		return sha256(string);
	};

	this.sign = function (string) {
		return sign('sha256', params['private_key'], string);
	};

	this.encode = function (hash) {
		const hexArr = hash.match(/.{1,2}/g);
		var uInt8Array = new Uint8Array(hexArr.length);
		hexArr.forEach(function (hex, idx) {
			uInt8Array[idx] = parseInt(hex, 16);
		});
		return btoa(uInt8Array);
	};

	this.getDate = function () {
		const weekdayShortList = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
		const monthShortList = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'];
		const today = new Date();
		return weekdayShortList[today.getUTCDay()] + ', ' + today.getUTCDate() + ' ' + monthShortList[today.getUTCMonth()] + ' ' + today.getUTCFullYear() + ' ' + today.getUTCHours() + ':' + today.getUTCMinutes() + ':' + today.getUTCSeconds() + ' GMT';
	};

	this.executeRequest = function (httpMethod, apiPath, apiParams, mql, namespace) {
		var headers = '(request-target) date host';
		const contentTypeHeader = 'content-type: application/json';
		const dateHeader = 'date: ' + this.getDate();
		const hostHeader = 'host: ' + params['api_host'];
		const requestTarget = '(request-target): ' + httpMethod + ' ' + apiPath + apiParams;
		var signingString = requestTarget + '\\n' + dateHeader + '\\n' + hostHeader;
		var reqHeaders = [contentTypeHeader, dateHeader];

		if (httpMethod === 'post') {
			var body = JSON.stringify({
				'namespace': namespace,
				'query': mql
			});
			headers = headers + ' x-content-sha256 content-type content-length';
			const bodyHeader = 'x-content-sha256: ' + this.encode(this.hash(body));
			const bodyLengthHeader = 'content-length: ' + body.length;
			signingString = signingString + '\\n' + bodyHeader + '\\n' + contentTypeHeader + '\\n' + bodyLengthHeader;
			reqHeaders.push(bodyHeader, bodyLengthHeader);
		}

		const signature = this.encode(this.sign(signingString));

		reqHeaders.push('Authorization: Signature version="1",keyId="' + params['tenancy_ocid'] + '/' + params['user_ocid'] + '/' + params['fingerprint'] + '",algorithm="rsa-sha256",headers="' + headers + '",signature="' + signature + '"');
		for (var header = 0, headerLength = reqHeaders.length; header < headerLength; header++) {
			this.request.addHeader(reqHeaders[header]);
		}

		if (params['http_proxy']) {
			this.request.setProxy(params['http_proxy']);
			Zabbix.log(4, this.zabbixLogPrefix + ' Using http proxy: ' + params['http_proxy']);
		}

		if (httpMethod === 'post') {
			var apiRateLimitExceeded = false;
			do {
				const response = this.request.post('https://' + params['api_host'] + apiPath + apiParams, body);

				try {
					if (JSON.parse(response)['code'] === 'TooManyRequests') {

						apiRateLimitExceeded = true;
						Zabbix.sleep(1000);
					} else {
						apiRateLimitExceeded = false;
					}
				} catch (error) {
					Zabbix.log(3, this.zabbixLogPrefix + ' Could not parse the response: ' + JSON.stringify(response));
					throw 'Could not parse the response. See logs for more information.';
				}
			} while (apiRateLimitExceeded);
		} else {
			const response = this.request.get('https://' + params['api_host'] + apiPath + apiParams);
		}

		this.request.clearHeader();

		if (this.request.getStatus() === parseInt(params['http_status_code'])) {
			return response;
		} else {
			Zabbix.log(3, this.zabbixLogPrefix + ' Unexpected HTTP response code: ' + this.request.getStatus());
			throw 'Unexpected HTTP response code: ' + this.request.getStatus();
		}
	};

	this.extractData = function (httpMethod, data, keys, compartment) {
		try {
			data = JSON.parse(data);
		} catch (error) {
			Zabbix.log(3, this.zabbixLogPrefix + ' Could not parse the received JSON object: ' + data);
			throw 'Could not parse received JSON object. See logs for more information.';
		}

		if (typeof keys == 'object') {
			var returnBuffer = [];
			for (var dataObj = 0, dataLength = data.length; dataObj < dataLength; dataObj++) {

				var objectBuffer = {};
				for (var key = 0, keysLength = keys.length; key < keysLength; key++) {
					if (data[dataObj][keys[key]] || data[dataObj][keys[key]] == null) {
						objectBuffer[keys[key].match(/^[a-z]+$|[A-Z][a-z]+$/)[0].toLowerCase()] = data[dataObj][keys[key]];
					} else {
						Zabbix.log(3, this.zabbixLogPrefix + ' Received an unexpected JSON object. Could not get value for key "' + keys[key] + '" in JSON: ' + JSON.stringify(data[dataObj]));
						throw 'Received an unexpected JSON object. See logs for more information.';
					}
				}
				if (typeof compartment != 'undefined' && compartment != '') objectBuffer['compartment'] = compartment;
				returnBuffer.push(objectBuffer);
			}
			return returnBuffer;
		}

		try {
			if (httpMethod === 'get') {
				return data[keys];
			} else {
				if (data.length === 0) {
					return 0;
				}
				data = data[0][keys];
				return data[data.length - 1]['value'];
			}
		} catch (error) {
			Zabbix.log(3, this.zabbixLogPrefix + ' Could not find key "' + keys + '" in JSON: ' + JSON.stringify(data));
			throw 'Could not find required key in JSON object. See logs for more information.';
		}
	};
}

function buildMql(id, metrics, defaultStatistic, resourceType) {
	resourceType = resourceType === '' || resourceType === undefined ? 'resourceId' : resourceType;
	this.query = '[' + params['req_interval'] + 'm]{' + resourceType + '=' + id + '}.';

	for (var i = 0, metricsLength = metrics.length; i < metricsLength; i++) {
		const metric = ((Array.isArray(metrics[i]) ? metrics[i] : [metrics[i], defaultStatistic]));
		metrics[i] = [metric[0], this.query + metric[1]];
	}
}


const params = JSON.parse(value);
validateZabbixParams(['tenancy_ocid', 'user_ocid', 'private_key', 'fingerprint', 'api_host', 'volume_id', 'http_status_code', 'req_interval', 'compartment_id'], params);
var oci = new OCI('Boot volume', 'Get metrics', params);

const metrics = [
	'VolumeReadThroughput',
	'VolumeWriteThroughput',
	'VolumeReadOps',
	'VolumeWriteOps',
	['VolumeThrottledIOs', 'sum'],
	'VolumeGuaranteedVPUsPerGB',
	'VolumeGuaranteedIOPS',
	'VolumeGuaranteedThroughput'
];
buildMql(params['volume_id'], metrics, 'mean');

var result = {};
for (var i = 0, metricsLength = metrics.length; i < metricsLength; i++) {
	result[metrics[i][0]] = oci.extractData('post', oci.executeRequest('post', '/20180401/metrics/actions/summarizeMetricsData', '?compartmentId=' + encodeURIComponent(params['compartment_id']), metrics[i][0] + metrics[i][1] + '()', 'oci_blockstore'), 'aggregatedDatapoints');
}
return JSON.stringify(result);