<?xml version="1.0"?>
<!--
    ***** BEGIN LICENSE BLOCK *****
    
    Copyright © 2009 Center for History and New Media
                     George Mason University, Fairfax, Virginia, USA
                     http://zotero.org
    
    This file is part of Zotero.
    
    Zotero is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    Zotero is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.
    
    You should have received a copy of the GNU Affero General Public License
    along with Zotero.  If not, see <http://www.gnu.org/licenses/>.
    
    ***** END LICENSE BLOCK *****
-->

<!DOCTYPE bindings SYSTEM "chrome://zotero/locale/zotero.dtd">
<!-- <!DOCTYPE bindings SYSTEM "chrome://zotero/locale/attachmentbox.dtd"> -->

<bindings xmlns="http://www.mozilla.org/xbl"
		  xmlns:xbl="http://www.mozilla.org/xbl"
		  xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
	
	<binding id="attachment-box">
		<resources>
			<stylesheet src="chrome://zotero/skin/bindings/attachmentbox.css"/>
			<stylesheet src="chrome://zotero-platform/content/attachmentbox.css"/>
		</resources>
		
		<implementation>
			<!--
				Public properties
			-->
			<field name="editable">false</field>
			<field name="clickableLink">false</field>
			<field name="displayButton">false</field>
			<field name="displayNote">false</field>
			
			<field name="buttonCaption"/>
			<field name="clickHandler"/>
			
			<!-- Modes are predefined settings groups for particular tasks -->
			<field name="_mode">"view"</field>
			<property name="mode" onget="return this._mode;">
				<setter>
				<![CDATA[
					Zotero.debug("Setting mode to '" + val + "'");
					
					this.editable = false;
					this.displayURL = false;
					this.displayFileName = false;
					this.clickableLink = false;
					this.displayAccessed = false;
					this.displayPages = false;
					this.displayDateModified = false;
					this.displayIndexed = false;
					this.displayNote = false;
					this.displayNoteIfEmpty = false;
					
					switch (val) {
						case 'view':
							this.displayURL = true;
							this.displayFileName = true;
							this.clickableLink = true;
							this.displayAccessed = true;
							this.displayPages = true;
							this.displayIndexed = true;
							this.displayNote = true;
							this.displayDateModified = true;
							break;
						
						case 'edit':
							this.editable = true;
							this.displayURL = true;
							this.displayFileName = true;
							this.clickableLink = true;
							this.displayAccessed = true;
							this.displayPages = true;
							this.displayIndexed = true;
							this.displayNote = true;
							this.displayNoteIfEmpty = true;
							this.displayDateModified = true;
							break;
						
						case 'merge':
							this.displayURL = true;
							this.displayFileName = true;
							this.displayAccessed = true;
							this.displayNote = true;
							this.displayButton = true;
							this.displayDateModified = true;
							break;
						
						case 'mergeedit':
							this.editable = true;
							this.displayURL = true;
							this.displayFileName = true;
							this.displayAccessed = true;
							this.displayNote = true;
							// Notes aren't currently editable in mergeedit pane
							this.displayNoteIfEmpty = false;
							this.displayDateModified = true;
							break;
						
						default:
							throw ("Invalid mode '" + val + "' in attachmentbox.xml");
					}
					
					this._mode = val;
					document.getAnonymousNodes(this)[0].setAttribute('mode', val);
				]]>
				</setter>
			</property>
			
			<field name="_item"/>
			<property name="item"
				onget="return this._item;"
				onset="this._item = val; this.refresh();">
			</property>
			
			<!-- .ref is an alias for .item -->
			<property name="ref"
				onget="return this._item;"
				onset="this._item = val; this.refresh();">
			</property>
			
			
			<!-- Private properties -->
			
			<method name="refresh">
				<body><![CDATA[
					Zotero.spawn(function* () {
						Zotero.debug('Refreshing attachment box');
						
						yield Zotero.Promise.all([this.item.loadItemData(), this.item.loadNote()]);
						
						var attachmentBox = document.getAnonymousNodes(this)[0];
						var title = this._id('title');
						var fileNameRow = this._id('fileNameRow');
						var urlField = this._id('url');
						var accessed = this._id('accessedRow');
						var pagesRow = this._id('pagesRow');
						var dateModifiedRow = this._id('dateModifiedRow');
						var indexStatusRow = this._id('indexStatusRow');
						var selectButton = this._id('select-button');
						
						// DEBUG: this is annoying -- we really want to use an abstracted
						// version of createValueElement() from itemPane.js
						// (ideally in an XBL binding)
						
						// Wrap title to multiple lines if necessary
						while (title.hasChildNodes()) {
							title.removeChild(title.firstChild);
						}
						var val = this.item.getField('title');
						
						if (typeof val != 'string') {
							val += "";
						}
						
						var firstSpace = val.indexOf(" ");
						// Crop long uninterrupted text
						if ((firstSpace == -1 && val.length > 29 ) || firstSpace > 29) {
							title.setAttribute('crop', 'end');
							title.setAttribute('value', val);
						}
						// Create a <description> element, essentially
						else {
							title.removeAttribute('value');
							title.appendChild(document.createTextNode(val));
						}
						
						if (this.editable) {
							title.className = 'zotero-clicky';
							
							// For the time being, use a silly little popup
							title.addEventListener('click', this.editTitle, false);
						}
						
						var isImportedURL = this.item.attachmentLinkMode ==
												Zotero.Attachments.LINK_MODE_IMPORTED_URL;
						
						// Metadata for URL's
						if (this.item.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_URL
								|| isImportedURL) {
							
							// URL
							if (this.displayURL) {
								var urlSpec = this.item.getField('url');
								urlField.setAttribute('value', urlSpec);
								urlField.setAttribute('hidden', false);
								if (this.clickableLink) {
									 urlField.onclick = function (event) {
										ZoteroPane_Local.loadURI(this.value, event)
									};
									urlField.className = 'zotero-text-link';
								}
								else {
									urlField.className = '';
								}
								urlField.hidden = false;
							}
							else {
								urlField.hidden = true;
							}
							
							// Access date
							if (this.displayAccessed) {
								this._id("accessed-label").value = Zotero.getString('itemFields.accessDate')
									+ Zotero.getString('punctuation.colon');
								this._id("accessed").value = Zotero.Date.sqlToDate(
										this.item.getField('accessDate'), true
									).toLocaleString();
								accessed.hidden = false;
							}
							else {
								accessed.hidden = true;
							}
						}
						// Metadata for files
						else {
							urlField.hidden = true;
							accessed.hidden = true;
						}
						
						if (this.item.attachmentLinkMode
									!= Zotero.Attachments.LINK_MODE_LINKED_URL
								&& this.displayFileName) {
							var fileName = this.item.getFilename();
							
							if (fileName) {
								this._id("fileName-label").value = Zotero.getString('pane.item.attachments.filename')
									+ Zotero.getString('punctuation.colon');
								this._id("fileName").value = fileName;
								fileNameRow.hidden = false;
							}
							else {
								fileNameRow.hidden = true;
							}
						}
						else {
							fileNameRow.hidden = true;
						}
						
						// Page count
						if (this.displayPages) {
							var pages = yield Zotero.Fulltext.getPages(this.item.id);
							var pages = pages ? pages.total : null;
							if (pages) {
								this._id("pages-label").value = Zotero.getString('itemFields.pages')
									+ Zotero.getString('punctuation.colon');
								this._id("pages").value = pages;
								pagesRow.hidden = false;
							}
							else {
								pagesRow.hidden = true;
							}
						}
						else {
							pagesRow.hidden = true;
						}
						
						if (this.displayDateModified) {
							this._id("dateModified-label").value = Zotero.getString('itemFields.dateModified')
								+ Zotero.getString('punctuation.colon');
							var mtime = yield this.item.attachmentModificationTime;
							if (mtime) {
								this._id("dateModified").value = new Date(mtime).toLocaleString();
							}
							// Use the item's mod time as a backup (e.g., when sync
							// passes in the mod time for the nonexistent remote file)
							else {
								this._id("dateModified").value = Zotero.Date.sqlToDate(
									this.item.getField('dateModified'), true
								).toLocaleString();
							}
							dateModifiedRow.hidden = false;
						}
						else {
							dateModifiedRow.hidden = true;
						}
						
						// Full-text index information
						if (this.displayIndexed) {
							yield this.updateItemIndexedState();
							indexStatusRow.hidden = false;
						}
						else {
							indexStatusRow.hidden = true;
						}
						
						// Note editor
						var noteEditor = this._id('attachment-note-editor');
						if (this.displayNote) {
							if (this.displayNoteIfEmpty || this.item.getNote() != '') {
								Zotero.debug("setting links on top");
								noteEditor.linksOnTop = true;
								noteEditor.hidden = false;
								
								// Don't make note editable (at least for now)
								if (this.mode == 'merge' || this.mode == 'mergeedit') {
									noteEditor.mode = 'merge';
									noteEditor.displayButton = false;
								}
								else {
									noteEditor.mode = this.mode;
								}
								noteEditor.parent = null;
								noteEditor.item = this.item;
							}
						}
						else {
							noteEditor.hidden = true;
						}
							
						
						if (this.displayButton) {
							selectButton.label = this.buttonCaption;
							selectButton.hidden = false;
							selectButton.setAttribute('oncommand',
								'document.getBindingParent(this).clickHandler(this)');
						}
						else {
							selectButton.hidden = true;
						}
					}, this);
				]]></body>
			</method>
			
			
			<method name="editTitle">
				<body>
				<![CDATA[
					var item = document.getBindingParent(this).item;
					var oldTitle = item.getField('title');
					
					var nsIPS = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
							.getService(Components.interfaces.nsIPromptService);
					
					var newTitle = { value: oldTitle };
					var checkState = { value: Zotero.Prefs.get('lastRenameAssociatedFile') };
					
					while (true) {
						// Don't show "Rename associated file" option for
						// linked URLs
						if (item.attachmentLinkMode ==
								Zotero.Attachments.LINK_MODE_LINKED_URL) {
							var result = nsIPS.prompt(
								window,
								'',
								Zotero.getString('pane.item.attachments.rename.title'),
								newTitle,
								null,
								{}
							);
							
							// If they hit cancel or left it blank
							if (!result || !newTitle.value) {
								return;
							}
							
							break;
						}
						
						var result = nsIPS.prompt(
							window,
							'',
							Zotero.getString('pane.item.attachments.rename.title'),
							newTitle,
							Zotero.getString('pane.item.attachments.rename.renameAssociatedFile'),
							checkState
						);
						
						// If they hit cancel or left it blank
						if (!result || !newTitle.value) {
							return;
						}
						
						Zotero.Prefs.set('lastRenameAssociatedFile', checkState.value);
						
						// Rename associated file
						if (checkState.value) {
							var newFilename = newTitle.value.trim();
							if (newFilename.search(/\.\w{1,10}$/) == -1) {
								// User did not specify extension. Use current
								var oldExt = item.getFilename().match(/\.\w{1,10}$/);
								if (oldExt) newFilename += oldExt[0];
							}
							var renamed = item.renameAttachmentFile(newFilename);
							if (renamed == -1) {
								var confirmed = nsIPS.confirm(
									window,
									'',
									newFilename + ' exists. Overwrite existing file?'
								);
								if (!confirmed) {
									// If they said not to overwrite existing file,
									// start again
									continue;
								}
								
								// Force overwrite, but make sure we check that this doesn't fail
								renamed = item.renameAttachmentFile(newFilename, true);
							}
							
							if (renamed == -2) {
								nsIPS.alert(
									window,
									Zotero.getString('general.error'),
									Zotero.getString('pane.item.attachments.rename.error')
								);
								return;
							}
							else if (!renamed) {
								nsIPS.alert(
									window,
									Zotero.getString('pane.item.attachments.fileNotFound.title'),
									Zotero.getString('pane.item.attachments.fileNotFound.text')
								);
							}
						}
						
						break;
					}
					
					if (newTitle.value != oldTitle) {
						item.setField('title', newTitle.value);
						item.save();
					}
				]]>
				</body>
			</method>
			
			
			<method name="onViewClick">
				<parameter name="event"/>
				<body>
				<![CDATA[
					ZoteroPane_Local.viewAttachment(this.item.id, event, !this.editable);
				]]>
				</body>
			</method>
			
			
			<method name="onShowClick">
				<parameter name="event"/>
				<body>
				<![CDATA[
					ZoteroPane_Local.showAttachmentInFilesystem(this.item.id, event.originalTarget, !this.editable);
				]]>
				</body>
			</method>
			
			
			<!--
			 Update Indexed: (Yes|No|Partial) line
			-->
			<method name="updateItemIndexedState">
				<body><![CDATA[
					return Zotero.spawn(function* () {
						var indexStatus = this._id('index-status');
						var reindexButton = this._id('reindex');
						
						var status = yield Zotero.Fulltext.getIndexedState(this.item);
						var str = 'fulltext.indexState.';
						switch (status) {
							case Zotero.Fulltext.INDEX_STATE_UNAVAILABLE:
								str += 'unavailable';
								break;
							case Zotero.Fulltext.INDEX_STATE_UNINDEXED:
								str = 'general.no';
								break;
							case Zotero.Fulltext.INDEX_STATE_PARTIAL:
								str += 'partial';
								break;
							case Zotero.Fulltext.INDEX_STATE_INDEXED:
								str = 'general.yes';
								break;
						}
						this._id("index-status-label").value = Zotero.getString('fulltext.indexState.indexed')
							+ Zotero.getString('punctuation.colon');
						indexStatus.value = Zotero.getString(str);
						
						// Reindex button tooltip (string stored in zotero.properties)
						var str = Zotero.getString('pane.items.menu.reindexItem');
						reindexButton.setAttribute('tooltiptext', str);
						
						if (this.editable && (yield Zotero.Fulltext.canReindex(this.item))) {
							reindexButton.setAttribute('hidden', false);
						}
						else {
							reindexButton.setAttribute('hidden', true);
						}
					}, this);
				]]></body>
			</method>
			
			
			<method name="_id">
				<parameter name="id"/>
				<body>
				<![CDATA[
					return document.getAnonymousNodes(this)[0].getElementsByAttribute('id', id)[0];
				]]>
				</body>
			</method>
		</implementation>
		
		<content>
			<vbox id="attachment-box" flex="1" orient="vertical"
				 	xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
				<label id="title"/>
				<label id="url" crop="end"
					ondragstart="var dt = event.dataTransfer; dt.setData('text/x-moz-url', this.value); dt.setData('text/uri-list', this.value); dt.setData('text/plain', this.value);"/>
				<grid>
					<columns>
						<column/>
						<column flex="1"/>
					</columns>
					<rows>
						<row id="fileNameRow">
							<label id="fileName-label"/>
							<label id="fileName" crop="end"/>
						</row>
						<row id="accessedRow">
							<label id="accessed-label"/>
							<label id="accessed"/>
						</row>
						<row id="pagesRow">
							<label id="pages-label"/>
							<label id="pages"/>
						</row>
						<row id="dateModifiedRow">
							<label id="dateModified-label"/>
							<label id="dateModified"/>
						</row>
						<row id="indexStatusRow">
							<label id="index-status-label"/>
							<hbox>
								<label id="index-status"/>
								<image id="reindex" onclick="this.hidden = true; setTimeout(function () { ZoteroPane_Local.reindexItem(); }, 50)"/>
							</hbox>
						</row>
					</rows>
				</grid>
				
				<zoteronoteeditor id="attachment-note-editor" notitle="1" flex="1"/>
				
				<button id="select-button" hidden="true"/>
			</vbox>
		</content>
	</binding>
</bindings>
