<?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">

<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"
		  xmlns:html="http://www.w3.org/1999/xhtml">
	
	<binding id="merge-group">
		<resources>
			<stylesheet src="chrome://zotero/skin/merge.css"/>
		</resources>
		
		<implementation>
			<constructor>
			<![CDATA[
				this._leftpane = this._id('leftpane');
				this._rightpane = this._id('rightpane');
				this._mergepane = this._id('mergepane');
			]]>
			</constructor>
			
			<field name="libraryID"/>
			
			<field name="_data"/>
			<property name="data" onget="return this._data;">
				<setter>
				<![CDATA[
					this._data = val;
					this.refresh();
				]]>
				</setter>
			</property>
			
			<property name="merged" onget="return this._mergepane.data"/>
			
			<field name="_type"/>
			<property name="type" onget="return this._type;">
				<setter>
				<![CDATA[
					switch (val) {
						case 'item':
						case 'attachment':
						case 'note':
						case 'file':
							break;
						
						default:
							throw new Error(`Unsupported merge object type '${type}'`);
					}
					
					this._type = val;
					var hbox = document.getAnonymousNodes(this)[0];
					hbox.setAttribute('mergetype', val);
				]]>
				</setter>
			</property>
			
			<property name="leftCaption" onset="this._leftpane.caption.label = val"/>
			<property name="rightCaption" onset="this._rightpane.caption.label = val"/>
			<property name="mergeCaption" onset="this._mergepane.caption.label = val"/>
			
			<field name="_leftpane"/>
			<property name="leftpane" onget="return this._leftpane"/>
			<field name="_rightpane"/>
			<property name="rightpane" onget="return this._rightpane"/>
			<field name="_mergepane"/>
			<property name="mergepane" onget="return this._mergepane"/>
			
			<property name="onSelectionChange"/>
			
			<method name="refresh">
				<body>
				<![CDATA[
					if (this._data.left.deleted && this._data.right.deleted) {
						throw new Error("'left' and 'right' cannot both be deleted");
					}
					
					// Check for note or attachment
					if (!this.type) {
						this.type = this._getTypeFromObject(
							this._data.left.deleted ?  this._data.right : this._data.left
						);
					}
					
					var showButton = this.type != 'item';
					
					this._leftpane.showButton = showButton;
					this._rightpane.showButton = showButton;
					this._leftpane.libraryID = this.libraryID;
					this._rightpane.libraryID = this.libraryID;
					this._mergepane.libraryID = this.libraryID;
					this._leftpane.data = this._data.left;
					this._rightpane.data = this._data.right;
					this._mergepane.data = this._data.merge;
					
					if (this._data.selected == 'left') {
						this.choosePane(this._leftpane);
					}
					else {
						this.choosePane(this._rightpane);
					}
					
					/*
					
					Code to display only the different values -- not used
					
					var diff = this._leftpane.ref.diff(this._rightpane.ref, true);
					
					var fields = [];
					var diffFields = [];
					for (var field in diff[0].primary) {
						fields.push(field);
						if (diff[0].primary[field] != diff[1].primary[field]) {
							diffFields.push(field);
						}
					}
					for (var field in diff[0].fields) {
						fields.push(field);
						if (diff[0].fields[field] != diff[1].fields[field]) {
							diffFields.push(field);
						}
					}
					
					this._leftpane.objectbox.fieldOrder = fields;
					this._rightpane.objectbox.fieldOrder = fields;
					
					// Display merge pane if item types match
					if (this._leftpane.ref.itemTypeID == this._rightpane.ref.itemTypeID) {
						this._leftpane.objectbox.visibleFields = fields;
						this._rightpane.objectbox.visibleFields = fields;
						
						this._leftpane.objectbox.clickable = false;
						this._rightpane.objectbox.clickable = false;
						this._leftpane.objectbox.clickableFields = diffFields;
						this._rightpane.objectbox.clickableFields = diffFields;
						
						var mergeItem = new Zotero.Item(this._leftpane.ref.itemTypeID);
						this._mergepane.ref = mergeItem;
						this._mergepane.objectbox.visibleFields = fields;
					}
					// Otherwise only allow clicking on item types
					else {
						this._leftpane.objectbox.clickableFields = ['itemType'];
						this._rightpane.objectbox.clickableFields = ['itemType'];
					}
					*/
					
					
					this._mergepane.objectbox.editable = true;
					
					
					/*
					
					No need to refresh if not comparing fields
					
					this._leftpane.objectbox.refresh();
					this._rightpane.objectbox.refresh();
					*/
				]]>
				</body>
			</method>
			
			
			<method name="choosePane">
				<parameter name="pane"/>
				<body>
				<![CDATA[
					if (pane.getAttribute('anonid') == 'leftpane') {
						var position = 'left';
						var otherPane = this._rightpane;
					}
					else {
						var position = 'right';
						var otherPane = this._leftpane;
					}
					
					pane.removeAttribute("selected");
					otherPane.removeAttribute("selected");
					pane.setAttribute("selected", "true");
					
					if (pane.deleted) {
						this._mergepane.deleted = true;
					}
					else {
						this._mergepane.data = pane.data;
					}
					
					if (this.onSelectionChange) {
						this.onSelectionChange();
					}
				]]>
				</body>
			</method>
			
			
			<method name="_getTypeFromObject">
				<parameter name="obj"/>
				<body>
				<![CDATA[
					if (!obj.itemType) {
						Zotero.debug(obj, 1);
						throw new Error("obj is not item JSON");
					}
					if (obj.itemType == 'attachment' || obj.itemType == 'note') {
						return obj.itemType;
					}
					return 'item';
				]]>
				</body>
			</method>
			
			<method name="_id">
				<parameter name="id"/>
				<body>
				<![CDATA[
					return document.getAnonymousNodes(this)[0].getElementsByAttribute('anonid',id)[0];
				]]>
				</body>
			</method>
		</implementation>
		
		<content>
			<xul:hbox id="merge-group" flex="1">
				<xul:zoteromergepane anonid="leftpane" flex="1"/>
				<xul:zoteromergepane anonid="rightpane" flex="1"/>
				<xul:zoteromergepane anonid="mergepane" flex="1"/>
			</xul:hbox>
		</content>
	</binding>
	
	
	<binding id="merge-pane">
		<resources>
			<stylesheet src="chrome://zotero/skin/bindings/merge.css"/>
		</resources>
		
		<implementation>
			<constructor>
			<![CDATA[
				this.parent = document.getBindingParent(this.parentNode);
				this.isMergePane = this.getAttribute('anonid') == 'mergepane';
				
				if (!this.isMergePane) {
					this.pane.onclick = function () {
						this.parent.choosePane(this);
					}.bind(this);
				}
			]]>
			</constructor>
			
			<property name="type" onget="return this.parent.type" readonly="true"/>
			<property name="caption" onget="return this._id('caption')" readonly="true"/>
			<field name="showButton"/>
			<property name="pane" onget="return document.getAnonymousNodes(this)[0]"/>
			<property name="objectbox" onget="return this._id('objectbox')" readonly="true"/>
			
			<field name="_deleted"/>
			<property name="deleted">
				<setter>
				<![CDATA[
					this._deleted = !!val;
					
					var placeholder = this._id('object-placeholder');
					if (placeholder) {
						placeholder.hidden = !!val;
					}
					else {
						this._id('objectbox').hidden = true;
					}
					var deleteBox = this._id('delete-box');
					deleteBox.hidden = !val;
				]]>
				</setter>
			</property>
			
			<field name="libraryID"/>
			
			<field name="_data"/>
			<property name="data" onget="return this._data">
				<setter>
				<![CDATA[
					this._data = val;
					
					var button = this._id('choose-button');
					button.label = Zotero.getString('sync.conflict.chooseThisVersion');
					if (this.showButton) {
						button.onclick = () => this.parent.choosePane(this);
						button.style.visibility = 'visible';
					}
					else {
						button.style.visibility = 'hidden';
					}
					
					if (val.deleted) {
						this.deleted = true;
						return;
					}
					
					this.deleted = false;
					
					// Replace XUL placeholder with XUL object box of given type
					var elementName;
					switch (this.type) {
						case 'item':
							elementName = 'zoteroitembox';
							break;
						
						case 'attachment':
						case 'file':
							elementName = 'zoteroattachmentbox';
							break;
						
						case 'note':
							elementName = 'zoteronoteeditor';
							break;
						
						default:
							throw new Error("Object type '" + this.type + "' not supported");
					}
					
					var objbox = document.createElement(elementName);
					
					var parentRow = this._id('parent-row');
					if (val.parentItem) {
						parentRow.textContent = '';
						
						let label = document.createElement('span');
						label.textContent = Zotero.getString('pane.item.parentItem');
						parentRow.appendChild(label);
						
						let parentItem = Zotero.Items.getByLibraryAndKey(this.libraryID, val.parentItem);
						let text = document.createTextNode(" " + parentItem.getDisplayTitle(true));
						parentRow.appendChild(text);
						
						parentRow.hidden = false;
					}
					else {
						parentRow.hidden = true;
					}
					
					if (this._id('object-placeholder')) {
						var placeholder = this._id('object-placeholder');
						placeholder.parentNode.replaceChild(objbox, placeholder);
					}
					else {
						var oldObjBox = this._id('objectbox');
						oldObjBox.parentNode.replaceChild(objbox, oldObjBox);
					}
					
					objbox.setAttribute("anonid", "objectbox");
					objbox.setAttribute("flex", "1");
					objbox.mode = this.type == 'file' ? 'filemerge' : 'merge';
					
					// Store JSON
					this._data = val;
					
					// Create a copy of the JSON that we can clean for display, since the remote object
					// might reference things that don't exist locally
					var displayJSON = Object.assign({}, val);
					displayJSON.collections = [];
					
					// Create item from JSON for metadata box
					var item = new Zotero.Item(val.itemType);
					item.libraryID = this.libraryID;
					item.fromJSON(displayJSON);
					objbox.item = item;
				]]>
				</setter>
			</property>
			
			<field name="parent"/>
			
			<method name="click">
				<body><![CDATA[
					this.pane.click();
				]]></body>
			</method>
			
			<method name="_id">
				<parameter name="id"/>
				<body>
				<![CDATA[
					var elems = document.getAnonymousNodes(this)[0].getElementsByAttribute('anonid', id);
					return elems.length ? elems[0] : false;
				]]>
				</body>
			</method>
		</implementation>
		
		<content>
			<xul:vbox flex="1">
				<xul:groupbox anonid="merge-pane" flex="1">
					<xul:caption anonid="caption"/>
					<html:div anonid="parent-row" hidden="true"/>
					<xul:box anonid="object-placeholder"/>
					<xul:hbox anonid="delete-box" hidden="true" flex="1">
						<xul:label value="&zotero.merge.deleted;"/>
					</xul:hbox>
				</xul:groupbox>
				<xul:button anonid="choose-button"/>
			</xul:vbox>
		</content>
	</binding>
</bindings>
