/**
 * Project      : Artenum
 * (c)Copyright :     Artenum SARL, 24 rue Louis Blanc
 *                    75010, Paris, France 2009-2010.
 *                    http://www.artenum.com
 *                    e-mail: contact@artenum.com
 * All copyright and trademarks reserved.
 * License      : cf. LICENSE.txt
 * Developed by : Artenum SARL
 * 								http://www.artenum.com
 * Creation     : Febrary 2011
 * Main author  : J.Forest, B.Thiebault, J.Turbet
 */
package com.artenum.cassandra.util;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

/**
 * Generic Bookmark Manager. <br>
 * <br>
 * This class allows to manager bookmarks (currently files only) and display them into a 
 * specific JMenu. Each new bookmarked file is added into an internal ArrayList and displayed
 * as a new FileItem, which is an extend JMenuItem with a file linked to it. <br>
 * <br>
 * The list of bookmarks is automatically saved/read from the Java preferences, with the 
 * PROPERTIES_PREFIX key as prefix and the index of the bookmark (i.e com.artenum.cassandra.bookmarks.0)
 * as property key. <br>
 * <br>
 * It is possible to add a new action listener to facilitate the integration of the bookmark manager
 * in your code. Every time a bookmark is selected, the SELECTED_MARK_ACTION command is performed
 * and the selected FileItem is updated and available via its getters. <br>
 * <br>
 * The typical instantiation and use is the following one: <br>
 * 
 * <pre>
 * {@code
 * bookmarkManager = new BookmarkManager(); 
 * bookmarkManager.setAutoSave(false); 
 * bookmarkManager.readBookmarkListFromProperties();
 * bookmarkManager.setAutoSave(true);
 * bookmarkManager.addActionListener(listener);
 * }
 * </pre>
 * 
 * And to recover the selected file:
 * 
 * <pre>
 * {@code
 * if (actionCommand.equals(bookmarkManager.SELECTED_MARK_ACTION)){
 *     File selectedFile = bookmarkManager.getSelectedItem().getFile();
 *     }
 *  }
 * </pre>
 *  
 * @author J.Forest
 * @author B.Thiebault
 * @author J.Turbet
 *
 * @version 1.0
 * 
 */
public class BookmarkManager extends JMenu implements ActionListener {


	private static final long serialVersionUID = 1L;
	
	public final static String PROPERTIES_PREFIX = "com.artenum.cassandra.bookmarks";
	public static final String ADD_BOOKMARK_ACTION = "add.bookmark.action";
	public static final String MANAGE_ACTION = "manage.items";
	public static final String REMOVE_BOOKMARK_ACTION = "remove.bookmark";
	public static final String CANCEL_BOOKMARK_ACTION = "cancel.bookmark.action";
	public static final String SELECTED_BOOKMARK_ACTION = "selected.bookmark.action";
	public final String LENGTH_FLAG = "length";
	private ArrayList<File> bookmark;
	private boolean autoSave = true;
	
	private JFrame managmentFrame;
	private JList marksList;
	
	private FileItem selectedItem; 
	
	private ArrayList<ActionListener> externalActionListener;
	
    /**
     * main constructor. 
     */
	public BookmarkManager() {
		bookmark = new ArrayList<File>();
		externalActionListener = new ArrayList<ActionListener>();
		
		this.setText("Bookmark");
		
		JMenuItem bookmarkItem = new JMenuItem("Add bookmark");
		bookmarkItem.addActionListener(this);
		bookmarkItem.setActionCommand(ADD_BOOKMARK_ACTION);
		this.add(bookmarkItem);
		
		JMenuItem manageItem = new JMenuItem("Remove bookmark");
		manageItem.addActionListener(this);
		manageItem.setActionCommand(MANAGE_ACTION);
		this.add(manageItem);
		
		this.addSeparator();
	}
	
	
	public void addActionListener(ActionListener listener){
		super.addActionListener(listener);
		externalActionListener.add(listener);
		for (int i=0; i<this.getItemCount(); i++){
			if (this.getItem(i) != null){
			this.getItem(i).addActionListener(listener);
			}
		}
	}
	
	/**
	 * Save the list of files into the Java Properties. 
	 * By default, this method is automatically called when the method addReference is called.
	 * To avoid this, set before the autoSave flag to false.
	 */
	public void saveBookmarkListToProperties() {
		File file;
		
		// save the size of the current bookmark
		java.util.prefs.Preferences.userRoot().putInt(PROPERTIES_PREFIX + "." + LENGTH_FLAG, this.bookmark.size());
		
		//save the bookmark
		Iterator<File> iter = this.bookmark.iterator();
		while (iter.hasNext()) {
			file = iter.next();
			java.util.prefs.Preferences.userRoot().put(PROPERTIES_PREFIX + "." + this.bookmark.indexOf(file), file.getAbsolutePath());
		}
	}
	
	
	/**
	 * read the file list from the java properties.
	 */
	public void readBookmarkListFromProperties() {
		// read the size of the previously saved bookmark
		int bookMarkTmpSize = java.util.prefs.Preferences.userRoot().getInt(PROPERTIES_PREFIX + "." + LENGTH_FLAG, 0);
		// read the saved files/paths
		for (int i = 0; i < bookMarkTmpSize; i++) {
			addBookmark(new File(java.util.prefs.Preferences.userRoot().get(PROPERTIES_PREFIX + "." + i, new File(".").getAbsolutePath())));
		}		
	}

	/**
	 * Add a reference (i.e path or file) to the bookmark. By default the 
	 * Java Properties are automatically updated in order to save the list of
	 * bookmarked files. To avoid this, set before the autoSave flag to false. 
	 * @param file
	 */
	public void addBookmark(File file) {
		bookmark.add(file);
		updateView(file);
		if( autoSave ){
			saveBookmarkListToProperties();
		}
	}
	
	private void updateView(File file){
		FileItem item = new FileItem();
		item.setFile(file);
		item.setText(file.getAbsolutePath());
		item.setActionCommand(SELECTED_BOOKMARK_ACTION);
		item.addActionListener(this);
		Iterator<ActionListener> iter = externalActionListener.iterator();
		while (iter.hasNext()) {
			item.addActionListener(iter.next());			
		}
		this.add(item);
	}

	@Override
	public void actionPerformed(ActionEvent evt) {
		File selectedFile;
		
		String command = evt.getActionCommand();
		
		// add a mark to the bookmark
		if (command == ADD_BOOKMARK_ACTION){	
			JFileChooser chooser = new JFileChooser();
			if(chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION){
				selectedFile = chooser.getSelectedFile();
				if (selectedFile != null){
				addBookmark(selectedFile);
				}
			}
			
		// the method to manage the bookmark
		} else if (command == MANAGE_ACTION){
			manageBookMarkList();
	    }else{
		selectedItem = (FileItem) evt.getSource();
		}
	}
	

	/**
	 * return the status of the auto save flag. 
	 * @return
	 */
	public boolean isAutoSave() {
		return autoSave;
	}


	/**
	 * Set the autoSave flag. If autoSave is true, the list of bookmarked 
	 * files will be save to the Java properties automatically when the addReference method
	 * is called and a new path/file added. 
	 * 
	 * @param autoSave
	 */
	public void setAutoSave(boolean autoSave) {
		this.autoSave = autoSave;
	}


	/**
	 * return the ArrayList of bookmarked files.
	 * @return
	 */
	public ArrayList<File> getBookmarkList() {
		return bookmark;
	}


	/**
	 * Set the list of the bookmarked files and update the 
	 * corresponding view (i.e the menu). 
	 * @param bookmark
	 */
	public void setBookmarkList(ArrayList<File> bookmark) {
		this.bookmark = bookmark;
		
		// we clean up the menu item list
		for (int i = 0; i<this.getItemCount(); i++){
		this.remove(this.getItem(0));
		}
		
		Iterator<File> iter = this.bookmark.iterator();
		while (iter.hasNext()) {
			updateView(iter.next());
		}
	}
	
	/**
	 * remove the reference (i.e mark) corresponding to the given file and update the view.
	 * @param file
	 */
	public void removeBookmark(File file){		
		// needed to pass over the three first items (add mark, remove mark and separator)
		int shift = 3; 
		
		int index = this.bookmark.indexOf(file);
		bookmark.remove(file);
		this.remove(this.getItem(index + shift)); // not very clean, I know...
		java.util.prefs.Preferences.userRoot().remove(PROPERTIES_PREFIX + "." + index); // to be sure and clean
		if( autoSave ){
			saveBookmarkListToProperties();
		}
	}

	/**
	 * Bookmark management window
	 */
    private void manageBookMarkList(){    	
    	managmentFrame = new JFrame();        
        marksList = new JList( this.bookmark.toArray());
		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setViewportView(marksList);
		
		JPanel mainPane = new JPanel();
		mainPane.setLayout(new BorderLayout());
		mainPane.add(scrollPane, BorderLayout.CENTER);
		mainPane.setPreferredSize(new Dimension(400, 600));

		Object[] options = {"Remove","Cancel"};
		int answer = JOptionPane.showOptionDialog(managmentFrame, mainPane, "Bookmark Managment", JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE,
			    null,    
			    options,  
			    options[0]); 
		
		if ( answer == 0){
			File selectedMark = (File) marksList.getSelectedValue();
			managmentFrame.setVisible(false);
			removeBookmark(selectedMark);
		} else {
			managmentFrame.setVisible(false);
		}
    }
	
	
	public FileItem getSelectedItem() {
		return selectedItem;
	}


	public void setSelectedItem(FileItem selectedItem) {
		this.selectedItem = selectedItem;
	}


}
