
import window from 'window';
import _ from '_';
import ko from 'ko';

import {FileType} from 'Common/Enums';
import {bAllowPdfPreview, data as GlobalsData} from 'Common/Globals';
import {trim, pInt, inArray, isNonEmptyArray, getFileExtension, friendlySize} from 'Common/Utils';
import {attachmentDownload, attachmentPreview, attachmentFramed, attachmentPreviewAsPlain, attachmentThumbnailPreview} from 'Common/Links';

import {AbstractModel} from 'Knoin/AbstractModel';

import Audio from 'Common/Audio';

/**
 * @param {string} sExt
 * @param {string} sMimeType
 * @returns {string}
 */
export const staticFileType = _.memoize((ext, mimeType) => {
	ext = trim(ext).toLowerCase();
	mimeType = trim(mimeType).toLowerCase();

	let result = FileType.Unknown;
	const mimeTypeParts = mimeType.split('/');

	switch (true)
	{
		case 'image' === mimeTypeParts[0] || -1 < inArray(ext, [
			'png', 'jpg', 'jpeg', 'gif', 'bmp'
		]):
			result = FileType.Image;
			break;
		case 'audio' === mimeTypeParts[0] || -1 < inArray(ext, [
			'mp3', 'ogg', 'oga', 'wav'
		]):
			result = FileType.Audio;
			break;
		case 'video' === mimeTypeParts[0] || -1 < inArray(ext, [
			'mkv', 'avi'
		]):
			result = FileType.Video;
			break;
		case -1 < inArray(ext, [
			'php', 'js', 'css'
		]):
			result = FileType.Code;
			break;
		case 'eml' === ext || -1 < inArray(mimeType, [
			'message/delivery-status', 'message/rfc822'
		]):
			result = FileType.Eml;
			break;
		case ('text' === mimeTypeParts[0] && 'html' !== mimeTypeParts[1]) || -1 < inArray(ext, [
			'txt', 'log'
		]):
			result = FileType.Text;
			break;
		case ('text/html' === mimeType) || -1 < inArray(ext, [
			'html'
		]):
			result = FileType.Html;
			break;
		case -1 < inArray(mimeTypeParts[1], [
			'zip', '7z', 'tar', 'rar', 'gzip', 'bzip', 'bzip2', 'x-zip', 'x-7z', 'x-rar', 'x-tar', 'x-gzip', 'x-bzip', 'x-bzip2', 'x-zip-compressed', 'x-7z-compressed', 'x-rar-compressed'
		]) || -1 < inArray(ext, [
			'zip', '7z', 'tar', 'rar', 'gzip', 'bzip', 'bzip2'
		]):
			result = FileType.Archive;
			break;
		case -1 < inArray(mimeTypeParts[1], ['pdf', 'x-pdf']) || -1 < inArray(ext, [
			'pdf'
		]):
			result = FileType.Pdf;
			break;
		case -1 < inArray(mimeType, [
			'application/pgp-signature', 'application/pgp-keys'
		]) || -1 < inArray(ext, [
			'asc', 'pem', 'ppk'
		]):
			result = FileType.Certificate;
			break;
		case -1 < inArray(mimeType, ['application/pkcs7-signature']) ||
			-1 < inArray(ext, ['p7s']):

			result = FileType.CertificateBin;
			break;
		case -1 < inArray(mimeTypeParts[1], [
			'rtf', 'msword', 'vnd.msword', 'vnd.openxmlformats-officedocument.wordprocessingml.document',
			'vnd.openxmlformats-officedocument.wordprocessingml.template',
			'vnd.ms-word.document.macroEnabled.12',
			'vnd.ms-word.template.macroEnabled.12'
		]):
			result = FileType.WordText;
			break;
		case -1 < inArray(mimeTypeParts[1], [
			'excel', 'ms-excel', 'vnd.ms-excel',
			'vnd.openxmlformats-officedocument.spreadsheetml.sheet',
			'vnd.openxmlformats-officedocument.spreadsheetml.template',
			'vnd.ms-excel.sheet.macroEnabled.12',
			'vnd.ms-excel.template.macroEnabled.12',
			'vnd.ms-excel.addin.macroEnabled.12',
			'vnd.ms-excel.sheet.binary.macroEnabled.12'
		]):
			result = FileType.Sheet;
			break;
		case -1 < inArray(mimeTypeParts[1], [
			'powerpoint', 'ms-powerpoint', 'vnd.ms-powerpoint',
			'vnd.openxmlformats-officedocument.presentationml.presentation',
			'vnd.openxmlformats-officedocument.presentationml.template',
			'vnd.openxmlformats-officedocument.presentationml.slideshow',
			'vnd.ms-powerpoint.addin.macroEnabled.12',
			'vnd.ms-powerpoint.presentation.macroEnabled.12',
			'vnd.ms-powerpoint.template.macroEnabled.12',
			'vnd.ms-powerpoint.slideshow.macroEnabled.12'
		]):
			result = FileType.Presentation;
			break;
		// no default
	}

	return result;
});

/**
 * @param {string} sFileType
 * @returns {string}
 */
export const staticIconClass = _.memoize((fileType) => {
	let
		resultText = '',
		resultClass = 'icon-file';

	switch (fileType)
	{
		case FileType.Text:
		case FileType.Eml:
		case FileType.WordText:
			resultClass = 'icon-file-text';
			break;
		case FileType.Html:
		case FileType.Code:
			resultClass = 'icon-file-code';
			break;
		case FileType.Image:
			resultClass = 'icon-file-image';
			break;
		case FileType.Audio:
			resultClass = 'icon-file-music';
			break;
		case FileType.Video:
			resultClass = 'icon-file-movie';
			break;
		case FileType.Archive:
			resultClass = 'icon-file-zip';
			break;
		case FileType.Certificate:
		case FileType.CertificateBin:
			resultClass = 'icon-file-certificate';
			break;
		case FileType.Sheet:
			resultClass = 'icon-file-excel';
			break;
		case FileType.Presentation:
			resultClass = 'icon-file-chart-graph';
			break;
		case FileType.Pdf:
			resultText = 'pdf';
			resultClass = 'icon-none';
			break;
		// no default
	}

	return [resultClass, resultText];
});

/**
 * @static
 * @param {string} sFileType
 * @returns {string}
 */
export const staticCombinedIconClass = (data) => {
	let
		result = '',
		types = [];

	if (isNonEmptyArray(data))
	{
		result = 'icon-attachment';
		types = _.uniq(_.compact(_.map(data, (item) => (item ? staticFileType(getFileExtension(item[0]), item[1]) : ''))));

		if (types && 1 === types.length && types[0])
		{
			switch (types[0])
			{
				case FileType.Text:
				case FileType.WordText:
					result = 'icon-file-text';
					break;
				case FileType.Html:
				case FileType.Code:
					result = 'icon-file-code';
					break;
				case FileType.Image:
					result = 'icon-file-image';
					break;
				case FileType.Audio:
					result = 'icon-file-music';
					break;
				case FileType.Video:
					result = 'icon-file-movie';
					break;
				case FileType.Archive:
					result = 'icon-file-zip';
					break;
				case FileType.Certificate:
				case FileType.CertificateBin:
					result = 'icon-file-certificate';
					break;
				case FileType.Sheet:
					result = 'icon-file-excel';
					break;
				case FileType.Presentation:
					result = 'icon-file-chart-graph';
					break;
				// no default
			}
		}
	}

	return result;
};

class AttachmentModel extends AbstractModel
{
	constructor() {
		super('AttachmentModel');

		this.checked = ko.observable(false);

		this.mimeType = '';
		this.fileName = '';
		this.fileNameExt = '';
		this.fileType = FileType.Unknown;
		this.estimatedSize = 0;
		this.friendlySize = '';
		this.isInline = false;
		this.isLinked = false;
		this.isThumbnail = false;
		this.cid = '';
		this.cidWithOutTags = '';
		this.contentLocation = '';
		this.download = '';
		this.folder = '';
		this.uid = '';
		this.mimeIndex = '';
		this.framed = false;
	}

	/**
	 * @static
	 * @param {AjaxJsonAttachment} json
	 * @returns {?AttachmentModel}
	 */
	static newInstanceFromJson(json) {
		const attachment = new AttachmentModel();
		return attachment.initByJson(json) ? attachment : null;
	}

	/**
	 * @param {AjaxJsonAttachment} json
	 * @returns {boolean}
	 */
	initByJson(json) {
		let bResult = false;
		if (json && 'Object/Attachment' === json['@Object'])
		{
			this.mimeType = trim((json.MimeType || '').toLowerCase());
			this.fileName = trim(json.FileName);
			this.estimatedSize = pInt(json.EstimatedSize);
			this.isInline = !!json.IsInline;
			this.isLinked = !!json.IsLinked;
			this.isThumbnail = !!json.IsThumbnail;
			this.cid = json.CID;
			this.contentLocation = json.ContentLocation;
			this.download = json.Download;

			this.folder = json.Folder;
			this.uid = json.Uid;
			this.mimeIndex = json.MimeIndex;
			this.framed = !!json.Framed;

			this.friendlySize = friendlySize(this.estimatedSize);
			this.cidWithOutTags = this.cid.replace(/^<+/, '').replace(/>+$/, '');

			this.fileNameExt = getFileExtension(this.fileName);
			this.fileType = staticFileType(this.fileNameExt, this.mimeType);

			bResult = true;
		}

		return bResult;
	}

	/**
	 * @returns {boolean}
	 */
	isImage() {
		return FileType.Image === this.fileType;
	}

	/**
	 * @returns {boolean}
	 */
	isMp3() {
		return FileType.Audio === this.fileType && 'mp3' === this.fileNameExt;
	}

	/**
	 * @returns {boolean}
	 */
	isOgg() {
		return FileType.Audio === this.fileType && ('oga' === this.fileNameExt || 'ogg' === this.fileNameExt);
	}

	/**
	 * @returns {boolean}
	 */
	isWav() {
		return FileType.Audio === this.fileType && 'wav' === this.fileNameExt;
	}

	/**
	 * @returns {boolean}
	 */
	hasThumbnail() {
		return this.isThumbnail;
	}

	/**
	 * @returns {boolean}
	 */
	isText() {
		return FileType.Text === this.fileType || FileType.Eml === this.fileType ||
			FileType.Certificate === this.fileType || FileType.Html === this.fileType || FileType.Code === this.fileType;
	}

	/**
	 * @returns {boolean}
	 */
	isPdf() {
		return FileType.Pdf === this.fileType;
	}

	/**
	 * @returns {boolean}
	 */
	isFramed() {
		return this.framed && (GlobalsData.__APP__ && GlobalsData.__APP__.googlePreviewSupported()) &&
			!(this.isPdf() && bAllowPdfPreview) && !this.isText() && !this.isImage();
	}

	/**
	 * @returns {boolean}
	 */
	hasPreview() {
		return this.isImage() || (this.isPdf() && bAllowPdfPreview) || this.isText() || this.isFramed();
	}

	/**
	 * @returns {boolean}
	 */
	hasPreplay() {
		return (Audio.supportedMp3 && this.isMp3()) || (Audio.supportedOgg && this.isOgg()) || (Audio.supportedWav && this.isWav());
	}

	/**
	 * @returns {string}
	 */
	linkDownload() {
		return attachmentDownload(this.download);
	}

	/**
	 * @returns {string}
	 */
	linkPreview() {
		return attachmentPreview(this.download);
	}

	/**
	 * @returns {string}
	 */
	linkThumbnail() {
		return this.hasThumbnail() ? attachmentThumbnailPreview(this.download) : '';
	}

	/**
	 * @returns {string}
	 */
	linkThumbnailPreviewStyle() {
		const link = this.linkThumbnail();
		return '' === link ? '' : 'background:url(' + link + ')';
	}

	/**
	 * @returns {string}
	 */
	linkFramed() {
		return attachmentFramed(this.download);
	}

	/**
	 * @returns {string}
	 */
	linkPreviewAsPlain() {
		return attachmentPreviewAsPlain(this.download);
	}

	/**
	 * @returns {string}
	 */
	linkPreviewMain() {
		let result = '';
		switch (true)
		{
			case this.isImage():
			case this.isPdf() && bAllowPdfPreview:
				result = this.linkPreview();
				break;
			case this.isText():
				result = this.linkPreviewAsPlain();
				break;
			case this.isFramed():
				result = this.linkFramed();
				break;
			// no default
		}

		return result;
	}

	/**
	 * @returns {string}
	 */
	generateTransferDownloadUrl() {
		let link = this.linkDownload();
		if ('http' !== link.substr(0, 4))
		{
			link = window.location.protocol + '//' + window.location.host + window.location.pathname + link;
		}

		return this.mimeType + ':' + this.fileName + ':' + link;
	}

	/**
	 * @param {AttachmentModel} attachment
	 * @param {*} event
	 * @returns {boolean}
	 */
	eventDragStart(attachment, event) {
		const localEvent = event.originalEvent || event;
		if (attachment && localEvent && localEvent.dataTransfer && localEvent.dataTransfer.setData)
		{
			localEvent.dataTransfer.setData('DownloadURL', this.generateTransferDownloadUrl());
		}

		return true;
	}

	/**
	 * @returns {string}
	 */
	iconClass() {
		return staticIconClass(this.fileType)[0];
	}

	/**
	 * @returns {string}
	 */
	iconText() {
		return staticIconClass(this.fileType)[1];
	}
}

export {AttachmentModel, AttachmentModel as default};
