package jdraw;

// Uebung Java Draw Editor
//
// Informatik 4/FHA
// Software Konstruktion/ETH
//

import javax.swing.*;
import jdraw.framework.*;
import jdraw.std.*;
import jdraw.figures.*;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;

/**
 * The class Draw is the main class of the graphic editor. Its main
 * method creates a new JFrame and initializes it. Changes in the
 * configuration of the main window (e.g. new menus, tools etc.)
 * have to be added in this class.
 * <P>
 * The application can be started with the command
 * <PRE>
 * java jdraw.Draw
 * </PRE>
 *
 * @see DrawView
 *
 * @author  Dominik Gruntz
 * @version 2.1, 29.04.2002
 */
public class Draw {

	private static int windowCounter = 0;
	
	private DrawView v;
	private int windowNr;
	private JFrame rootFrame;
	private Clipboard clipboard = new StdClipboard();
	
	private java.util.List tools = new LinkedList();
	
	/**
	 * Starts the Graphic editor.
	 *
	 *    java jdraw.Draw
	 *
	 * Arguments are not yet interpreted.
	 */
	public static void main (String[] args){
		Draw d = new Draw(new StdDrawModel());
		d.rootFrame.setSize(600,400);
		d.rootFrame.setVisible(true);
	}

	private Draw(DrawModel model){
		rootFrame = new JFrame("Draw Editor");		
		windowNr = windowCounter++;
		if(windowNr > 0)
			rootFrame.setTitle("<"+rootFrame.getTitle()+":"+windowNr+">");
		
	 	final JTextField statusField = new JTextField();
		final JMenuBar   menuBar     = new JMenuBar();
		
		// define the call-back DrawEditor interface to access 
		// the menuBar and the statusField
		final DrawEditor editor = new DrawEditor(){
			public DrawView getView(){return v;}
			public void showStatus(String s){
				statusField.setText(s);
			}
			public void addMenu(JMenu m){
				menuBar.add(m);
				rootFrame.setJMenuBar(menuBar);
			}
			public void removeMenu(JMenu m){
				menuBar.remove(m);
				rootFrame.setJMenuBar(menuBar);
			}
			public void toolChanged(){
				checkTools();
			}
		};	
		
		v = new StdDrawView(editor, model, 300, 200);
		JScrollPane scrollPane = new JScrollPane(
			(JComponent)v, 
			JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
			JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		
		statusField.setEditable(false);
		
		final JToolBar toolBar = new JToolBar();
		
		JPanel center = new JPanel(new BorderLayout());
		center.add(toolBar,    BorderLayout.NORTH);
		center.add(scrollPane, BorderLayout.CENTER);
		rootFrame.getContentPane().add(center,      BorderLayout.CENTER);
		rootFrame.getContentPane().add(statusField, BorderLayout.SOUTH);

		rootFrame.pack();
		rootFrame.setSize(300, 200);
		

		rootFrame.addWindowListener(
			new WindowAdapter(){
				public void windowClosing(WindowEvent e){
					close();
				}
			}
		);

		// Setup menu bar
		rootFrame.setJMenuBar(menuBar);

		JMenu file = new JMenu("File");
		menuBar.add(file);
		
		JMenu edit = new JMenu("Edit");
		menuBar.add(edit);
		
		final JMenu figures = new JMenu("Figures");
		menuBar.add(figures);
		
		JMenu decorations = new JMenu("Decorators");
		menuBar.add(decorations);
		
		JMenu window = new JMenu("Window");
		menuBar.add(window);
		
		// ADD TOOLS
		try{
			InputStream is = getClass().getResourceAsStream("jdraw.xml");
			javax.xml.parsers.SAXParser parser = javax.xml.parsers.SAXParserFactory.newInstance().newSAXParser();
			parser.parse(is, new org.xml.sax.helpers.DefaultHandler(){

				public void startElement(String xmlns, String name, String qname, org.xml.sax.Attributes atts) {
					try {
						if(qname.equals("tool")){
							String entry   = atts.getValue("name");
							String factory = atts.getValue("factory");
							try {
								DrawToolFactory f = (DrawToolFactory)Class.forName(factory).newInstance();
								DrawTool tool = f.createTool(editor);
								addFigureMenuEntry(figures, entry, tool);
								if(f.getIcon() != null)
									addToolBarEntry(toolBar, entry, tool, f.getIcon(), editor);
							}
							catch(ClassNotFoundException cnfe){
								System.err.println(factory + " not found");
							}
							catch(InstantiationException ie){
								System.err.println(factory + " could not be instantiated");
							}
							catch(IllegalAccessException iae){
								System.err.println(factory + " could not be accessed");					
							}
							
						}
						else if(qname.equals("separator")){
							figures.addSeparator();		
							toolBar.addSeparator();			
						}
					}
					catch(Exception e){
						System.out.println("Other exception:" + e);
					}
				}
			}
			);
		}
		catch(Exception e){
			System.out.println("could not read property file jdraw.xml");
		}

		
		// FILE MENU
		/////////////
		
		JMenuItem open = new JMenuItem("Open");
		file.add(open);
		open.setAccelerator(KeyStroke.getKeyStroke("control O"));
		open.addActionListener(
			new ActionListener(){
				public void actionPerformed(ActionEvent e){
					doOpen();
				}
			}
		);
		
		JMenuItem save = new JMenuItem("Save");
		save.setAccelerator(KeyStroke.getKeyStroke("control S"));
		file.add(save);
		save.addActionListener(
			new ActionListener(){
				public void actionPerformed(ActionEvent e){
					doSave();
				}
			}
		);
		
		JMenuItem exit = new JMenuItem("Exit");
		file.add(exit);
		exit.addActionListener(
			new ActionListener(){
				public void actionPerformed(ActionEvent e){
					System.exit(0);
				}
			}
		);
			
		
		// EDIT MENU
		////////////
		
		JMenuItem sa = new JMenuItem("SelectAll");
		sa.setAccelerator(KeyStroke.getKeyStroke("control A"));
		edit.add(sa);
		sa.addActionListener(
			new ActionListener(){
				public void actionPerformed(ActionEvent e){
					Iterator it = v.getModel().getFigures();
					while(it.hasNext()){
						v.addToSelection((Figure)it.next());
					}
					v.repaint();
				}
			}
		);
		
		edit.addSeparator();
		
		JMenuItem cut = new JMenuItem("Cut");
		cut.setAccelerator(KeyStroke.getKeyStroke("control X"));
		cut.addActionListener(new ActionListener () {
			public void actionPerformed(ActionEvent e) {
				clipboard.cut(v.getSelection(), v.getModel());
			}
		});
		edit.add(cut);
		
		JMenuItem copy = new JMenuItem("Copy");
		copy.setAccelerator(KeyStroke.getKeyStroke("control C"));
		copy.addActionListener(new ActionListener () {
			public void actionPerformed(ActionEvent e) {
				clipboard.copy(v.getSelection());
			}
		});
		edit.add(copy);
		
		JMenuItem paste = new JMenuItem("Paste");
		paste.setAccelerator(KeyStroke.getKeyStroke("control V"));
		paste.addActionListener(new ActionListener () {
			public void actionPerformed(ActionEvent e) {
				clipboard.paste(v.getModel());
			}
		});
		edit.add(paste);
		
		edit.addSeparator();
		JMenuItem group = new JMenuItem("Group");
		group.setAccelerator(KeyStroke.getKeyStroke("control G"));
		group.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				DrawModel model = v.getModel();
				Set selection = v.getSelection();
				if (!selection.isEmpty()) {
					Figure g = new GroupFigure(selection);
					Iterator it = selection.iterator();
					while(it.hasNext()) {
						Figure f = (Figure)it.next();
						v.removeFromSelection(f);
						model.removeFigure(f);
					}
					model.addFigure(g);
					v.addToSelection(g);
				}
			}
		});
		edit.add(group);
		
		JMenuItem ungroup = new JMenuItem("Ungroup");
		ungroup.setAccelerator(KeyStroke.getKeyStroke("control U"));
		ungroup.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Set selection = v.getSelection();
				Iterator it = selection.iterator();
				while(it.hasNext()) {
					Figure g = (Figure)it.next();
					if (g instanceof GroupFigure) {
						DrawModel model = v.getModel();
						GroupFigure gf = (GroupFigure)g;
						v.removeFromSelection(gf);
						model.removeFigure(gf);
						
						Iterator iter = gf.unGroup().iterator();
						while(iter.hasNext()) {
							Figure f = (Figure)iter.next();
							model.addFigure(f);
							v.addToSelection(f);
						}
					}
				}
			}
		});
		edit.add(ungroup);
		
		edit.addSeparator();
		
		JMenu grid = new JMenu("Grid");

		JRadioButtonMenuItem nogrid = new JRadioButtonMenuItem("None");
		nogrid.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				v.setConstrainer(null);
			}
		});

		JRadioButtonMenuItem grid5 = new JRadioButtonMenuItem("5x5");
		grid5.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (((AbstractButton)e.getSource()).isSelected()) v.setConstrainer(new Grid5());
				else v.setConstrainer(null);
			}
		});

		JRadioButtonMenuItem grid10 = new JRadioButtonMenuItem("10x10");
		grid10.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (((AbstractButton)e.getSource()).isSelected()) v.setConstrainer(new Grid10());
				else v.setConstrainer(null);
			}
		});
		
		ButtonGroup gg = new ButtonGroup();
		gg.add(nogrid);
		gg.add(grid5);
		gg.add(grid10);
		gg.setSelected(nogrid.getModel(), true);

		
		edit.add(grid);
		grid.add(nogrid);
		grid.add(grid5);
		grid.add(grid10);
		
		// DECORATOR MENU
		////////////
		JMenuItem border = new JMenuItem("Border");
		border.setAccelerator(KeyStroke.getKeyStroke("control B"));
		border.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Set selection = v.getSelection();
				Iterator it = selection.iterator();
				while (it.hasNext()) {
					Figure f = (Figure)it.next();
					Figure g = new BorderDecorator(f);
					v.removeFromSelection(f);
					v.getModel().removeFigure(f);
					v.getModel().addFigure(g);
					v.addToSelection(g);
				}
			}
		});

		JMenuItem bundle = new JMenuItem("Bundle");
		bundle.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Set selection = v.getSelection();
				Iterator it = selection.iterator();
				while (it.hasNext()) {
					Figure f = (Figure)it.next();
					Figure g = new BundleDecorator(f);
					v.removeFromSelection(f);
					v.getModel().removeFigure(f);
					v.addToSelection(g);
					v.getModel().addFigure(g);
				}
			}
		});

		JMenuItem logger = new JMenuItem("Logger");
		logger.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Set selection = v.getSelection();
				Iterator it = selection.iterator();
				while (it.hasNext()) {
					Figure f = (Figure)it.next();
					Figure g = new LogDecorator(f);
					v.removeFromSelection(f);
					v.getModel().removeFigure(f);
					v.addToSelection(g);
					v.getModel().addFigure(g);
				}
			}
		});

		decorations.add(border);
		decorations.add(bundle);
		decorations.add(logger);
				
		// WINDOW MENU
		//////////////
		
		JMenuItem newWindow = new JMenuItem("New Window");
		window.add(newWindow);
		newWindow.addActionListener(
			new ActionListener(){
				public void actionPerformed(ActionEvent e){
					Draw d = new Draw(v.getModel());
					d.rootFrame.setSize(600,400);
					d.rootFrame.setVisible(true);
				}
			}
		);

	}
	
	private void addFigureMenuEntry(JMenu figures, String name, final DrawTool tool){
		final JMenuItem m = new JMenuItem(name);
		figures.add(m);
		m.addActionListener(
			new ActionListener(){
				public void actionPerformed(ActionEvent e){
					v.setTool(tool);
				}
			}
		);
	}
	
	private void addToolBarEntry(JToolBar toolbar, String name, DrawTool tool, 
									String iconName, DrawEditor editor){
		Icon icon = new ImageIcon(getClass().getResource(iconName));
		addToolBarEntry(toolbar, name, tool, icon, editor);
	}

	private void addToolBarEntry(JToolBar toolbar, String name, final DrawTool tool, 
									Icon icon, DrawEditor editor){
		jdraw.std.ToolButton button;
		button = new jdraw.std.ToolButton(name, icon, tool, editor);
		toolbar.add(button);
		tools.add(button);
		button.addActionListener(
			new ActionListener(){
				public void actionPerformed(ActionEvent e){
					v.setTool(tool);
				}
			}
		);
	}
	
	private void checkTools(){
		Iterator it = tools.iterator();
		while(it.hasNext()){
			Object x = it.next();
			if(x instanceof jdraw.std.ToolButton){
				((jdraw.std.ToolButton)x).checkState();
				((jdraw.std.ToolButton)x).repaint();
			}
		}
	}
	
	
	private void doOpen(){
		JFileChooser chooser = new JFileChooser(
			getClass().getResource("").getFile()
		);
		chooser.setDialogTitle("Open Graphic");
		chooser.setDialogType(JFileChooser.OPEN_DIALOG);
		chooser.setFileFilter(
			new javax.swing.filechooser.FileFilter(){
				public String getDescription(){return "JDraw Graphic (*.draw)";}
				public boolean accept(File f){return f.getName().endsWith(".draw");}
			}
		);
		int res = chooser.showOpenDialog(rootFrame);
		
		if(res == JFileChooser.APPROVE_OPTION) {
			// read jdraw graphic
			File f = chooser.getSelectedFile();
			v.getModel().loadFigures(f);
		}
	}
	
	private void doSave(){
		JFileChooser chooser = new JFileChooser(
			getClass().getResource("").getFile()
		);
		chooser.setDialogTitle("Save Graphic");
		chooser.setDialogType(JFileChooser.SAVE_DIALOG);
		chooser.setFileFilter(
			new javax.swing.filechooser.FileFilter(){
				public String getDescription(){return "JDraw Graphic (*.draw)";}
				public boolean accept(File f){return f.getName().endsWith(".draw");}
			}
		);
		int res = chooser.showOpenDialog(rootFrame);
		
		if(res == JFileChooser.APPROVE_OPTION) {
			// save graphic
			File f = chooser.getSelectedFile();
			v.getModel().saveFigures(f);
		}
	}
	
	void close(){
		if(windowNr == 0){
			System.exit(0);
		}
	}
}

