/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/
package lu.tudor.santec.gecamed.core.gui;

import java.awt.event.KeyEvent;
import java.util.HashMap;

import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

/**
 * A JPanel to be shown as a TAB in a JTabbedPane.
 * It provides extra functionality like an title and an icon for the tab,
 * a way to show unsaved modifications in the tabtitle and a
 * preparetoShowup method that will be called whenever the tab gets visible.
 *
 * @author Johannes Hermen johannes.hermen(at)tudor.lu
 * 
 * @Version
 * <br>$Log: GECAMedTab.java,v $
 * <br>Revision 1.27  2013-12-27 18:09:26  donak
 * <br>Cleanup of imports
 * <br>
 * <br>Revision 1.26  2013-07-15 06:18:35  ferring
 * <br>logging changed
 * <br>
 * <br>Revision 1.25  2010-03-12 14:17:42  hermen
 * <br>cleanup of panel layouts and icons
 * <br>
 * <br>Revision 1.24  2009-05-29 13:51:21  hermen
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.23  2008-09-25 09:43:07  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.22  2008-09-11 13:39:29  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.21  2008-04-07 13:10:36  hermen
 * <br>added Mainframe.addAdminTab to allow modules to add their own tabs to the admin module.
 * <br>
 * <br>Revision 1.20  2008-01-15 09:29:39  hermen
 * <br>updated Javadoc and refactured code
 * <br>
 * <br>Revision 1.19  2007-12-03 10:59:02  hermen
 * <br>updated Javadoc
 * <br>
 *
 */
public abstract class GECAMedTab extends JPanel {

	private static final long serialVersionUID = 1L;

	/**
	 * property that is fires via propertychange if the tab has been modified
	 */
	public static final String DATA_CHANGED = "data_changed";

	/**
	 * static logger for this class
	 */
	private static Logger logger = Logger.getLogger(GECAMedTab.class.getName());
	
	/**
	 * static hashmap that stores the current shown tab for each JTabbedPane instance 
	 */
	private static HashMap<JTabbedPane, GECAMedTab> currentTabs  = new HashMap<JTabbedPane, GECAMedTab>();

	/**
	 * the title of the tab
	 */
	private String tabTitle = "";
	
	/**
	 * the icon of the tab 
	 */
	private ImageIcon tabIcon;
	
	/**
	 * the tooltip of the tab 
	 */
	private String tabToolTip = null;

	/**
	 * tabbedpane on which this tab is shown
	 */
	protected JTabbedPane tabbedPane;

	/**
	 * has the tab been modified after the last save-call
	 */
	private volatile boolean modified;
	
	/**
	 * is this tab enabled
	 */
	private boolean enabled = true;

	/**
	 * creates a new GECAMedTab
	 */
	public GECAMedTab() {
	}

	/**
	 * creates a new GECAMedTab
	 * @param tabName the name of the Tab
	 * @param tabIcon the icon of the Tab
	 */
	public GECAMedTab(String tabName, ImageIcon tabIcon) {
		this.tabTitle  =tabName;
		this.tabIcon = tabIcon;
	}


 	/**
 	 * Gets the title of the tab
 	 * @return The title of the tab
 	 */
 	public String getTitle() {
		return this.tabTitle;
	}

	/**
	 * sets the title of the Tab
	 * @param tabTitle The title to set.
	 */
	public void setTitle(String tabTitle) {
		this.tabTitle = tabTitle;
		if (this.tabbedPane != null)
			try {
				this.tabbedPane.setTitleAt(this.tabbedPane.indexOfComponent(this), this.tabTitle);
			} catch (Exception e) {
			}
	}

	/**
	 * sets the icon of the Tab
	 * @param tabIcon The Icon to set.
	 */
	public void setIcon(ImageIcon tabIcon) {
		this.tabIcon = tabIcon;
		if (this.tabbedPane != null)
			try {
				this.tabbedPane.setIconAt(this.tabbedPane.indexOfComponent(this), this.tabIcon);
			} catch (Exception e) {
			}
	}

	/**
	 * Gets the icon of the Tab
	 * @return the icon of the tab
	 */
	public ImageIcon getIcon() {
		return tabIcon;
	}



	/**
	 * @return Returns the tabToolTip.
	 */
	public String getTabToolTip() {
		return tabToolTip;
	}

	/**
	 * @param tabToolTip The tabToolTip to set.
	 */
	public void setTabToolTip(String tabToolTip) {
		this.tabToolTip = tabToolTip;
	}

	/**
	 * adds the panel to the given JTabbedPane as a new tab.
	 * @param tabbedPane
	 */
	public void addToTabbedPane(final JTabbedPane tabbedPane) {
		this.tabbedPane = tabbedPane;

		// add and enable/disable the tab
		this.tabbedPane.addTab(getTitle(), getIcon(), this, getTabToolTip());
		this.tabbedPane.setEnabledAt(this.getTabIndex(),this.enabled);

		// set Mnemonic to the tab ALT+NumberOfTab
		int keyCode = 0;
		switch (this.getTabIndex()+1) {
		case 0:
			keyCode = KeyEvent.VK_0;
			break;
		case 1:
			keyCode = KeyEvent.VK_1;
			break;
		case 2:
			keyCode = KeyEvent.VK_2;
			break;
		case 3:
			keyCode = KeyEvent.VK_3;
			break;
		case 4:
			keyCode = KeyEvent.VK_4;
			break;
		case 5:
			keyCode = KeyEvent.VK_5;
			break;
		case 6:
			keyCode = KeyEvent.VK_6;
			break;
		case 7:
			keyCode = KeyEvent.VK_7;
			break;
		case 8:
			keyCode = KeyEvent.VK_8;
			break;
		case 9:
			keyCode = KeyEvent.VK_9;
			break;
		default:
			break;
		}
		this.tabbedPane.setMnemonicAt(this.getTabIndex(), keyCode);

		if (!GECAMedTab.currentTabs.containsKey(this.tabbedPane)) {
			// install a changelistener to get tab changes
			TabChangeListener tabAction = new TabChangeListener();
			this.tabbedPane.addChangeListener(tabAction);
			// store current selected tab for preparetoHide on tab changes
			GECAMedTab.currentTabs.put(this.tabbedPane, (GECAMedTab) this.tabbedPane.getSelectedComponent());
		}

	}

	/**
	 * removes the tab from its Tabbedpane
	 */
	public void removeFromTabbedPane() {
		/* ================================================== */
		if (this.tabbedPane != null) {
			try {
				this.tabbedPane.remove(this);
			} catch (Exception e) {
				logger.log(Level.WARN, "removing tab failed" ,e);
			}
		}
		/* ================================================== */
	}


	/**
	 * shows that the tab has been modified in the Tab
	 * by adding a <b>*</b> to its Tabtitle
	 *
	 * @param modified
	 */
	public void setModified(boolean modified) {
//		if (this.modified == modified) {
//			return;
//		}
		this.modified = modified;
		firePropertyChange(DATA_CHANGED, !this.modified, this.modified);
		if (this.tabbedPane != null ) {
			if (modified == true) {
				this.tabbedPane.setTitleAt(this.tabbedPane.indexOfComponent(this), getTitle() + " *");
				this.tabbedPane.setBackgroundAt(this.tabbedPane.indexOfComponent(this), GECAMedColors.c_ModifiedTitleBackground);
			} else {
				this.tabbedPane.setTitleAt(this.tabbedPane.indexOfComponent(this), getTitle());
				this.tabbedPane.setBackgroundAt(this.tabbedPane.indexOfComponent(this), null);
			}
		}
	}

	/**
	 * returns true if modified is set
	 * @return
	 */
	public boolean isModified() {
		return this.modified;
	}

	/**
	 * this method is called before the tab gets visible
	 */
	public void preparetoShowup()
		{
		}

	/**
	 * this method is called before the tab gets invisible
	 */
	public void preparetoHide ()
		{
		}

	/**
	 * this method is called when reload button is hit
	 */
	public void reload ()
	{
	}


	/**
	 * sets this tab as the active one in the tabbedpane
	 */
	public void showTab() {
		try {
			this.tabbedPane.setSelectedComponent(this);
		} catch (Exception e) {
		}
	}

	/**
	 * enables the tab
	 */
	public void enableTab() {
		try {
			this.enabled = true;
			this.tabbedPane.setEnabledAt(this.getTabIndex(),true);
		} catch (Exception e) {
		}
	}

	/**
	 * disables the tab, it can no longer be selected in the tabbedpane
	 * and is shown in grey
	 */
	public void disableTab() {
		try {
			this.enabled = false;
			this.tabbedPane.setEnabledAt(this.getTabIndex(), false);
		} catch (Exception e) {
		}
	}

	/**
	 * returns the index of this tab in the tabbedpane
	 * @return
	 */
	public int getTabIndex() {
		for (int i = 0; i < this.tabbedPane.getTabCount(); i++) {
			if (this.tabbedPane.getTitleAt(i).equals(this.getTitle())) {
				return i;
			}
		}
		return -1;
	}

	/**
	 * returns true if this tab is enabled
	 * @return
	 */
	public boolean isTabEnabled() {
		/* ====================================================== */
		return enabled;
		/* ====================================================== */
	}
	
	/**
	 * enables/disables all elements of this panel
	 * @param enable
	 */
	public void enablePanel(boolean enable) {
	    logger.info(this.getClass().getName()+":enablePanel(" + enable +  ") not implemented");
	}


	/**
	 * this method is called when the save button is pressed, 
	 * the tab should save its data then.
	 */
	public void saveData() {
		System.out.println("saveData not implemented in Class: " + this.getClass().getSimpleName());
	}

	/**
	 * @author Johannes Hermen johannes.hermen(at)tudor.lu
	 * 
	 * changelistener to register changes of the shown tab
	 *
	 * @Version
	 * <br>$Log: GECAMedTab.java,v $
	 * <br>Revision 1.27  2013-12-27 18:09:26  donak
	 * <br>Cleanup of imports
	 * <br>
	 * <br>Revision 1.26  2013-07-15 06:18:35  ferring
	 * <br>logging changed
	 * <br>
	 * <br>Revision 1.25  2010-03-12 14:17:42  hermen
	 * <br>cleanup of panel layouts and icons
	 * <br>
	 * <br>Revision 1.24  2009-05-29 13:51:21  hermen
	 * <br>*** empty log message ***
	 * <br>
	 * <br>Revision 1.23  2008-09-25 09:43:07  heinemann
	 * <br>fixed copyrights
	 * <br>
	 * <br>Revision 1.22  2008-09-11 13:39:29  heinemann
	 * <br>*** empty log message ***
	 * <br>
	 * <br>Revision 1.21  2008-04-07 13:10:36  hermen
	 * <br>added Mainframe.addAdminTab to allow modules to add their own tabs to the admin module.
	 * <br>
	 * <br>Revision 1.20  2008-01-15 09:29:39  hermen
	 * <br>updated Javadoc and refactured code
	 * <br>
	 * <br>Revision 1.19  2007-12-03 10:59:02  hermen
	 * <br>updated Javadoc
	 * <br>
	 *
	 */
	class TabChangeListener implements ChangeListener {	
		public void stateChanged(ChangeEvent e) {
			JTabbedPane jtb = (JTabbedPane) e.getSource();

			GECAMedTab oldCurrTab = GECAMedTab.currentTabs.get(jtb);
			// fire preparetoHide on the last selected tab
			if (oldCurrTab != null) {
				logger.info("now hiding Tab: " + oldCurrTab.tabTitle);
				oldCurrTab.preparetoHide();
			}
			//	fire preparetoShowup on the new selected tab
			GECAMedTab newCurrTab = (GECAMedTab) tabbedPane
					.getSelectedComponent();
			if (newCurrTab != null) {
				logger.info("now showing Tab: " + newCurrTab.tabTitle);
				newCurrTab.preparetoShowup();
			}
			// store current selected tab for preparetoHide on tab changes
			GECAMedTab.currentTabs.put(jtb, newCurrTab);

		}
	}

}
