/*
 * org.openmicroscopy.shoola.agents.metadata.editor.GeneralPaneUI 
 *
 *------------------------------------------------------------------------------
 *  Copyright (C) 2006-2014 University of Dundee. All rights reserved.
 *
 *
 * 	This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *  This program 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 General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *------------------------------------------------------------------------------
 */
package org.openmicroscopy.shoola.agents.metadata.editor;


//Java imports
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;

import org.apache.commons.collections.CollectionUtils;
//Third-party libraries
import org.jdesktop.swingx.JXTaskPane;
import org.jdesktop.swingx.JXTaskPaneContainer;
import org.jdesktop.swingx.VerticalLayout;

//Application-internal dependencies
import org.openmicroscopy.shoola.agents.metadata.browser.Browser;
import org.openmicroscopy.shoola.agents.metadata.util.DataToSave;
import org.openmicroscopy.shoola.agents.util.EditorUtil;
import org.openmicroscopy.shoola.agents.util.editorpreview.PreviewPanel;
import org.openmicroscopy.shoola.util.ui.UIUtilities;
import pojos.AnnotationData;
import pojos.BooleanAnnotationData;
import pojos.DataObject;
import pojos.DatasetData;
import pojos.DoubleAnnotationData;
import pojos.FileAnnotationData;
import pojos.ImageData;
import pojos.LongAnnotationData;
import pojos.ProjectData;
import pojos.ScreenData;
import pojos.TagAnnotationData;
import pojos.TermAnnotationData;
import pojos.TextualAnnotationData;
import pojos.WellSampleData;
import pojos.XMLAnnotationData;

/** 
 * Component displaying the annotation.
 *
 * @author  Jean-Marie Burel &nbsp;&nbsp;&nbsp;&nbsp;
 * <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
 * @author Donald MacDonald &nbsp;&nbsp;&nbsp;&nbsp;
 * <a href="mailto:donald@lifesci.dundee.ac.uk">donald@lifesci.dundee.ac.uk</a>
 * @version 3.0
 * <small>
 * (<b>Internal version:</b> $Revision: $Date: $)
 * </small>
 * @since 3.0-Beta4
 */
class GeneralPaneUI 
	extends JPanel//JScrollPane
{

	/** The default text. */
	private static final String			DETAILS = "'s details";
	
	/** The protocols title. */
	private static final String			PROTOCOL = "Protocols and Experiments";
	
	/** Reference to the controller. */
	private EditorControl				controller;
	
	/** Reference to the Model. */
	private EditorModel					model;
	
	/** Reference to the Model. */
	private EditorUI					view;
	
	/** The UI component displaying the object's properties. */
	private PropertiesUI				propertiesUI;
	
	/** The UI component displaying the textual annotations. */
	private TextualAnnotationsUI		textualAnnotationsUI;
	
	/** Component hosting the tags, rating, URLs and attachments. */
	private AnnotationDataUI			annotationUI;
	
	/** The component hosting the {@link #browser}. */
	private JXTaskPane 					browserTaskPane;

	/** The component hosting the {@link #propertiesUI}. */
	private JXTaskPane 					propertiesTaskPane;
	
	/** The component hosting the annotation component. */
	private JXTaskPane 					annotationTaskPane;
	
	/** Collection of annotations UI components. */
	private List<AnnotationUI>			components;

	/** The component hosting the various protocols. */
	private JXTaskPane					protocolTaskPane;
	
	/** Collection of preview panels. */
	private List<PreviewPanel>			previews;
	
	/** Flag indicating to build the UI once. */
	private boolean 					init;

	/** The container hosting the <code>JXTaskPane</code>. */
	private JXTaskPaneContainer 		container;
	
	/** The tool bar.*/
	private ToolBar toolbar;
	
	/**;
	 * Loads or cancels any on-going loading of containers hosting
	 * the edited object.
	 * 
	 * @param b Pass <code>true</code> to load, <code>false</code> to cancel.
	 */
	private void loadParents(boolean b)
	{
		if (b) controller.loadParents();
		else model.cancelParentsLoading();
	}
	
    /** Initializes the UI components. */
	private void initComponents()
	{
		container  = new JXTaskPaneContainer();
		container.setBackground(UIUtilities.BACKGROUND);
		if (container.getLayout() instanceof VerticalLayout) {
			VerticalLayout vl = (VerticalLayout) container.getLayout();
			vl.setGap(0);
		}
		if (model.getBrowser() != null) {
			browserTaskPane = EditorUtil.createTaskPane(Browser.TITLE);
			browserTaskPane.add(model.getBrowser().getUI());
			browserTaskPane.addPropertyChangeListener(controller);
		}
		
		protocolTaskPane = EditorUtil.createTaskPane(PROTOCOL);
		
		propertiesUI = new PropertiesUI(model, controller);
		textualAnnotationsUI = new TextualAnnotationsUI(model, controller);
		annotationUI = new AnnotationDataUI(view, model, controller);

		components = new ArrayList<AnnotationUI>();
		components.add(propertiesUI);
		components.add(textualAnnotationsUI);
		components.add(annotationUI);
		Iterator<AnnotationUI> i = components.iterator();
		while (i.hasNext()) {
			i.next().addPropertyChangeListener(EditorControl.SAVE_PROPERTY,
											controller);
		}
		previews = new ArrayList<PreviewPanel>();
		propertiesTaskPane = EditorUtil.createTaskPane("");
		propertiesTaskPane.setCollapsed(false);
		propertiesTaskPane.add(propertiesUI);
		annotationTaskPane = EditorUtil.createTaskPane("Annotations");
		annotationTaskPane.setCollapsed(false);
		JPanel p = new JPanel();
		p.setBackground(UIUtilities.BACKGROUND_COLOR);
		p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
		p.add(annotationUI);
		p.add(textualAnnotationsUI);
		annotationTaskPane.add(p);
	}
	
	/** The Component hosting the container.*/
	private JScrollPane pane;
	
	/** Builds and lays out the components. */
	private void buildGUI()
	{
		setLayout(new BorderLayout(0, 0));
		container.add(propertiesTaskPane);
		container.add(annotationTaskPane);
		pane = new JScrollPane();
		JViewport viewport = pane.getViewport();
		viewport.add(container);
		viewport.setBackground(UIUtilities.BACKGROUND_COLOR);
		add(toolbar, BorderLayout.NORTH);
    	add(pane, BorderLayout.CENTER);
	}
	
	/** 
	 * Lays out the protocols files. Returns the components hosting the 
	 * files.
	 * 
	 * @return See above.
	 */
	private JXTaskPaneContainer buildProtocolTaskPanes()
	{
		Collection list = model.getAttachments();
		if (list.size() == 0) return null;
		JXTaskPaneContainer paneContainer = new JXTaskPaneContainer();
		VerticalLayout vl = (VerticalLayout) paneContainer.getLayout();
		vl.setGap(0);
		paneContainer.setBackground(UIUtilities.BACKGROUND_COLOR);

		Iterator i = list.iterator();
		FileAnnotationData fa;
		JXTaskPane pane;
		PreviewPanel preview;
		String description;
		String ns;
		int index = 0;
		previews.clear();
		boolean b;
		while (i.hasNext()) {
			fa = (FileAnnotationData) i.next();
			ns = fa.getNameSpace();
			b = annotationUI.isEditorFile(fa.getFileName());
			if (!b) b = annotationUI.isEditorFile(ns);
			if (fa.getId() > 0 && b) {
				description = fa.getDescription();
				if (description != null) {
					preview = new PreviewPanel(description, fa.getId());
					previews.add(preview);
					preview.addPropertyChangeListener(controller);
					pane = EditorUtil.createTaskPane(fa.getFileName());
					pane.addPropertyChangeListener(controller);
					pane.add(preview);
					paneContainer.add(pane);
					index++;
				}
			}
		}
		if (index == 0) return null;
		return paneContainer;
	}
	
	/**
	 * Creates a new instance.
	 * 
	 * @param view			Reference to the View. Mustn't be <code>null</code>.
	 * @param model			Reference to the Model. 
	 * 						Mustn't be <code>null</code>.
	 * @param controller	Reference to the Control. 
	 * 						Mustn't be <code>null</code>.
	 * @param tooBar 		The tool Bar
	 */
	GeneralPaneUI(EditorUI view, EditorModel model, EditorControl controller, 
			ToolBar toolBar)
	{
		if (model == null)
			throw new IllegalArgumentException("No model.");
		if (controller == null)
			throw new IllegalArgumentException("No control.");
		if (view == null)
			throw new IllegalArgumentException("No view.");
		this.model = model;
		this.controller = controller;
		this.toolbar = toolBar;
		this.view = view;
		initComponents();
		init = false;
	}

	/** Lays out the UI when data are loaded. */
	void layoutUI()
	{
		if (!init) {
			buildGUI();
			init = true;
		}
		propertiesUI.buildUI();
		annotationUI.buildUI();
		textualAnnotationsUI.buildUI();
		propertiesTaskPane.setTitle(propertiesUI.getText()+DETAILS);

	
		//TableLayout layout = (TableLayout) content.getLayout();
		
		double h = 0;
		String s = Browser.TITLE;
		boolean multi = model.isMultiSelection();
		Object refObject = model.getRefObject();
		if (refObject instanceof TagAnnotationData) {
			TagAnnotationData tag = (TagAnnotationData) refObject;
			if (TagAnnotationData.INSIGHT_TAGSET_NS.equals(
					tag.getNameSpace())) {
				browserTaskPane.setCollapsed(true);
			} else {
				if (!multi) {
					h = 1;
				}
			}
		} else if (refObject instanceof FileAnnotationData) {
			if (!multi) {
				h = 1;
				s = "Attached to...";
			}
		} else if (refObject instanceof DatasetData) {
			if (!multi) {
				h = 1;
			}
		} else if (refObject instanceof ImageData) {
			if (!multi) {
				h = 1;
				propertiesUI.onChannelDataLoading();
				controller.loadChannelData();
			}
		} else if (refObject instanceof WellSampleData) {
			if (!multi) controller.loadChannelData();
		} else if ((refObject instanceof ProjectData) || 
				(refObject instanceof ScreenData) ||
				(refObject instanceof WellSampleData)) {
			browserTaskPane.setCollapsed(true);
		}
		browserTaskPane.setTitle(s);
		container.remove(browserTaskPane);
		if (protocolTaskPane != null) {
			container.remove(protocolTaskPane);
			protocolTaskPane.removeAll();
		}
		JComponent n = buildProtocolTaskPanes();
		if (n != null) {
			protocolTaskPane.add(n);
			container.add(protocolTaskPane);
		}
		container.remove(propertiesTaskPane);
		if (!multi) {
			container.add(propertiesTaskPane, 0); //first index
		}
		if (h > 0) {
			container.add(browserTaskPane);
			if (!browserTaskPane.isCollapsed())
				loadParents(true);
		}
	}
	
	/**
	* Get a reference to the PropertiesUI
	* 
	* @return See above
	*/
	public PropertiesUI getPropertiesUI() {
            return propertiesUI;
        }

    	/** 
	 * Returns the object hosting the annotation/link to save.
	 * 
	 * @return See above.
	 */
	DataToSave prepareDataToSave()
	{
		if (!model.isMultiSelection()) propertiesUI.updateDataObject();
		List<AnnotationData> toAdd = new ArrayList<AnnotationData>();
		List<Object> toRemove = new ArrayList<Object>();
		List<AnnotationData> l = annotationUI.getAnnotationToSave();
		//To add
		if (CollectionUtils.isNotEmpty(l))
			toAdd.addAll(l);
		l = textualAnnotationsUI.getAnnotationToSave();
		if (CollectionUtils.isNotEmpty(l))
			toAdd.addAll(l);
		//To remove
		List<Object> ll = annotationUI.getAnnotationToRemove();
		if (CollectionUtils.isNotEmpty(ll))
			toRemove.addAll(ll);
		ll = textualAnnotationsUI.getAnnotationToRemove();
		if (CollectionUtils.isNotEmpty(ll))
			toRemove.addAll(ll);
		
		return new DataToSave(toAdd, toRemove);
	}
	
	/** Updates display when the parent of the root node is set. */
	void setParentRootObject()
	{
		propertiesUI.setParentRootObject();
	}
	
	/** 
	 * Updates display when the new root node is set.
	 * 
	 *  @param oldObject The object previously selected.
	 */
	void setRootObject(Object oldObject)
	{
		if (!init) {
			buildGUI();
			init = true;
		}	
		clearData(oldObject);
		textualAnnotationsUI.clearDisplay();
		propertiesUI.clearDisplay();
		annotationUI.clearDisplay();
    	textualAnnotationsUI.clearDisplay();
    	//propertiesUI.buildUI();
    	Object uo = model.getRefObject();
    	
    	int annotation = 0;
    	if (!(uo instanceof AnnotationData)) { //hide everything
    		annotation = 1;
    	}
		container.remove(annotationTaskPane);
		//container.remove(protocolTaskPane);
		if (annotation > 0) 
			container.add(annotationTaskPane);
		/*
		if (protocolTaskPane.getComponentCount() > 0)
			container.add(protocolTaskPane);
		*/
		revalidate();
		repaint();
	}
	
	/**
	 * Returns the list of tags currently selected by the user.
	 * 
	 * @return See above.
	 */
	List<TagAnnotationData> getCurrentTagsSelection()
	{
		return annotationUI.getCurrentTagsSelection();
	}
	
	/**
	 * Returns the list of attachments currently selected by the user.
	 * 
	 * @return See above.
	 */
	List<FileAnnotationData> getCurrentAttachmentsSelection() 
	{
		return annotationUI.getCurrentAttachmentsSelection();
	}
	
	/** Shows the image's info. */
    void setChannelData()
    { 
    	Object refObject = model.getRefObject();
    	if ((refObject instanceof ImageData) || 
    			(refObject instanceof WellSampleData))
    		propertiesUI.setChannelData(model.getChannelData());
    }
    
	/**
	 * Returns <code>true</code> if data to save, <code>false</code>
	 * otherwise.
	 * 
	 * @return See above.
	 */
	boolean hasDataToSave()
	{
		Iterator<AnnotationUI> i = components.iterator();
		AnnotationUI ui;
		while (i.hasNext()) {
			ui = i.next();
			if (ui.hasDataToSave())
				return true;
		}
		Iterator<PreviewPanel> p = previews.iterator();
		PreviewPanel pp;
		while (p.hasNext()) {
			pp = p.next();
			if (pp.hasDataToSave()) return true;
		}
		return false;
	}
	
	/** 
	 * Clears data to save.
	 * 
	 * @param oldObject The previously selected object.
	 */
	void clearData(Object oldObject)
	{
		Iterator<AnnotationUI> i = components.iterator();
		AnnotationUI ui;
		while (i.hasNext()) {
			ui = i.next();
			ui.clearData(oldObject);
			ui.clearDisplay();
		}
		setCursor(Cursor.getDefaultCursor());
	}
	
	/**
	 * Handles the expansion or collapsing of the passed component.
	 * 
	 * @param source The component to handle.
	 */
	void handleTaskPaneCollapsed(JXTaskPane source)
	{
		if (source == null) return;
		if  (source.equals(browserTaskPane)) 
			loadParents(!browserTaskPane.isCollapsed());
	}

	/**
	 * Attaches the passed files.
	 * Returns <code>true</code> if the files
	 * do not already exist, <code>false</code> otherwise.
	 * 
	 * @param files The files to attach.
	 * @return See above
	 */
	boolean attachFiles(File[] files)
	{ 
		return annotationUI.attachFiles(files); 
	}

	/**
	 * Removes the passed file from the display.
	 * 
	 * @param file The file to remove.
	 */
	void removeAttachedFile(Object file)
	{ 
		annotationUI.removeAttachedFile(file);
	}
	
	/**
	 * Returns the collection of attachments.
	 * 
	 * @return See above.
	 */
	List<FileAnnotationData> removeAttachedFiles()
	{
		return annotationUI.removeAttachedFiles();
	}
	
	/**
	 * Returns the collection of tags.
	 * 
	 * @return See above.
	 */
	List<TagAnnotationData> removeTags()
	{
		return annotationUI.removeTags();
	}
	
	/**
	 * Returns the collection of other annotation.
	 * 
	 * @return See above.
	 */
	List<AnnotationData> removeOtherAnnotations()
	{
		return annotationUI.removeOtherAnnotation();
	}
	
	/**
	 * Returns <code>true</code> some tags can be unlinked,
	 * <code>false</code> otherwise.
	 * 
	 * @return See above.
	 */
	boolean hasAttachmentsToUnlink()
	{ 
		return annotationUI.hasAttachmentsToUnlink();
	}
	
	/**
	 * Returns <code>true</code> some tags can be unlinked,
	 * <code>false</code> otherwise.
	 * 
	 * @return See above.
	 */
	boolean hasTagsToUnlink()
	{
		return annotationUI.hasTagsToUnlink();
	}
	
	/**
	 * Returns <code>true</code> some other annotations can be unlinked,
	 * <code>false</code> otherwise.
	 * 
	 * @return See above.
	 */
	boolean hasOtherAnnotationsToUnlink()
	{
		return annotationUI.hasOtherAnnotationsToUnlink();
	}
	
	/**
	 * Removes the annotation from the view.
	 * 
	 * @param annotation The annotation to remove.
	 */
	void removeObject(DataObject annotation)
	{
		if (annotation == null) return;
		if (annotation instanceof TagAnnotationData ||
			annotation instanceof TermAnnotationData ||
			annotation instanceof XMLAnnotationData ||
			annotation instanceof LongAnnotationData ||
			annotation instanceof DoubleAnnotationData ||
			annotation instanceof BooleanAnnotationData)
			annotationUI.removeAnnotation((AnnotationData) annotation);
		else if (annotation instanceof TextualAnnotationData)
			textualAnnotationsUI.removeTextualAnnotation(
					(TextualAnnotationData) annotation);
	}
	
	/**
	 * Handles the selection of objects via the selection wizard.
	 * 
	 * @param type		The type of objects to handle.
	 * @param objects   The objects to handle.
	 */
	void handleObjectsSelection(Class type, Collection objects)
	{
		if (objects == null) return;
		annotationUI.handleObjectsSelection(type, objects, true);
	}
	
	/** Updates the UI when the related nodes have been set.*/
	void onRelatedNodesSet()
	{
		annotationUI.onRelatedNodesSet();
	}

	void setExtentWidth(int width)
	{
		if (propertiesUI != null)
			propertiesUI.setExtentWidth(width);
	}
	
}
