<script>
import { onMount, tick } from "svelte";
import Modal from "../util/Modal.svelte";
import PixeldrainLogo from "../util/PixeldrainLogo.svelte";
import DetailsWindow from "./DetailsWindow.svelte";
import FilePreview from "./FilePreview.svelte";
import ListNavigator from "./ListNavigator.svelte";
import FileStats from "./FileStats.svelte";
import { copy_text } from "../util/Util.svelte";
import EditWindow from "./EditWindow.svelte";
import EmbedWindow from "./EmbedWindow.svelte";
import ReportWindow from "./ReportWindow.svelte";
import IntroPopup from "./IntroPopup.svelte";
import AdHead from "./AdHead.svelte";
import AdLeaderboard from "./AdLeaderboard.svelte";
import AdSkyscraper from "./AdSkyscraper.svelte";
import Sharebar from "./Sharebar.svelte";
import GalleryView from "./GalleryView.svelte";
import Spinner from "../util/Spinner.svelte";

const file_struct = {
	id: "",
	name: "",
	size: 0,
	bandwidth_used: 0,
	bandwidth_used_paid: 0,
	downloads: 0,
	views: 0,
	mime_type: "",
	availability: "",
	abuse_type: "",
	show_ads: false,
	can_edit: false,
	get_href: "",
	info_href: "",
	download_href: "",
	icon_href: "",
}
const list_struct = {
	id: "",
	title: "",
	files: [],
	download_href: "",
	info_href: "",
	can_edit: false,
}

let loading = true
let embedded = false
let view_token = ""
let ads_enabled = false

let view = "" // file or gallery
let file = file_struct
let list = list_struct
let is_list = false

let button_home
let list_navigator
let list_shuffle = false
let toggle_shuffle = () => {
	list_shuffle = !list_shuffle
}

let sharebar
let sharebar_visible = false
let toggle_sharebar = () => {
	if (navigator.share) {
		let name = file.name
		if (is_list) {
			name = list.title
		}

		navigator.share({
			title: name,
			text: "I would like to share '" + name + "' with you",
			url: window.location.href
		})
		return
	}

	sharebar_visible = !sharebar_visible
	if (sharebar_visible) {
		sharebar.show()
	} else {
		sharebar.hide()
	}
}
let toolbar_visible = (window.innerWidth > 600)
let toolbar_toggle = () => {
	toolbar_visible = !toolbar_visible
	if (!toolbar_visible && sharebar_visible) {
		toggle_sharebar()
	}
}
let details_window
let details_visible = false
let qr_window
let qr_visible = false
let edit_window
let edit_visible = false
let report_window
let report_visible = false
let embed_window
let embed_visible = false
let skyscraper_visible = false

onMount(() => {
	let viewer_data = window.viewer_data
	embedded = viewer_data.embedded

	if (embedded) {
		toolbar_visible = false
	}

	view_token = viewer_data.view_token

	if (viewer_data.type === "list") {
		open_list(viewer_data.api_response)
	} else {
		list.files = [viewer_data.api_response]
		open_file_index(0)
	}

	ads_enabled = list.files[0].show_ads
	loading = false
})
const reload = async () => {
	loading = true
	if (is_list) {
		try {
			const resp = await fetch(list.info_href);
			if (resp.status >= 400) {
				throw (await resp.json()).message
			}

			open_list(await resp.json())
		} catch (err) {
			alert(err)
		}
	} else {
		try {
			const resp = await fetch(file.info_href);
			if (resp.status >= 400) {
				throw (await resp.json()).message
			}

			list.files = [await resp.json()]
			open_file_index(0)
		} catch (err) {
			alert(err)
		}
	}
	loading = false
}

const open_list = async l => {
	l.download_href = window.api_endpoint+"/list/"+l.id+"/zip"
	l.info_href = window.api_endpoint+"/list/"+l.id
	l.files.forEach(f => {
		file_set_href(f)
	})

	list = l

	// Setting is_list to true activates the ListNavgator, which makes sure the
	// correct file is opened
	is_list = true

	// Skip to the file defined in the link hash
	let matches = location.hash.match(new RegExp('item=([^&]*)'))
	let hashID = parseInt(matches ? matches[1] : null)
	if (Number.isInteger(hashID)) {
		// The URL contains an item number. Navigate to that item
		view = "file"
		open_file_index(parseInt(hashID))
	} else {
		view = "gallery"
	}
}
const open_file_index = async index => {
	if (index >= list.files.length) {
		index = 0
	} else if (index < 0) {
		index = list.files.length - 1
	}
	console.debug("received request to open file", index)

	file_set_href(list.files[index])
	file = list.files[index]
	view = "file"

	if (is_list) {
		// Wait for the ListNavigator to render
		await tick()

		// Update the URL
		location.replace("#item=" + index)
		list_navigator.set_item(index)
	}

	// Register a file view
	fetch(window.api_endpoint + "/file/" + file.id + "/view", {
		method: "POST",
		headers: { "Content-Type": "application/x-www-form-urlencoded" },
		body: "token=" + view_token
	})
}
const file_set_href = f => {
	f.get_href = window.api_endpoint+"/file/"+f.id
	f.info_href = window.api_endpoint+"/file/"+f.id+"/info"
	f.download_href = window.api_endpoint+"/file/"+f.id+"?download"
	f.icon_href = window.api_endpoint+"/file/"+f.id+"/thumbnail"
	f.timeseries_href = window.api_endpoint+"/file/"+f.id+"/timeseries"
}
const toggle_gallery = () => {
	if (view === "gallery") {
		open_file_index(0)
	} else {
		location.replace("#gallery")
		view = "gallery"
		file = file_struct // Empty the file struct
	}
}

let download_frame
let is_captcha_script_loaded = false
let download_captcha_window
let captcha_type = "" // rate_limit or malware
let captcha_window_title = ""
let captcha_container
const download = () => {
	if (!window.viewer_data.captcha_key) {
		console.debug("Server doesn't support captcha, starting download")
		download_frame.src = file.download_href
		return
	}
	if (file.availability === "") {
		console.debug("File is available, starting download")
		download_frame.src = file.download_href
		return
	}

	console.debug("File is not readily available, showing captcha dialog")

	// When the captcha is filled in by the user this function is called. Here
	// we trigger the download using the captcha token Google provided us with
	let captcha_complete_callback = token => {
		// Download the file using the recaptcha token
		download_frame.src = file.download_href + "&recaptcha_response=" + token
		download_captcha_window.hide()
	}

	// Function which will be called when the captcha script is loaded. This
	// renders the checkbox in the modal window
	window.captcha_script_loaded = async () => {
		download_captcha_window.show()
		await tick()
		grecaptcha.render(captcha_container, {
			sitekey: window.viewer_data.captcha_key,
			theme: "dark",
			callback: captcha_complete_callback,
		})
	}

	if (file.availability === "file_rate_limited_captcha_required") {
		captcha_type = "rate_limit"
		captcha_window_title = "Rate limiting enabled!"
	} else if (file.availability === "virus_detected_captcha_required") {
		captcha_type = "malware"
		captcha_window_title = "Malware warning!"
	}

	if (is_captcha_script_loaded) {
		console.debug("Captcha script is already loaded. Show the modal")
		captcha_script_loaded()
	} else {
		console.debug("Captcha script has not been loaded yet. Embedding now")

		let script = document.createElement("script")
		script.src = "https://www.google.com/recaptcha/api.js?onload=captcha_script_loaded&render=explicit"
		document.body.appendChild(script)
		is_captcha_script_loaded = true
	}
}
const download_list = () => {
	if (is_list) {
		download_frame.src = list.download_href
	}
}

let supports_fullscreen = !!document.documentElement.requestFullscreen
let fullscreen = false
const toggle_fullscreen = () => {
	if (!fullscreen) {
		document.documentElement.requestFullscreen()
		document.getElementById("btn_fullscreen_icon").innerText = "fullscreen_exit"
		fullscreen = true
	} else {
		document.exitFullscreen()
		document.getElementById("btn_fullscreen_icon").innerText = "fullscreen"
		fullscreen = false
	}
}

let copy_url_status = "" // empty, copied, or error
const copy_url = () => {
	if (copy_text(window.location.href)) {
		copy_url_status = "copied"
	} else {
		copy_url_status = "error"
		alert("Your browser does not support copying text.")
	}

	setTimeout(() => { copy_url_status = "" }, 60000)
}

const grab_file = async () => {
	if (!window.user_authenticated || file.can_edit) {
		return
	}

	const form = new FormData()
	form.append("grab_file", file.id)

	try {
		const resp = await fetch(
			window.api_endpoint + "/file",
			{ method: "POST", body: form },
		);
		if (resp.status >= 400) {
			throw (await resp.json()).message
		}

		window.open("/u/" + (await resp.json()).id, "_blank")
	} catch (err) {
		alert("Failed to grab file: " + err)
		return
	}
}

const keyboard_event = evt => {
	if (evt.ctrlKey || evt.altKey || evt.metaKey) {
		return // prevent custom shortcuts from interfering with system shortcuts
	}
	if (document.activeElement.type && document.activeElement.type === "text") {
		return // Prevent shortcuts from interfering with input fields
	}

	console.debug("Key pressed: " + evt.keyCode)
	switch (evt.keyCode) {
		case 65: // A or left arrow key go to previous file
		case 37:
			if (list_navigator) {
				list_navigator.prev()
			}
			break
		case 68: // D or right arrow key go to next file
		case 39:
			if (list_navigator) {
				list_navigator.next()
			}
			break
		case 83:
			if (evt.shiftKey) {
				download_list() // SHIFT + S downloads all files in list
			} else {
				download() // S to download the current file
			}
			break
		case 82: // R to toggle list shuffle
			if (list_navigator) {
				toggle_shuffle()
			}
			break
		case 67: // C to copy to clipboard
			copy_url()
			break
		case 73: // I to open the details window
			details_window.toggle()
			break
		case 69: // E to open the edit window
			if (file.can_edit) {
				edit_window.toggle()
			}
			break
		case 77: // M to open the embed window
			embed_window.toggle()
			break
		case 71: // G to grab this file
			this.grabFile()
			break
		case 81: // Q to close the window
			window.close()
			break
	}
}

</script>

<svelte:window on:keydown={keyboard_event}/>

<div id="file_viewer" class="file_viewer">
	<!-- Head elements for the ads -->
	<AdHead></AdHead>

	{#if loading}
		<div class="spinner_container">
			<Spinner></Spinner>
		</div>
	{/if}

	<div id="headerbar" class="headerbar" class:embedded>
		<button on:click={toolbar_toggle} class="button_toggle_toolbar round" class:button_highlight={toolbar_visible}>
			<i class="icon">menu</i>
		</button>
		<a href="/" bind:this={button_home} class="button button_home round" target={embedded ? "_blank" : ""}>
			<PixeldrainLogo style="height: 1.6em; width: 1.6em; margin: 0 4px 0 0;"></PixeldrainLogo>
		</a>
		<div id="file_viewer_headerbar_title" class="file_viewer_headerbar_title">
			{#if list.title !== ""}{list.title}<br/>{/if}
			{#if file.name !== ""}{file.name}{/if}
		</div>
		{#if embedded && supports_fullscreen}
			<button class="round" on:click={toggle_fullscreen}>
				<i class="icon" id="btn_fullscreen_icon">fullscreen</i>
			</button>
		{/if}
	</div>

	{#if is_list && view === "file"}
		<ListNavigator
			bind:this={list_navigator}
			files={list.files}
			shuffle={list_shuffle}
			on:set_file={e => { open_file_index(e.detail) }}>
		</ListNavigator>
	{/if}

	<div id="file_preview_window" class="file_preview_window">
		<div id="toolbar" class="toolbar" class:toolbar_visible><div><div>
			{#if view === "file"}
				<FileStats file={file}></FileStats>
				<hr/>
			{/if}

			{#if is_list}
				<button on:click={toggle_gallery} class="toolbar_button button_full_width" class:button_highlight={view === "gallery"}>
					<i class="icon">photo_library</i>
					Gallery
				</button>
			{/if}

			{#if file.abuse_type === "" && view === "file"}
				<button on:click={download} class="toolbar_button button_full_width">
					<i class="icon">download</i>
					<span>Download</span>
				</button>
			{/if}
			{#if file.abuse_type === "" && is_list}
				<button on:click={download_list} class="toolbar_button button_full_width">
					<i class="icon">download</i>
					<span>DL all files</span>
				</button>
			{/if}

			<button on:click={copy_url}
				class="toolbar_button button_full_width"
				class:button_highlight={copy_url_status === "copied"}
				class:button_red={copy_url_status === "error"}>
				<i class="icon">content_copy</i>
				<span>
					{#if copy_url_status === "copied"}
						Copied!
					{:else if copy_url_status === "error"}
						Error!
					{:else}
						<u>C</u>opy link
					{/if}
				</span>
			</button>

			<button on:click={toggle_sharebar} class="toolbar_button button_full_width" class:button_highlight={sharebar_visible}>
				<i class="icon">share</i>
				<span>Share</span>
			</button>

			<button class="toolbar_button button_full_width" on:click={qr_window.toggle} class:button_highlight={qr_visible}>
				<i class="icon">qr_code</i>
				<span>QR code</span>
			</button>

			{#if is_list}
				<button
					class="toolbar_button button_full_width"
					title="Randomize the order of the files in this list"
					class:button_highlight={list_shuffle}
					on:click={toggle_shuffle}>
					<i class="icon">shuffle</i>
					{#if list_shuffle}
						<span>Shuffle&nbsp;&#x2611;</span>
					{:else}
						<span>Shuffle&nbsp;&#x2610;</span>
					{/if}
				</button>
			{/if}

			{#if view === "file"}
				<button class="toolbar_button button_full_width" on:click={details_window.toggle} class:button_highlight={details_visible}>
					<i class="icon">help</i>
					<span>Deta<u>i</u>ls</span>
				</button>
			{/if}

			<hr/>

			{#if file.can_edit || list.can_edit}
				<button class="toolbar_button button_full_width" on:click={edit_window.toggle} class:button_highlight={edit_visible}>
					<i class="icon">edit</i>
					<span><u>E</u>dit</span>
				</button>
			{/if}

			{#if view === "file" && window.user_authenticated && !file.can_edit}
				<button on:click={grab_file} class="toolbar_button button_full_width" title="Copy this file to your own pixeldrain account">
					<i class="icon">save_alt</i>
					<span><u>G</u>rab file</span>
				</button>
			{/if}

			<button class="toolbar_button button_full_width" title="Include this file in your own webpages" on:click={embed_window.toggle} class:button_highlight={embed_visible}>
				<i class="icon">code</i>
				<span>E<u>m</u>bed</span>
			</button>

			{#if view === "file"}
				<button class="toolbar_button button_full_width" title="Report abuse in this file" on:click={report_window.toggle} class:button_highlight={report_visible}>
					<i class="icon">flag</i>
					<span>Report</span>
				</button>
			{/if}
			<br/>
		</div></div></div>

		<Sharebar bind:this={sharebar}></Sharebar>

		<div id="file_preview" class="file_preview checkers" class:toolbar_visible class:skyscraper_visible>
			{#if view === "file"}
				<FilePreview
					file={file}
					on:download={download}
					on:prev={() => { if (list_navigator) { list_navigator.prev() }}}
					on:next={() => { if (list_navigator) { list_navigator.next() }}}>
				</FilePreview>
			{:else if view === "gallery"}
				<GalleryView
					list={list}
					on:set_file={e => { open_file_index(e.detail) }}
					on:reload={reload}
					on:loading={e => {loading = e.detail}}>
				</GalleryView>
			{/if}
		</div>

		{#if ads_enabled}
			<AdSkyscraper on:visibility={e => {skyscraper_visible = e.detail}}></AdSkyscraper>
		{/if}

		<!-- This frame will load the download URL when a download button is pressed -->
		<iframe bind:this={download_frame} title="File download frame" style="display: none; width: 1px; height: 1px;"></iframe>
	</div>

	{#if ads_enabled}
		<AdLeaderboard></AdLeaderboard>
	{:else if !window.viewer_data.user_ads_enabled && !embedded}
		<div style="text-align: center; line-height: 1.3em; font-size: 13px;">
			Thank you for supporting pixeldrain!
		</div>
	{:else if !ads_enabled && !embedded}
		<div style="text-align: center; line-height: 1.3em; font-size: 13px;">
			The uploader of this file disabled advertisements. You can do the same for <a href="/#pro">only €2 per month</a>!
		</div>
	{/if}

	<Modal bind:this={details_window} on:is_visible={e => {details_visible = e.detail}} title="File details" width="1200px">
		<DetailsWindow file={file}></DetailsWindow>
	</Modal>

	<Modal bind:this={qr_window} on:is_visible={e => {qr_visible = e.detail}} title="QR code" width="500px">
		<img src="{window.api_endpoint}/misc/qr?text={encodeURIComponent(window.location.href)}" alt="QR code" style="display: block; width: 100%;"/>
	</Modal>

	<Modal bind:this={edit_window} on:is_visible={e => {edit_visible = e.detail}} title={"Editing "+file.name}>
		<EditWindow file={file} list={list} on:reload={reload}></EditWindow>
	</Modal>

	<Modal bind:this={embed_window} on:is_visible={e => {embed_visible = e.detail}} title="Embed file" width="850px">
		<EmbedWindow file={file} list={list}></EmbedWindow>
	</Modal>

	<Modal bind:this={report_window} on:is_visible={e => {report_visible = e.detail}} title="Report abuse" width="800px">
		<ReportWindow file={file} list={list}></ReportWindow>
	</Modal>

	<Modal bind:this={download_captcha_window} title={captcha_window_title} width="500px">
		{#if captcha_type === "rate_limit"}
			<p>
				This file is using a suspicious amount of bandwidth relative to
				its popularity. To continue downloading this file you will have
				to prove that you're a human first.
			</p>
		{:else if captcha_type === "malware"}
			<p>
				According to our scanning systems this file may contain a virus.
				You can continue downloading this file at your own risk, but you
				will have to prove that you're a human first.
			</p>
		{/if}
		<br/>
		<div bind:this={captcha_container} class="captcha_container"></div>
	</Modal>

	<IntroPopup target={button_home}></IntroPopup>
</div>

<style>
.spinner_container {
	position: absolute;
	top: 10px;
	right: 10px;
	height: 100px;
	width: 100px;
	z-index: 10000;
}

.file_viewer {
	position: absolute;
	display: flex;
	flex-direction: column;
	width: 100%;
	height: 100%;
	overflow: hidden;
	background-color: var(--layer_2_color);
}

/* Headerbar (row 1) */
.headerbar {
	flex-grow: 0;
	flex-shrink: 0;
	display: flex;
	flex-direction: row;
	text-align: left;
	z-index: 10;
	box-shadow: none;
	padding: 4px;
}
.headerbar.embedded {
	padding: 2px;
}

/* Headerbar components */
.headerbar > * {
	flex-grow: 0;
	flex-shrink: 0;
	margin-left: 4px;
	margin-right: 4px;
	display: inline;
}
.headerbar > .file_viewer_headerbar_title {
	flex-grow: 1;
	flex-shrink: 1;
	display: flex;
	flex-direction: column;
	overflow: hidden;
	line-height: 1.2em; /* When the page is a list there will be two lines. Dont's want to stretch the container*/
	white-space: nowrap;
	text-overflow: ellipsis;
	justify-content: center;
}
.headerbar > button > .icon {
	font-size: 1.6em;
}
.headerbar > .button_home::after {
	content: "pixeldrain";
}
@media (max-width: 600px) {
	.headerbar > .button_home::after {
		content: "pd";
	}
}

/* File preview area (row 3) */
.file_preview_window {
	flex-grow: 1;
	flex-shrink: 1;
	position: relative;
	display: inline-block;
	width: auto;
	height: auto;
	margin: 0;
	z-index: 9;
}
.file_preview {
	position: absolute;
	left: 0;
	right: 0;
	top: 0;
	bottom: 0;
	display: inline-block;
	min-height: 100px;
	min-width: 100px;
	text-align: center;
	vertical-align: middle;
	transition: left 0.5s, right 0.5s;
	overflow: hidden;
	box-shadow: inset 2px 2px 10px 2px var(--shadow_color);
	border-radius: 16px;
}

/* Toolbars */
.toolbar {
	position: absolute;
	width: 8em;
	z-index: 49;
	overflow: hidden;
	left: -8em;
	bottom: 0;
	top: 0;
	padding: 0;
	text-align: left;
	transition: left 0.5s, right 0.5s;
	background-color: var(--layer_2_color);
}
.toolbar.toolbar_visible { left: 0; }
.file_preview.toolbar_visible { left: 8em; }
.file_preview.skyscraper_visible { right: 160px; }

/* Workaround to hide the scrollbar in non webkit browsers, it's really ugly' */
.toolbar > div {
	position: absolute;
	left: 0;
	top: 0;
	bottom: 0;
	right: -30px;
	overflow-y: scroll;
	overflow-x: hidden;
}
.toolbar > div > div {
	position: absolute;
	left: 0;
	top: 0;
	width: 8em;
	height: auto;
	text-align: center;
}

.toolbar_button{
	text-align: left;
}
.toolbar_button > span {
	vertical-align: middle;
}

/* =====================
	|| MISC COMPONENTS ||
	===================== */

.captcha_container {
	text-align: center;
}
/* global() to silence the unused selector warning */
.captcha_container > :global(div) {
	display: inline-block;
}
</style>
