/**
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * Copyright © 2009 Mindoo GmbH
 *
 * @author Tammo Riedinger
 *
 */
package com.mindoo.ec09.legacy;

import java.awt.Component;
import java.awt.Container;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;

import com.mindoo.ec09.framework.actions.ActionDelegate;
import com.mindoo.ec09.framework.actions.ActionManager;
import com.mindoo.ec09.framework.actions.PopupAction;
import com.mindoo.ec09.framework.application.MultiViewApplication;
import com.mindoo.ec09.framework.views.View;
import com.mindoo.ec09.framework.views.ViewActivationListener;
import com.mindoo.ec09.framework.views.ViewData;
import com.mindoo.ec09.legacy.worldwind.WorldWindView;

public abstract class AbstractLegacyApplication extends MultiViewApplication {
	public static final String VIEWS_WORLDWIND_MAIN = "views.worldwind.main";

	private static final String ACTION_SELECTED_KEY="Action.SELECTED_KEY";
	
	private ActionManager m_actionManager;
	protected final Action EXIT_ACTION=new AbstractAction("Exit") {
		private static final long serialVersionUID = 5831723179687163026L;

		public void actionPerformed(ActionEvent arg0) {
			exit();
		}
    };
	
    public ActionManager getActionManager() {
    	return m_actionManager;
    }
    
	protected String getApplicationID() {
		return AbstractLegacyApplication.class.getName();
	}
	
	protected void startup() {
		super.startup();
		
		JPopupMenu.setDefaultLightWeightPopupEnabled(false);
	}
	
	/**
	 * Method to create a new empty view of the given type.
	 * 
	 * @param type		the type
	 * @return			the created view or <code>null</code>
	 */
	private View createView(String type) {
		try {
			Class<?> clazz=Class.forName(type);
			
			if (View.class.isAssignableFrom(clazz)) {
				return (View)clazz.newInstance();
			}
			else
				System.err.println("AbstractLegacyApplication: Specified ViewType '" + type + "' is not an instance of 'com.mindoo.ec09.framework.views.View'!");
		} catch (Throwable t) {
			System.err.println("AbstractLegacyApplication: Error instantiating ViewType '" + type + "': " + t.getLocalizedMessage());
			t.printStackTrace();
		}
		
		return null;
	}
	
	/**
	 * Method to set the specified view.<br>
	 * If a view with the given ID is found, then it will be updated.<br>
	 * Otherwise a new view will be added.
	 * 
	 * @param id			the id of the view
	 * @param type			type of the view (classname of an implementation of {@link View})
	 * @param title			title of the view
	 * @param data			data-string to be loaded
	 */
	public void setView(final String id, final String type, final String title, final String data) {
		if (!SwingUtilities.isEventDispatchThread()) {
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					setView(id, type, title, data);
				}
			});
			return;
		}
		
		View foundView=findView(id);
		
		// construct a data object
		ViewData viewData=null;
		try {
			// try as a url
			viewData=new URLViewData(id,new URL(data));
		} catch (MalformedURLException e) {
			// treat as string
			viewData=new StringViewData(id,data);
		}
		
		int newIndex=getTabCount();
		if (foundView!=null) {
			// change an existing view
			if (type.equals(foundView.getClass().getName())) {
				// view class has not changed -> just update the data
				foundView.initialize(title, viewData);
				setViewAt(indexOfView(foundView),foundView);

				return;
			}
			else
				// view class has changed -> construct a new view and replace the former one
				newIndex=indexOfView(foundView);
		}

		// create and initialize the view
		View v=createView(type);
			
		v.initialize(title, viewData);
			
		setViewAt(newIndex, v);
	}
	
	protected void configureContentPane(final Container contentPane) {
		if (contentPane instanceof JTabbedPane) {
			((JTabbedPane)contentPane).setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
			((JTabbedPane)contentPane).setTabPlacement(JTabbedPane.BOTTOM);
			
			((JTabbedPane)contentPane).addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					if (e.isPopupTrigger()) {
						Point location=e.getPoint().getLocation();
						SwingUtilities.convertPointToScreen(location, contentPane);

						showPopup(location);
					}
				}

				@Override
				public void mousePressed(MouseEvent e) {
					if (e.isPopupTrigger()) {
						Point location=e.getPoint().getLocation();
						SwingUtilities.convertPointToScreen(location, contentPane);

						showPopup(location);
					}
				}

				@Override
				public void mouseReleased(MouseEvent e) {
					if (e.isPopupTrigger()) {
						Point location=e.getPoint().getLocation();
						SwingUtilities.convertPointToScreen(location, contentPane);

						showPopup(location);
					}
				}
				
				private void showPopup(Point p) {
					final Point location=p.getLocation();
					SwingUtilities.convertPointFromScreen(location, contentPane);

					JPopupMenu menu=new JPopupMenu();
					menu.add(new AbstractAction("Close", new ImageIcon(AbstractLegacyApplication.class.getResource("images/cancel.png"))) {
						private static final long serialVersionUID = 6687515623717962924L;

						public void actionPerformed(ActionEvent evt) {
							
							int tabIndex=((JTabbedPane)contentPane).indexAtLocation(location.x, location.y);
							if (tabIndex!=-1)
								((JTabbedPane)contentPane).removeTabAt(tabIndex);
						}
					});
					
					menu.show(contentPane, location.x, location.y);
				}
			});
		}	
	}
	
	private void registerTextEditorActions(ActionManager actionManager) {
		actionManager.registerAction(new ActionDelegate("Select all"), TextView.class.getName(), "Edit", "Edit");
		
		actionManager.registerAction(new ActionDelegate("Cut", new ImageIcon(AbstractLegacyApplication.class.getResource("images/cut.png"))), TextView.class.getName(), "Edit", "Edit");

		actionManager.registerAction(new ActionDelegate("Copy", new ImageIcon(AbstractLegacyApplication.class.getResource("images/editcopy.png"))), TextView.class.getName(), "Edit", "Edit");

		actionManager.registerAction(new ActionDelegate("Paste", new ImageIcon(AbstractLegacyApplication.class.getResource("images/editpaste.png"))), TextView.class.getName(), "Edit", "Edit");
	}
	
	private void registerPictureViewerActions(ActionManager actionManager) {
		actionManager.registerAction(new ActionDelegate("Zoom in", new ImageIcon(AbstractLegacyApplication.class.getResource("images/viewmag_in.png"))), PictureView.class.getName(), "View", "View");
		
		actionManager.registerAction(new ActionDelegate("Zoom out", new ImageIcon(AbstractLegacyApplication.class.getResource("images/viewmag_out.png"))), PictureView.class.getName(), "View", "View");
	}
	
	private void registerChartViewerActions(ActionManager actionManager) {
		actionManager.registerAction(new ActionDelegate("Zoom in", new ImageIcon(AbstractLegacyApplication.class.getResource("images/viewmag_in.png"))), ChartView.class.getName(), "View", "View");
		
		actionManager.registerAction(new ActionDelegate("Zoom out", new ImageIcon(AbstractLegacyApplication.class.getResource("images/viewmag_out.png"))), ChartView.class.getName(), "View", "View");
	}
	
	private void registerWorldWindViewerActions(ActionManager actionManager) {
		actionManager.registerAction(new ActionDelegate("Zoom in", new ImageIcon(AbstractLegacyApplication.class.getResource("images/viewmag_in.png"))), WorldWindView.class.getName(), "View", "View");
		
		actionManager.registerAction(new ActionDelegate("Zoom out", new ImageIcon(AbstractLegacyApplication.class.getResource("images/viewmag_out.png"))), WorldWindView.class.getName(), "View", "View");
	}
	
	private void registerGeneralActions(ActionManager actionManager) {
		actionManager.registerAction(new AbstractAction("Open document", new ImageIcon(AbstractLegacyApplication.class.getResource("images/wordprocessing.png"))) {
			private static final long serialVersionUID = -2145350084643663463L;

			public void setEnabled(boolean newValue) {
				super.setEnabled(newValue);
			}
			
			public void actionPerformed(ActionEvent evt) {
				JFileChooser fc=new JFileChooser();
				
				if (fc.showOpenDialog(AbstractLegacyApplication.this.getWindow())==JFileChooser.APPROVE_OPTION) {
					try {
						URLViewData data=new URLViewData(fc.getSelectedFile().toURI().toURL());
						addView(new TextView(data.getID(),data));
					} catch (MalformedURLException e) {
						e.printStackTrace();
					}
				}
			}
	    }, getApplicationID(), "File", null);
		
		actionManager.registerAction(new AbstractAction("Open picture", new ImageIcon(AbstractLegacyApplication.class.getResource("images/thumbnail.png"))) {
			private static final long serialVersionUID = -6393088117684430844L;

			public void actionPerformed(ActionEvent evt) {
				JFileChooser fc=new JFileChooser();
				
				if (fc.showOpenDialog(AbstractLegacyApplication.this.getWindow())==JFileChooser.APPROVE_OPTION) {
					try {
						URLViewData data=new URLViewData(fc.getSelectedFile().toURI().toURL());
						addView(new PictureView(data.getID(), data));
					} catch (MalformedURLException e) {
						e.printStackTrace();
					}
				}
			}
	    }, getApplicationID(), "File", null);
		
		actionManager.registerAction(new AbstractAction("Open chart", new ImageIcon(AbstractLegacyApplication.class.getResource("images/kcmpartitions.png"))) {
			private static final long serialVersionUID = -6393088117684430844L;

			public void actionPerformed(ActionEvent evt) {
				JFileChooser fc=new JFileChooser();
				
				if (fc.showOpenDialog(AbstractLegacyApplication.this.getWindow())==JFileChooser.APPROVE_OPTION) {
					try {
						URLViewData data=new URLViewData(fc.getSelectedFile().toURI().toURL());
						addView(new ChartView(data.getID(), data));
					} catch (MalformedURLException e) {
						e.printStackTrace();
					}
				}
			}
	    }, getApplicationID(), "File", null);
		
		actionManager.registerAction(new AbstractAction("Load URL", new ImageIcon(AbstractLegacyApplication.class.getResource("images/network.png"))) {
			private static final long serialVersionUID = 5831723179687163026L;

			public void actionPerformed(ActionEvent evt) {
				Object s = JOptionPane.showInputDialog(
				                    null,
				                    "Enter document-URL:",
				                    "Load URL",
				                    JOptionPane.PLAIN_MESSAGE,
				                    null,
				                    null,
				                    null);

				if (s instanceof String && !"".equals((String)s))
					try {
						URLViewData data=new URLViewData(new URL(s.toString()));

						addView(new TextView(data.getID(),data));
					} catch (MalformedURLException e) {
						e.printStackTrace();
					}
			}
	    }, getApplicationID(), "File", null);
		
		
		actionManager.registerAction(new AbstractAction("Find address", new ImageIcon(AbstractLegacyApplication.class.getResource("images/package_network.png"))) {
			private static final long serialVersionUID = 1094340644423637297L;

			public void actionPerformed(ActionEvent evt) {
				Object s = JOptionPane.showInputDialog(
				                    null,
				                    "Enter an address like in google maps:",
				                    "Find address",
				                    JOptionPane.PLAIN_MESSAGE,
				                    null,
				                    null,
				                    null);

				if (s instanceof String && !"".equals((String)s)) {
					ViewData data=null;
					try {
						data=new URLViewData(VIEWS_WORLDWIND_MAIN, new URL("http://maps.google.com/maps/geo?q=" + ((String)s).replace(" ", "+") +"&output=xml"));
					} catch (MalformedURLException e) {
						System.err.println("AbstractLegacyApplication: Error creating google-maps URL: " + e.getLocalizedMessage());
						e.printStackTrace();
					}
					
					if (data!=null) {
						View worldWindView=findView(VIEWS_WORLDWIND_MAIN);
						
						if (worldWindView!=null) {
							worldWindView.initialize((String)s, data);
							
							setViewAt(indexOfView(worldWindView),worldWindView);
						}
						else
							addView(new WorldWindView((String)s, data));
					}
				}
			}
	    }, getApplicationID(), "File", null);
		
		actionManager.registerAction(new WindowsAction("Windows") , getApplicationID(), null, null);
		
		actionManager.registerAction(EXIT_ACTION, getApplicationID(), "File", null);
	}
	
	private class WindowsAction extends AbstractAction implements PopupAction {
		private static final long serialVersionUID = 8306400934671595327L;

		public WindowsAction(String name) {
			super(name, new ImageIcon(AbstractLegacyApplication.class.getResource("images/tab_duplicate.png")));
		}

		public Action[] getChildActions() {
			ArrayList<Action> actions=new ArrayList<Action>();
			
			Iterator<View> views=getViews();
			while (views.hasNext()) {
				final View v=views.next();
				
				Action a=new AbstractAction(v.getTitle()) {
					private static final long serialVersionUID = -4635724272258465980L;

					public void actionPerformed(ActionEvent evt) {
						setActiveView(v);
					}
				};
				actions.add(a);

				if (v==getActiveView())
					a.putValue(ACTION_SELECTED_KEY,Boolean.valueOf(true));
			}

			return actions.toArray(new Action[0]);
		}

		public void actionPerformed(ActionEvent evt) {
			View activeView=getActiveView();
			if (activeView!=null) {
				Iterator<View> views=getViews();
				while (views.hasNext()) {
					View v=views.next();
					
					if (activeView==v && views.hasNext())
						setActiveView(views.next());
				}
			}
		}
	}

	protected ActionManager createActionManager(Component window, Container contentPane) {
		 return new ActionManager(null,contentPane.getParent());
	}
	
	protected void createActions(Component window, Container contentPane) {
	    m_actionManager=createActionManager(null,contentPane);
	    
	    registerGeneralActions(m_actionManager);
	    registerTextEditorActions(m_actionManager);
	    registerPictureViewerActions(m_actionManager);
	    registerChartViewerActions(m_actionManager);
	    registerWorldWindViewerActions(m_actionManager);
	    
		this.addViewActivationListener(new ViewActivationListener() {
			public void activationChanged(View newView, View formerView) {
				if (formerView!=newView) {
					if (formerView!=null)
						m_actionManager.deActivate(formerView.getClass().getName());
					
					if (newView!=null)
						activateView(newView);
				}
			}
		});
		
		m_actionManager.activate(getApplicationID());

		View v=getActiveView();
		if (v!=null)
			activateView(v);
	}
	
    protected JMenuBar createMenuBar(Container contentPane) {
	    final JMenuBar mb=new JMenuBar() {
			private static final long serialVersionUID = 7012602766230800003L;

			@Override
	    	public JMenu add(JMenu c) {
	    		if (!"Windows".equals(c.getName())) {
	    			super.add(c,this.getComponentCount()-1);
	    			return c;
	    		}
	    		else {
	    			JMenu m=super.add(c);
	            
	    			return m;
	    		}
	        }
	    };
	    
	    final JMenu windowMenu=new JMenu("Windows");
	    windowMenu.addMenuListener(new MenuListener() {

			public void menuCanceled(MenuEvent e) {
				windowMenu.removeAll();
			}

			public void menuDeselected(MenuEvent e) {
				windowMenu.removeAll();
			}

			public void menuSelected(MenuEvent e) {
				windowMenu.removeAll();
				
				Iterator<Action> actions=m_actionManager.getActions(getApplicationID());
				while (actions.hasNext()) {
					Action windowAction=actions.next();
					
					if (windowAction instanceof WindowsAction) {
						Action[] childActions=((WindowsAction)windowAction).getChildActions();
						
						for (Action a:childActions) {
							Boolean isSelected=(Boolean)a.getValue(ACTION_SELECTED_KEY);
							
							if (isSelected!=null) {
								JCheckBoxMenuItem menuItem=new JCheckBoxMenuItem(a);
								menuItem.setSelected(isSelected.booleanValue());
								
								windowMenu.add(menuItem);
							}
							else
								windowMenu.add(a);
						}
						break;
					}
				}
			}
	    });
	    mb.add(windowMenu);
	    
	    m_actionManager.setMenuBar(mb);

		return mb;
	}
    
	private void activateView(View view) {
		if (view!=null) {
			String setID=view.getClass().getName();
			
			updateDelegates(setID,view);

			m_actionManager.activate(setID);
		}
	}
	
	private void updateDelegates(String setID, View view) {
		Iterator<Action> actions=m_actionManager.getActions(setID);
		while (actions.hasNext()) {
			Action a=actions.next();
			if (a instanceof ActionDelegate)
				((ActionDelegate)a).setView(view);
		}
	}
    
    protected URL locateResource(String relativePath) {
    	return AbstractLegacyApplication.class.getResource("/" + relativePath);
    }

    @Override
	protected void installInitialTabs() {
		URLViewData data=new URLViewData(locateResource("resources/piedata.xml"));
		addView(new ChartView(data.getID(),data));

		data=new URLViewData(locateResource("resources/categorydata.xml"));
		addView(new ChartView(data.getID(),data));
	}

    @Override
	protected void show(Component window) { }

	@Override
	protected void hide(Component window) { }
}