"use strict";

describe("Reader", function () {
	var win, zp;

	before(function* () {
		win = yield loadZoteroPane();
		zp = win.ZoteroPane;
	});

	after(function () {
		win.Zotero_Tabs.closeAll();
		win.close();
	});

	describe('PDF Reader', function () {
		it('should create/update annotations', async function () {
			var attachment = await importFileAttachment('test.pdf');

			var reader = await Zotero.Reader.open(attachment.itemID);
			await reader._initPromise;
			reader._internalReader._annotationManager._skipAnnotationSavingDebounce = true;

			// Add highlight annotation
			let highlightAnnotation = reader._internalReader._annotationManager.addAnnotation(
				Components.utils.cloneInto({
					type: 'highlight',
					color: '#ffd400',
					sortIndex: '00000|003305|00000',
					position: {
						pageIndex: 0,
						rects: [[0, 0, 100, 100]]
					},
					text: 'test'
				}, reader._iframeWindow)
			);
			await waitForItemEvent("add");
			// Add underline annotation
			let underlineAnnotation = await reader._internalReader._annotationManager.addAnnotation(
				Components.utils.cloneInto({
					type: 'underline',
					color: '#ffd400',
					sortIndex: '00000|003305|00000',
					position: {
						pageIndex: 0,
						rects: [[0, 0, 100, 100]]
					},
					text: 'test'
				}, reader._iframeWindow)
			);
			await waitForItemEvent("add");
			// Add note annotation
			let noteAnnotation = await reader._internalReader._annotationManager.addAnnotation(
				Components.utils.cloneInto({
					type: 'note',
					color: '#ffd400',
					sortIndex: '00000|003305|00000',
					comment: 'test',
					position: {
						pageIndex: 0,
						rects: [[0, 0, 100, 100]]
					},
					text: 'test'
				}, reader._iframeWindow)
			);
			await waitForItemEvent("add");
			// Add text annotation
			let textAnnotation = await reader._internalReader._annotationManager.addAnnotation(
				Components.utils.cloneInto({
					type: 'text',
					color: '#ffd400',
					sortIndex: '00000|003305|00000',
					comment: 'test',
					position: {
						pageIndex: 0,
						rects: [[17.70514027630181, 729.1404633368757, 132.24914027630183, 762.1404633368757]],
						fontSize: 14,
						rotation: 10
					},
					text: 'test'
				}, reader._iframeWindow)
			);
			await waitForItemEvent("add");
			// Add image annotation
			let imageAnnotation = await reader._internalReader._annotationManager.addAnnotation(
				Components.utils.cloneInto({
					type: 'image',
					color: '#ffd400',
					sortIndex: '00000|003305|00000',
					comment: 'test',
					position: {
						pageIndex: 0,
						rects: [[0, 0, 100, 100]]
					}
				}, reader._iframeWindow)
			);
			await waitForItemEvent("add");
			// Add ink annotation
			let inkAnnotation = await reader._internalReader._annotationManager.addAnnotation(
				Components.utils.cloneInto({
					type: 'ink',
					color: '#ffd400',
					sortIndex: '00000|003305|00000',
					position: {
						pageIndex: 0,
						paths: [[517.759, 760.229]],
						width: 2
					},
				}, reader._iframeWindow)
			);
			await waitForItemEvent("add");

			// Modify highlight annotation
			reader._internalReader._annotationManager.updateAnnotations(
				Components.utils.cloneInto([
					{
						id: highlightAnnotation.id,
						text: 'test2'
					}
				], reader._iframeWindow)
			);
			await waitForItemEvent("modify");
			// Modify underline annotation
			await reader._internalReader._annotationManager.updateAnnotations(
				Components.utils.cloneInto([
					{
						id: underlineAnnotation.id,
						text: 'test2'
					}
				], reader._iframeWindow)
			);
			await waitForItemEvent("modify");
			// Modify note annotation
			await reader._internalReader._annotationManager.updateAnnotations(
				Components.utils.cloneInto([
					{
						id: noteAnnotation.id,
						color: '#aabbcc'
					}
				], reader._iframeWindow)
			);
			await waitForItemEvent("modify");
			// Modify text annotation
			await reader._internalReader._annotationManager.updateAnnotations(
				Components.utils.cloneInto([
					{
						id: textAnnotation.id,
						sortIndex: '00000|001491|00283',
						position: {
							pageIndex: 0,
							rects: [[17.70514027630181, 729.1404633368757, 132.24914027630183, 762.1404633368757]],
							fontSize: 16,
							rotation: 10
						},
					}
				], reader._iframeWindow)
			);
			await waitForItemEvent("modify");
			// Modify image annotation
			await reader._internalReader._annotationManager.updateAnnotations(
				Components.utils.cloneInto([
					{
						id: imageAnnotation.id,
						sortIndex: '00000|001491|00283',
						position: {
							pageIndex: 0,
							rects: [[0, 0, 200, 200]]
						}
					}
				], reader._iframeWindow)
			);
			await waitForItemEvent("modify");
			// Modify ink annotation
			await reader._internalReader._annotationManager.updateAnnotations(
				Components.utils.cloneInto([
					{
						id: inkAnnotation.id,
						sortIndex: '00000|001491|00283',
						position: {
							pageIndex: 0,
							paths: [[617.759, 560.229]],
							width: 2,
							unknownField: 'test'
						},
					}
				], reader._iframeWindow)
			);
			await waitForItemEvent("modify");

			var annotations = attachment.getAnnotations();
			assert.equal(annotations.length, 6);

			assert.equal(annotations.find(x => x.key === highlightAnnotation.id).annotationText, 'test2');
			assert.equal(annotations.find(x => x.key === underlineAnnotation.id).annotationText, 'test2');
			assert.equal(annotations.find(x => x.key === noteAnnotation.id).annotationColor, '#aabbcc');
			assert.equal(JSON.parse(annotations.find(x => x.key === textAnnotation.id).annotationPosition).fontSize, 16);
			assert.equal(JSON.parse(annotations.find(x => x.key === imageAnnotation.id).annotationPosition).rects[0][2], 200);
			assert.equal(JSON.parse(annotations.find(x => x.key === inkAnnotation.id).annotationPosition).pageIndex, 0);
			assert.equal(JSON.parse(annotations.find(x => x.key === inkAnnotation.id).annotationPosition).unknownField, 'test');
			reader.close();
		});

		describe("#importFromEPUB()", function () {
			let bookEpubPath; // The EPUB itself
			let bookSdrPath; // The KOReader "sidecar" folder
			let calibreBookmarksPath; // The calibre_bookmarks.txt file (we'll copy this into META_INF for some tests)
			let metadataOpfPath; // The Calibre metadata.opf file

			let tempPath;
			let tempBookEpubPath;

			async function waitForReader(reader) {
				await reader._initPromise;
				// Shouldn't this just be included in _initPromise?
				await reader._internalReader._primaryView.initializedPromise;
			}
			
			async function waitForAdds(n) {
				while (n > 0) {
					n -= (await waitForItemEvent('add')).length;
				}
			}
			
			before(function () {
				bookEpubPath = getTestDataDirectory();
				bookEpubPath.append('moby_dick');
				bookEpubPath.append('book.epub');
				bookEpubPath = bookEpubPath.path;
				
				calibreBookmarksPath = getTestDataDirectory();
				calibreBookmarksPath.append('moby_dick');
				calibreBookmarksPath.append('calibre_bookmarks.txt');
				calibreBookmarksPath = calibreBookmarksPath.path;

				metadataOpfPath = getTestDataDirectory();
				metadataOpfPath.append('moby_dick');
				metadataOpfPath.append('metadata.opf');
				metadataOpfPath = metadataOpfPath.path;

				bookSdrPath = getTestDataDirectory();
				bookSdrPath.append('moby_dick');
				bookSdrPath.append('book.sdr');
				bookSdrPath = bookSdrPath.path;
			});
			
			beforeEach(async function () {
				tempPath = await getTempDirectory();
				tempBookEpubPath = PathUtils.join(tempPath, 'book.epub');
				await IOUtils.copy(bookEpubPath, tempBookEpubPath);
			});
			
			it("should import EPUB annotations from KOReader (stored alongside EPUB)", async function () {
				await IOUtils.copy(bookSdrPath, PathUtils.join(tempPath, 'book.sdr'), { recursive: true });
				
				let attachment = await Zotero.Attachments.linkFromFile({ file: tempBookEpubPath });
				let reader = await Zotero.Reader.open(attachment.id);
				await waitForReader(reader);
				
				let donePromise = Promise.all([waitForDialog(), waitForAdds(2)]);
				await reader.importFromEPUB();
				await donePromise;
				
				assert.equal(attachment.getAnnotations().length, 2);
			});
			
			it("should import EPUB annotations from KOReader (stored elsewhere)", async function () {
				let attachment = await Zotero.Attachments.linkFromFile({ file: tempBookEpubPath });
				let reader = await Zotero.Reader.open(attachment.id);
				await waitForReader(reader);

				let donePromise = Promise.all([waitForDialog(), waitForAdds(2)]);
				// Import annotations from the *original* EPUB (alongside its book.sdr/metadata.epub.lua)
				await reader.importFromEPUB(bookEpubPath);
				await donePromise;
				
				assert.equal(attachment.getAnnotations().length, 2);
			});

			it("should import EPUB annotations from Calibre (stored alongside EPUB)", async function () {
				await IOUtils.copy(metadataOpfPath, PathUtils.join(tempPath, 'metadata.opf'));

				let attachment = await Zotero.Attachments.linkFromFile({ file: tempBookEpubPath });
				let reader = await Zotero.Reader.open(attachment.id);
				await waitForReader(reader);

				let donePromise = Promise.all([waitForDialog(), waitForAdds(2)]);
				await reader.importFromEPUB();
				await donePromise;

				assert.equal(attachment.getAnnotations().length, 2);
			});

			it("should import EPUB annotations from Calibre (stored within EPUB)", async function () {
				let zipWriter = Cc['@mozilla.org/zipwriter;1'].createInstance(Ci.nsIZipWriter);
				zipWriter.open(Zotero.File.pathToFile(tempBookEpubPath), 0x04 /* RDWR */);
				zipWriter.addEntryFile(
					'META-INF/calibre_bookmarks.txt',
					Ci.nsIZipWriter.COMPRESSION_DEFAULT,
					Zotero.File.pathToFile(calibreBookmarksPath),
					false,
				);
				zipWriter.close();
				
				let attachment = await Zotero.Attachments.linkFromFile({ file: tempBookEpubPath });
				let reader = await Zotero.Reader.open(attachment.id);
				await waitForReader(reader);

				let donePromise = Promise.all([waitForDialog(), waitForAdds(2)]);
				await reader.importFromEPUB();
				await donePromise;

				assert.equal(attachment.getAnnotations().length, 2);
			});
		});
	});
});
