/* globals iframeAPI*/
const createLog = function(){
	"use strict";
	
	const div = document.getElementById("log");
	
	return function createLog(){
		const logDiv = document.createElement("div");
		logDiv.className = "log";
		div.appendChild(logDiv);
		return function createLine(str){
			const logLine = document.createElement("div");
			logLine.className = "logLine";
			logDiv.appendChild(logLine);
			logLine.textContent = str;
			return {
				update: function updateLine(str){
					str = str.replace("{old content}", logLine.textContent);
					logLine.textContent = str;
				},
				mark: function mark(marktext){
					logLine.classList.add("marked");
					logLine.title += marktext + "\n";
				}
			};
		};
	};
}();

const log = createLog();

const userAgentIsConsistent = document.getElementById("serverUserAgent").text === navigator.userAgent;
const consistencyLine = log("user agent equal between server and client: " + userAgentIsConsistent);
if (!userAgentIsConsistent){
	consistencyLine.mark();
}
const lines = {};

function processNavigatorObject(navigator, keys, name){
	"use strict";
	
	keys.sort().forEach(function(property){
		const value = navigator[property];
		if ((typeof value) === "string"){
			if (!lines[property]){
				lines[property] = {
					values: [],
					log: log(property + ": ")
				};
			}
			const propertyLine = lines[property];
			if (propertyLine.values.indexOf(value) === -1){
				propertyLine.log.update("{old content}" + (propertyLine.values.length? " | ": "") + value);
				propertyLine.values.push(value);
			}
			if (propertyLine.values[0] !== value){
				propertyLine.log.mark("failed test " + name);
			}
		}
	});
}

iframeAPI.forEachMethod(async function(windowToUse, name){
	"use strict";

	const navigator = windowToUse.navigator;
	const values = {};
	const keys = Object.keys(navigator.__proto__);
	let hasPropertyError = false;
	keys.forEach(function(property){
		try {
			const value = navigator[property];
			if ((typeof value) === "string"){
				values[property] = value;
			}
		}
		catch (error){
			hasPropertyError = true;
			console.warn(name, error);
		}
	});
	if (!hasPropertyError){
		const storage = await navigator.storage.estimate();
		values.storage_quota = storage.quota.toString(10);
		keys.push("storage_quota");
	}
	console.log(name, values);
	processNavigatorObject(values, keys, name);
});

function processWorkerNavigatorObject(data, name){
	"use strict";
	console.log(name, data);
	processNavigatorObject(data.values, Object.keys(data.values), name);
	if (data.nestedValues){
		processWorkerNavigatorObject(data.nestedValues, "nested " + name);
	}
}

const worker = new Worker("navigatorTestWorker.js", {name: "Worker"});
worker.addEventListener("message", function(event){
	"use strict";
	
	processWorkerNavigatorObject(event.data, "Worker");
	worker.terminate();
});

fetch("navigatorTestWorker.js").then(function(response){
	"use strict";
	
	return response.text();
}).then(function(code){
	"use strict";
	
	const blob = new Blob([code], {type: "text/javascript"});
	const blobWorker = new Worker(URL.createObjectURL(blob), {name: "BlobWorker"});
	blobWorker.addEventListener("message", function(event){
		processWorkerNavigatorObject(event.data, "BlobWorker");
		blobWorker.terminate();
	});
	
	return blobWorker;
}).catch(function(error){
	"use strict";
	
	console.error("Unable to create BlobWorker:", error);
});

const sharedWorker = new SharedWorker("navigatorTestWorker.js", {name: "SharedWorker"});
sharedWorker.port.addEventListener("message", function(event){
	"use strict";
	
	processWorkerNavigatorObject(event.data, "SharedWorker");
	sharedWorker.port.close();
});
sharedWorker.port.start();

navigator.serviceWorker.register("navigatorTestWorker.js").then(function(registration){
	"use strict";
	
	const worker = (registration.active || registration.waiting || registration.installing);
	navigator.serviceWorker.addEventListener("message", function(event){
		processWorkerNavigatorObject(event.data, "ServiceWorker");
		registration.unregister();
	});
	if (worker.state !== "activated"){
		worker.addEventListener("statechange", function(){
			if (worker.state === "activated"){
				worker.postMessage("send");
			}
		});
	}
	else {
		worker.postMessage("send");
	}
	return registration;
}).catch(function(error){
	"use strict";
	console.error("Unable to register service worker:", error);
});
