<script>
	// get the data from the JSON Webservices feed in +page.js
	export let data;
	const { webservices } = data;

	//import References from '../references.js';
	import { colours } from '../colours.js';
	import { processData } from '../lib/processData.svelte';

	console.log('colours: ', colours);



	//    console.log(technologies);
	// return true if a tech object includes valid instances
	function hasInstances(tech) {
		if (
			tech.hasOwnProperty('instances') &&
			tech.instances.constructor === Array &&
			tech.instances.length
		)
			return true;
		return false;
	}

	// return an array of keys from an object
	function getKeys(ob) {
		let keys = [];
		for (let key in ob) {
			//keys.push(key.replace(/ /g, '\u00a0'));
			keys.push(key);
		}
		return keys;
	}

	// get intersection: ref https://bobbyhadz.com/blog/javascript-get-intersection-of-two-arrays
	function getIntersection(a, b) {
		const set1 = new Set(a);
		const set2 = new Set(b);

		const intersection = [...set1].filter((element) => set2.has(element));

		return intersection;
	}

	// combine an array of terms into a sentence with proper Oxford commas, dealing with the special cases
	// of one or two elements.
	function toOxfordCommaString(arr) {
		if (arr.length == 1) return arr;
		if (arr.length == 2) return arr.join(' and ');
		else {
			var last = arr.pop();
			return arr.join(', ') + ', and ' + last;
		}
	}

	// return a singular or plural term depending on the value of 'count'
	function pluraliser(singular, plural, count) {
		if (count > 1) return plural;
		return singular;
	}

	// assign colours from a set of differentiated colours to a list of tags...
	// this one is for 'hosts'
	function hostColours(host_list, colours, hosts) {
		let host_array = {};
		let i = 0;

		//console.log('hosts:', hosts);

		host_list.forEach(function (host) {
			//console.log(host);
			if (hosts[host].hasOwnProperty('domain') && hosts[host].hasOwnProperty('affiliation')) {
				host_array[host] = {
					colour: colours[i++],
					domain: hosts[host].domain,
					affiliation: hosts[host].affiliation
				};
			}
		});
		return host_array;
	}

	// assign colours from a set of differentiated colours to a list of tags...
	// this one is for 'affiliates'
	function affiliateColours(affiliate_list, colours, affiliates) {
		let affiliate_result = {};
		let i = 0;

		//console.log('affiliates:', affiliates);
		console.log('affiliate_list:', affiliate_list);

		for (const affiliate of affiliate_list) {
			//console.log('affiliate:', affiliate);
			if (
				affiliates[affiliate].hasOwnProperty('name') &&
				affiliates[affiliate].hasOwnProperty('website')
			) {
				affiliate_result[affiliate] = {
					colour: colours[i++],
					name: affiliates[affiliate].name,
					website: affiliates[affiliate].website
				};
			}
		}
		return affiliate_result;
	}

	// sort technologies alphabetically by name
	function sortTechnologies(technologies) {
		return technologies.sort((a, b) => a.name.localeCompare(b.name));
	}

	// generic function to find the intersection of two arrays
	// approach ref: https://bobbyhadz.com/blog/javascript-get-intersection-of-two-arrays
	function inCommon(a, b) {
		const set1 = new Set(a);
		const set2 = new Set(b);

		const intersection = [...set1].filter((element) => set2.has(element));
		console.log('intersection = ', intersection);
		return intersection;
	}

	// filter technologies based on a list of Categories
	function filterTechnologiesByCategoryList(technologies, list) {
		console.log('looking for tech in categories: ', list);
		const included = [];
		technologies.forEach(function (tech, index) {
			//console.log('tech(' + index + '): ', tech);
			if (hasInstances(tech)) {
				const intersection = inCommon(tech.categories, list);
				console.log('categories: ', tech.categories);
				//console.log('list: ', list);
				console.log('intersection: ', intersection);
				if (intersection && intersection.constructor === Array) {
					//console.log('intersection length: '. intersection.length);
					if (intersection.length > 0) {
						console.log('including tech: ', tech);
						included.push(tech);
					}
				} else {
					console.log('intersection not array');
				}
			}
		});
		console.log('found ' + included.length + ' technologies.');
		return included;
	}

	const results = processData(webservices);
	//console.log('results: ', results);

	//const technologies = webservices.technologies;
	//console.log(technologies);

	const category_list = getKeys(results.tech_lists.category_list).sort();
	const analogue_list = getKeys(results.tech_lists.analogue_list).sort();
	const license_list = getKeys(results.tech_lists.license_list).sort();
	const status_list = getKeys(results.instance_lists.status_list).sort();
	const affiliate_list = getKeys(results.instance_lists.affiliate_list).sort();
	const host_list = getKeys(results.instance_lists.host_list).sort();

	const hosts = results.hosts;
	//console.log('host_data: ', results.hosts);
	const affiliates = results.affiliates;
	//console.log('affiliate_data: ', results.affiliates);
	const host_colours = hostColours(host_list, colours, hosts);
	//console.log('host_colours:', host_colours);
	colours.sort();
	const affiliate_colours = affiliateColours(affiliate_list, colours, affiliates);
	//console.log('affiliate_colours:',affiliate_colours);

	//console.log('categories array: ', results.tech_tags.categories);
	//console.log('categories keys: ', categories);

	console.log('category_list: ', category_list);
	//console.log('analogue_list: ', analogue_list);
	console.log('license_list: ', license_list);
	console.log('status_list: ', status_list);
	console.log('affiliate_list: ', affiliate_list);
	console.log('hosts_list: ', host_list);

	// filter technolologies based on a subset of categories
	const full_category_list = [
		'App Ecosystem',
		'Application Design',
		'Asset Management',
		'Association Management',
		'Association Management System',
		'Blog Syndication',
		'Book Reviews',
		'Calendar',
		'Collaborative',
		'Collaborative Markdown Editing',
		'Collaborative Wiki',
		'Content Management Systems',
		'Digital Media Sales',
		'Document Management',
		'Email Marketing Automation',
		'Email Services',
		'Enterprise Resource Planning',
		'Event Management',
		'Facial Recognition',
		'Facility Booking',
		'Federated Messaging',
		'Fediverse',
		'File Synchronisation',
		'Forum',
		'Framasoft',
		'Home Automation',
		'Home Security',
		'Image Backup',
		'Image Gallery',
		'Kanban Project Management',
		'Learning Management System',
		'Link Ranking',
		'Link Sharing',
		'Link Shortener',
		'Membership Management',
		'Messaging Cache',
		'Micro-blogging',
		'Multi-Domain Server',
		'Multimedia',
		'Music Discovery',
		'Music Streaming',
		'Network Infrastructure Monitoring',
		'Newsletters',
		'Online Forms',
		'Password Manager',
		'Photos',
		'Portfolio Management',
		'Privacy',
		'Productivity',
		'Reading List',
		'Remote Desktop Sharing',
		'Remote Incremental Encrypted System Backups',
		'Reverse Proxy',
		'Rich Messaging Client',
		'Rich Messaging Server',
		'Scheduling',
		'Server Monitoring',
		'Share Secrets Management',
		'Single Sign-On',
		'Social Bookmarking',
		'Social Media',
		'Software Development Forge',
		'Software Interface Designer',
		'Streaming',
		'Surveys',
		'TURN/STUN Server',
		'Video',
		'Video Conferencing',
		'Video Surveillance',
		'Visualisation of Time Series Data',
		'Webmail',
		'Webserver',
		'Website Analytics'
	];
	const copyleft_list = [
		'AGPL-3',
		'AGPL-3+',
		'GPL',
		'GPL-2',
		'GPL-2+',
		'GPL-3',
		'GPL-3+',
		'LGPL-3'
	];
	const category_filter_list = [
		'App Ecosystem',
		'Application Design',
		'Asset Management',
		'Association Management',
		'Association Management System',
		'Blog Syndication',
		'Book Reviews',
		'Calendar',
		'Collaborative',
		'Collaborative Markdown Editing',
		'Collaborative Wiki',
		'Content Management Systems',
		'Digital Media Sales',
		'Document Management',
		'Email Marketing Automation',
		'Email Services',
		'Enterprise Resource Planning',
		'Event Management',
		'Facial Recognition',
		'Facility Booking',
		'Federated Messaging',
		'Fediverse',
		'File Synchronisation',
		'Forum',
		'Framasoft',
		'Home Automation',
		'Home Security',
		'Image Backup',
		'Image Gallery',
		'Kanban Project Management',
		'Learning Management System',
		'Link Ranking',
		'Link Sharing',
		'Link Shortener',
		'Membership Management',
		'Messaging Cache',
		'Micro-blogging',
		'Multi-Domain Server',
		'Multimedia',
		'Music Discovery',
		'Music Streaming',
		'Network Infrastructure Monitoring',
		'Newsletters',
		'Online Forms',
		'Password Manager',
		'Photos',
		'Portfolio Management',
		'Privacy',
		'Productivity',
		'Reading List',
		'Remote Desktop Sharing',
		'Remote Incremental Encrypted System Backups',
		'Reverse Proxy',
		'Rich Messaging Client',
		'Rich Messaging Server',
		'Scheduling',
		'Server Monitoring',
		'Share Secrets Management',
		'Single Sign-On',
		'Social Bookmarking',
		'Social Media',
		'Software Development Forge',
		'Software Interface Designer',
		'Streaming',
		'Surveys',
		'TURN/STUN Server',
		'Video',
		'Video Conferencing',
		'Video Surveillance',
		'Visualisation of Time Series Data',
		'Webmail',
		'Webserver',
		'Website Analytics'
	];

	const filtered_technologies = filterTechnologiesByCategoryList(
		results.active_services,
		full_category_list,
//		category_filter_list
	);
	const technologies = sortTechnologies(filtered_technologies);
</script>

<div class="webservices">
	<h1>Web Services</h1>

	<div class="introduction">
		<p>
			This sites exists to provide an 'always-up-to-date', in-depth description of the <a
				href="https://tech.oeru.org/foss-libresoftware-its-about-clarity-and-values"
				title="What do I mean by 'libre' software?">libre software</a> web services <a href="https://davelane.nz" title="Who is this Dave Lane character?">I</a> have set
			up and maintain.
		</p>
	</div>
	<div class="summary">
		<ul>
			<li>Total number of services: {results.total_instances}</li>
		</ul>
	</div>
	<div class="filters">
		<div class="tag-list tech">
			<div class="tags tech categories">
				Categories<br/> {#each category_list as category}<span class="tag category" style="white-space: nowrap; word-break: normal;">{category} xo</span><wbr/>{/each}
			</div>
			<!--<div class="tags tech analogues">{#each analogues as analogue}<span class="tag analogue">{analogue}</span> {/each}</div>-->
			<div class="tags tech licenses">
				Licenses<br/> {#each license_list as license}<span class="tag license">{license} xo</span><wbr/>{/each}
			</div>
		</div>
		<div class="tag-list instance">
			<div class="tags instance statuses">
				Statuses<br/> {#each status_list as status}<span class="tag status">{status} xo</span><wbr/>{/each}
			</div>
			<div class="tags instance affiliates">
				Affiliates<br/> {#each affiliate_list as affiliate}<span class="tag affiliate"><span class="marker circle" style="background-color: {affiliate_colours[affiliate].colour}"></span> {affiliate} xo</span><wbr/>{/each}
			</div>
			<div class="tags instance hosts">
				Hosts<br/> {#each host_list as host}<span class="tag host"><span class="marker square" style="background-color:  {host_colours[host].colour}"></span> {host} xo</span><wbr/>{/each}
			</div>
		</div>
	</div>
	<div class="tiles">
		{#each filtered_technologies as technology}
			<div class="tile technology">
				<div class="links">
					{#if technology.repository}<span class="repository"
							><a
								href={technology.repository}
								title="The source code repository for {technology.name}">R</a
							></span
						>{/if}
					{#if technology.wikipedia}<span class="wikipedia"
							><a href={technology.wikipedia} title="Wikipedia Page for {technology.name}">W</a
							></span
						>{/if}
				</div>
				<h2><a href={technology.website}>{technology.name}</a></h2>
				{#if technology.license}<p
						class="license"
						title="The libre license for this project is {technology.license}"
					>
						License: <span class="value">{technology.license}</span>
					</p>{/if}
				{#if technology.categories}<p class="categories">
						{pluraliser('Category', 'Categories', technology.categories.length)}:
						<span class="value">{toOxfordCommaString(technology.categories)}</span>
					</p>{/if}
				{#if technology.analogues}<p class="analogues">
						Alternative to <span class="value">{toOxfordCommaString(technology.analogues)}</span>
					</p>{/if}
				<p class="description">
					{technology.description}{#if technology.extended_description}<span
							title={technology.extended_description}>i</span
						>{/if}
				</p>
				{#if hasInstances(technology)}
					<div class="instances">
						<p>
							{#each technology.instances as instance}
								<a
									href="https://{instance.domain}"
									title="{technology.name} instance {instance.domain} hosted on '{instance.host}' by {instance.affiliation}"
									><span
										class="marker circle"
										style="background-color: {affiliate_colours[instance.affiliation].colour}"
									></span></a
								>{/each}
						</p>
					</div>
				{:else}
					<div class="instances">Nothing here yet...</div>
				{/if}
			</div>
		{/each}
	</div>
</div>

<style>
	.webservices {
		display: grid;
		margin: 0 auto 3em auto;
		padding: 0;
	}
	.summary {
	    background-color: #ccc;
	    display: block;
	}
	.filters {
		/*background-color: #f1ff94;
        padding: 0.5em;
        border: 3px solid #cbea77;
        margin: 1em 0;*/
		margin-bottom: 1em;
	}
	.filters .tags {
		/*padding: 0.5em;*/
		margin: 1em 0;
		display: block;
	}
	.tag-list {
/*		white-space: normal;
		word-break: normal;
		display: inline;*/
	}
	.tags {
/*		white-space: normal;
		word-break: normal;
	    display: inline;*/
	}
	.tag {
		font-size: 80%;
		margin-right: 0.5em;
		line-height: 2.5;
		padding: 6px 8px;
		border-radius: 14px;
		white-space: nowrap;
		word-break: normal;
		box-shadow: 3px 3px 3px #71ba71;
	}
	.tag:hover { box-shadow: 4px 4px 3px #71ba71;}
	.tag.category {
		background-color: #9aa34d;
		color: #fff;
	}
	.tag.license {
		background-color: #6498a3;
		color: #fff;
	}
	.tag.status {
		background-color: #a369a2;
		color: #fff;
	}
	.tag.affiliate {
		background-color: #fff;
		color: #000;
	}
	.tag.host {
		background-color: #fff;
		color: #000;
	}
	.tiles {
		display: grid;
		grid-gap: 15px;
		grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
	}
	/* flip card stuff: https://www.w3schools.com/howto/howto_css_flip_card.asp */
	.tile {
		height: 515px;
		min-width: 270px;
		max-width: 330px;
		/*width: 290px;*/
		overflow: hidden;
		box-sizing: border-box;
		box-shadow: 5px 5px 3px #71ba71;
		border: solid 3px #1e6831;
		text-overflow: ellipsis;
		overflow: hidden;
		position: relative;
		background-color: #eee;
	}
	.tile .links {
		position: absolute;
		top: 0;
		right: 0;
		padding: 2px 6px;
		font-size: 90%;
	}
	.tile:hover {
		box-shadow: 10px 10px 6px #71ba71;
	}
	.tile .links h2 a {
		color: #e6c4fc;
	}
	.tile .links a:visited {
		color: #ced0ff;
	}
	.tile .links a:hover,
	.tile:hover h2 a {
		color: #fff !important;
	}
	.tile h2 {
		background-color: #999;
		text-align: center;
		padding: 0.5em;
		margin: 0;
	}
	.tile h2 a {
		color: #e6c4fc;
	}
	.tile h2 a:visited {
		color: #ced0ff;
	}
	.tile h2 a:hover {
		color: #fff;
	}
	.tile .description {
		height: 260px;
		text-overflow: ellipsis;
		overflow: hidden;
	}
	.tile p {
		padding: 0 1em 0.2em 1em;
		font-size: 80%;
		color: #555;
	}
	.instances {
		background-color: #ddd;
		position: absolute;
		bottom: 0;
		height: 3em;
		width: 100%;
	}
	.instances .marker {
		margin-right: 3px;
	}
	.webservices li {
		list-style-type: none;
	}
	.value {
		font-weight: bold;
		color: #000;
	}
	.marker {
		vertical-align: middle;
	}
	.circle {
		height: 20px;
		width: 20px;
		background-color: #555;
		border-radius: 50%;
		display: inline-block;
	}
	.square {
		height: 20px;
		width: 20px;
		background-color: #555;
		display: inline-block;
	}
</style>
