package j3deditor.bin;


import j3deditor.bin.editor.EditorFrame;

import j3deditor.bin.hierarchy.view.HierarchyFrame;

import j3deditor.bin.util.ProgressIndicator;
import j3deditor.bin.util.UserData;
import j3deditor.bin.util.Utilities;
import j3deditor.bin.util.preferences.PrefDialog;

import j3deditor.bin.util.startup.StartUp;

import com.centerkey.utils.BareBonesBrowserLaunch;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;

import java.io.File;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.SwingWorker;


/**
 * Main window of the Java 3D editor.
 * Contains desktop pane for internal frames
 * and main entry point for the application.
 *
 * @author Risto Seene
 */
public class MainFrame extends JFrame{

	/** Desktop pane for internal frames. */
	private MainDesktop desktop;


	/**
	 * Creates an instance of <code>MainFrame</code>.
	 *
	 * @param args
	 *	arguments sent by <code>main</code> method.
	 *        Can be <code>null</code>
	 */
	public MainFrame(String[] args){
		this.setTitle(Utilities.translator.translate(getClass(), "title"));
		initializeMenu();

		setLayout(new BorderLayout());
		desktop = new MainDesktop();
		add(desktop, BorderLayout.CENTER);

		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		setIconImage(Utilities.image.getImage("icons/translate.png"));
		Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
		setLocation((int)(0.1 * dim.getWidth()), (int)(0.1 * dim.getHeight()));
		setSize((int)(0.8 * dim.getWidth()), (int)(0.8 * dim.getHeight()));
		applyPreferences();
		setVisible(true);

		if(args != null && args.length > 0){
			openScene(args);
		}
	}


	/**
	 * Initializes the menubar and all its items.
	 */
	private void initializeMenu(){
		JMenuBar menubar = new JMenuBar();

		JMenu filemenu = new JMenu(Utilities.translator.translate(getClass(), "filemenu"));
		JMenuItem newproj = new JMenuItem(Utilities.translator.translate(getClass(), "newproj"));
		JMenuItem open = new JMenuItem(Utilities.translator.translate(getClass(), "open"));
		JMenuItem quit = new JMenuItem(Utilities.translator.translate(getClass(), "quit"));

		JMenu editmenu = new JMenu(Utilities.translator.translate(getClass(), "editmenu"));
		JMenuItem hierarchy = new JMenuItem(Utilities.translator.translate(getClass(), "hierarchy"));
		JMenuItem pref = new JMenuItem(Utilities.translator.translate(getClass(), "pref"));

		JMenu helpmenu = new JMenu(Utilities.translator.translate(getClass(), "helpmenu"));
		JMenuItem api = new JMenuItem(Utilities.translator.translate(getClass(), "api"));
		JMenuItem source = new JMenuItem(Utilities.translator.translate(getClass(), "src"));

		setJMenuBar(menubar);

		menubar.add(filemenu);
		filemenu.add(newproj);
		filemenu.add(open);
		filemenu.addSeparator();
		filemenu.add(quit);

		newproj.addActionListener(new ActionListener(){

				public void actionPerformed(ActionEvent e){
					SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>(){

						public Void doInBackground(){
							menuFileNew();
							return null;
						}
					};
					String info = Utilities.translator.translate(this.getClass(), "opening");
					worker.addPropertyChangeListener(new ProgressIndicator(info));
					worker.execute();
				}
			});
		open.addActionListener(new ActionListener(){

				public void actionPerformed(ActionEvent e){
					SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>(){

						public Void doInBackground(){
							FileDialog fd = new FileDialog(new JFrame(), "Load project", FileDialog.LOAD);
							fd.setVisible(true);
							if(fd.getDirectory() != null && fd.getFile() != null){
								menuFileOpen(fd.getDirectory() + fd.getFile());
							}
							return null;
						}
					};
					worker.execute();
				}
			});
		quit.addActionListener(new ActionListener(){

				public void actionPerformed(ActionEvent e){
					SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>(){

						public Void doInBackground(){
							menuFileQuit();
							return null;
						}
					};
					worker.execute();
				}
			});


		menubar.add(editmenu);
		editmenu.add(hierarchy);
		editmenu.addSeparator();
		editmenu.add(pref);

		hierarchy.addActionListener(new ActionListener(){

				public void actionPerformed(ActionEvent e){
					SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>(){

						public Void doInBackground(){
							menuEditHierarchy();
							return null;
						}
					};
					worker.execute();
				}
			});
		pref.addActionListener(new ActionListener(){

				public void actionPerformed(ActionEvent e){
					SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>(){

						public Void doInBackground(){
							menuEditPreferences();
							return null;
						}
					};
					worker.execute();
				}
			});


		menubar.add(helpmenu);
		helpmenu.add(api);
		helpmenu.add(source);

		api.addActionListener(new ActionListener(){

				public void actionPerformed(ActionEvent e){
					SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>(){

						public Void doInBackground(){
							menuHelpApi();
							return null;
						}
					};
					worker.execute();
				}
			});
		source.addActionListener(new ActionListener(){

				public void actionPerformed(ActionEvent e){
					SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>(){

						public Void doInBackground(){
							menuHelpSource();
							return null;
						}
					};
					worker.execute();
				}
			});
	}


	/**
	 * Applies user preferences to this frame.
	 */
	private void applyPreferences(){
		try{
			if(Utilities.userdata.getBooleanData("fullscreen")){
				setExtendedState(Frame.MAXIMIZED_BOTH);
			}
		} catch(Throwable t){
		}
	}


	/**
	 * Opens a scene using <code>String</code> array as the path
	 * of the file this scene is described in.
	 *
	 * @param args
	 *	file path sent as <code>String</code> array
	 */
	private void openScene(String[] args){
		String source = args[0];
		for(int i = 1; i < args.length; i++){
			source = source + " " + args[i];
		}

		this.menuFileOpen(source);
	}


	/**
	 * Method for processing the closing event of this
	 * window (<code>JFrame</code>).
	 *
	 * @param e
	 *	<code>WindowEvent</code> that will be processed
	 */
	protected void processWindowEvent(WindowEvent e){
		if(e.getID() == WindowEvent.WINDOW_CLOSING){
			this.desktop.closeAllWindows();
		}
		super.processWindowEvent(e);
	}


	/**
	 * Opens new project window that creates new scene.
	 */
	private void menuFileNew(){
		try{
			new EditorFrame(desktop);
		} catch(NoClassDefFoundError e){
			Utilities.out.throwError(e.toString());
		} catch(Throwable t){
			Utilities.out.throwError(t);
		}
	}

	/**
	 * Opens new project window that opens the given scene.
	 * 
	 * @param filePath
	 * 	path of the scene file that will be loaded
	 */
	private void menuFileOpen(String filePath){
		if(filePath != null){
			try{
				EditorFrame ef = new EditorFrame(desktop);
				ef.openScene(filePath);
			} catch(NoClassDefFoundError e){
				Utilities.out.throwError(e.toString());
			} catch(Throwable t){
				Utilities.out.throwError(t);
			}
		}
	}

	/**
	 * Closes the editor.
	 */
	private void menuFileQuit(){
		this.processWindowEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
	}


	/**
	 * Opens new hierarchy frame.
	 */
	private void menuEditHierarchy(){
		new HierarchyFrame(desktop);
	}

	/**
	 * Opens new preferences dialog.
	 */
	private void menuEditPreferences(){
		new PrefDialog();
	}


	/**
	 * Tries to open API specification files in default web browser.
	 * If those files do not exist starts the extracting process.
	 */
	private void menuHelpApi(){
		try{
			File html = UserData.getFile(UserData.resources + File.separator + "javadoc" + File.separator + "index.html");
			if(!html.exists()){
				String question = Utilities.translator.translate(this.getClass(), "confirmApiExtract");
				int response = Utilities.out.throwQuestion(question);
				if(response == 0){
					Utilities.util.extractZipResources(Utilities.compressedData + "javadoc.zip", UserData.resources);
					BareBonesBrowserLaunch.openURL(html.getCanonicalPath());
				}
			}
			else {
			          BareBonesBrowserLaunch.openURL(html.getCanonicalPath());
			}
		} catch(Throwable t){
			Utilities.out.throwError(t);
		}
	}

	/**
	 * Starts the extracting process of application source code files.
	 */
	private void menuHelpSource(){
		try{
			String question = Utilities.translator.translate(this.getClass(), "confirmSourceExtract");
			int response = Utilities.out.throwQuestion(question);
			if(response == 0){
				Utilities.util.extractZipResources(Utilities.compressedData + "src.zip", UserData.resources);
				String info = Utilities.translator.translate(this.getClass(), "srcLocation");
				String path = UserData.resources;
				try{
					path = UserData.getFile(path) + File.separator;
				} catch(Throwable t){}
				Utilities.out.throwInfo(info + " " + path);
			}
		} catch(Throwable t){
			Utilities.out.throwError(t);
		}
	}


	/**
	 * Main entry point.
	 * 
	 * @param arg
	 * 	program arguments
	 */
	public static void main(String[] arg){
		StartUp start = new StartUp();

		start.setInfo("Initializing utilities...");
		new Utilities(start);

		start.setInfo("Starting editor...");
		try{
			Thread.sleep(1000);
		} catch(Throwable t){
		}
		new MainFrame(arg);

		start.dispose();
		start = null;
	}

}
