package pbl2011.gui;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.WindowConstants;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;

import pbl2011.common.CommonConst;
import pbl2011.common.Util;
import pbl2011.mvc.Model;
import ash.gui.core.AshMenu;
import ash.gui.editor.core.AshEditorArea;
import ash.gui.editor.core.AshEditorFrame;
import ash.reverse.uml.UMLTool;			// CA,20111217

/**
 * クラス図エディタ
 * <p>
 *
 * @author 10745104 Y.Ishii
 *
 */

@SuppressWarnings("serial")
public class ClassEditorFrame extends AshEditorFrame implements CommonConst {
	public static void main(String[] args) {
		ClassEditorFrame frame = new ClassEditorFrame(FRAME_TITLE);
		GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
        Rectangle rect = env.getMaximumWindowBounds();
        frame.setBounds(rect);

        ClassLoader cloader = Util.getClassLoader(ClassEditorFrame.class);
        frame.setIconImage(Toolkit.getDefaultToolkit().createImage
        		(cloader.getResource("img/ICON.png")));
		frame.setVisible(true);
	}

	ClassEditorFrame(String title) {
		super(title);
		setSize(1600, 1000);
		setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
	}
	ClassEditorArea editArea ;
	@Override protected Component createWorkArea() {
 		editArea = createEditArea();
		setEditArea(editArea);
  		createPopupMenu(editArea.getEditArea());
		return editArea.getEditArea();
 	}
	@Override protected ClassEditorArea createEditArea() {
		return new ClassEditorArea(this);
	}

	JComboBox attributeJcb;
	JComboBox methodJcb;
	JToolBar bar;

	/*
	 * ツールバー生成
	 */
	@Override protected JToolBar createToolBar() {

		bar = new JToolBar();
		createJButton(CREATE, FILE_OPEN, FILE_OPEN_TOOLTIP);
		createJButton(SAVE, FILE_SAVEAS, FILE_SAVE_TOOLTIP);

		State.selectJtg = createJToggleButton(SELECT, MOD_SELECT, MOD_SELECT_TOOLTIP, true);
		JToggleButton classJtg = createJToggleButton(ClassType.CLASS.alias(), ADD_CLASS, ADD_CLASS_TOOLTIP, false);
		JToggleButton arcJtg = createJToggleButton(AssocType.ASSOC.alias(), ADD_ASSOC, ADD_ASSOC_TOOLTIP, false);
		JToggleButton extJtg = createJToggleButton(AssocType.EXTENDS.alias(), ADD_EXTENDS, ADD_EXTENDS_TOOLTIP, false);
		JToggleButton depJtg = createJToggleButton(AssocType.DEPENDS.alias(), ADD_DEPENDS, ADD_DEPENDS_TOOLTIP, false);
		createJToggleButton(GRID, MOD_GRID, MOD_GRID_TOOLTIP, true);
		createJToggleButton(GRIDLINE, MOD_GRIDLINE, MOD_GRIDLINE_TOOLTIP, true);

		State.toggleBtnList = new ArrayList<JToggleButton> ();
		State.toggleBtnList.add(State.selectJtg);
		State.toggleBtnList.add(classJtg);
		State.toggleBtnList.add(arcJtg);
		State.toggleBtnList.add(extJtg);
		State.toggleBtnList.add(depJtg);

		createJLabel(LABEL_ATTRIBUTE,LABEL_ATTRIBUTE_TOOLTIP);
		attributeJcb = createJComboBox(VISIBILITY_LIST, 3, VISIBILITY_ATTRIBUTE, new Dimension(120, 30));
		createJLabel(LABEL_METHOD,LABEL_METHOD_TOOLTIP);
		methodJcb = createJComboBox(VISIBILITY_LIST, 3, VISIBILITY_METHOD, new Dimension(120, 30));

		return bar;
	}

	private JButton createJButton(String img, String command, String tooltip) {
		JButton jButton= new JButton(makeImageIcon(img));
		jButton.addActionListener(this);
		jButton.setActionCommand(command);
		jButton.setToolTipText(tooltip);
		bar.add(jButton);
		return jButton;
	}

	private JToggleButton createJToggleButton(String img, String command, String tooltip, boolean flg) {
		JToggleButton jToggleButton= new JToggleButton(makeImageIcon(img), flg);
		jToggleButton.addActionListener(this);
		jToggleButton.setActionCommand(command);
		jToggleButton.setToolTipText(tooltip);
		bar.add(jToggleButton);
		return jToggleButton;
	}

	private ImageIcon makeImageIcon(String name) {
	    ClassLoader cloader = Util.getClassLoader(this.getClass());
		return new ImageIcon(cloader.getResource("img/" + name + ".png"));
	}

	private JLabel createJLabel(String text, String tooltip) {
		JLabel jLabel= new JLabel(text);
		jLabel.setToolTipText(tooltip);
		bar.add(jLabel);
		return jLabel;
	}

	private JComboBox createJComboBox(String[] list, int index, String command, Dimension d) {
		JComboBox jComboBox = new JComboBox(list);
		jComboBox.setSelectedIndex(index);
		jComboBox.addActionListener(this);
		jComboBox.setActionCommand(command);
		jComboBox.setMaximumSize(d);
		bar.add(jComboBox);
		return jComboBox;
	}

	@Override protected JMenuBar createMenuBar() {
		JMenuBar mbar = new JMenuBar();
		mbar.add(new FileMenu());
		mbar.add(new EditMenu());
		mbar.add(new ViewMenu());
		mbar.add(new SrcMenu());
		return mbar;
	}
	
	@Override protected void disposeFrame() {
		if(confirmDispose()) {
			disposeEditorResource();
			dispose();
			System.exit(0);
		}
	}

	@Override protected boolean confirmDispose() {
		editArea.setModified(m.isModified());
		return super.confirmDispose();
	}
	private static final String FILE_OPEN_TOOLTIP = "ファイルを開く";
	private static final String FILE_SAVE_TOOLTIP = "ファイルに保存";

	private static final String EDIT_COMMAND = actionName();
	private static final String MOD_SELECT = actionName();
	private static final String MOD_SELECT_TOOLTIP = "選択モード";
	private static final String ADD_CLASS = actionName();
	private static final String ADD_CLASS_TOOLTIP = "クラス";
	private static final String ADD_ASSOC = actionName();
	private static final String ADD_ASSOC_TOOLTIP = "関連";
	private static final String ADD_EXTENDS = actionName();
	private static final String ADD_EXTENDS_TOOLTIP = "汎化";
	private static final String ADD_DEPENDS = actionName();
	private static final String ADD_DEPENDS_TOOLTIP = "依存";
	private static final String OUTPUT_JAVA = actionName();
	private static final String OUTPUT_IMAGE = actionName();

	private static final String MOD_GRID = actionName();
	private static final String MOD_GRID_TOOLTIP = "補助線 ON/OFF";
	private static final String MOD_GRIDLINE = actionName();
	private static final String MOD_GRIDLINE_TOOLTIP = "グリッド ON/OFF";
	private static final String VISIBILITY_ATTRIBUTE = actionName();
	private static final String VISIBILITY_METHOD = actionName();

	private static final String LABEL_ATTRIBUTE = "　属性：";
	private static final String LABEL_METHOD = "　操作：";
	private static final String LABEL_ATTRIBUTE_TOOLTIP = "属性 ON/OFF";
	private static final String LABEL_METHOD_TOOLTIP = "操作 ON/OFF";

	protected static final String AUTO_ADJUST = actionName();
	protected static final String CANVAS_SIZE = actionName();
	protected static final String IMPORT_PUBLIC = actionName();
	protected static final String IMPORT_PROTECTED = actionName();
	protected static final String IMPORT_PACKAGE = actionName();
	protected static final String IMPORT_PRIVATE = actionName();
	protected static final String IMPORT_CLASS = actionName();
	protected static final String IMPORT_P = actionName();
	protected static final String IMPORT_PR = actionName();
	protected static final String IMPORT_PD = actionName();
	protected static final String IMPORT_PRD = actionName();
	protected static final String MULTI_INHERIT = actionName();

	protected class EditMenu extends AshEditorFrame.EditMenu {
		EditMenu() {
			setup("編集(E)");
			setActionListener(ClassEditorFrame.this);
			constructBasics();
			addSeparator();
			add("編集コマンド", EDIT_COMMAND);
			constructUndo();

		}
	}

	protected class ViewMenu extends AshMenu {
		ViewMenu() {
			setup("表示(V)");
			setActionListener(ClassEditorFrame.this);
			add("フォント(F)",   VIEW_FONT);
			add("サイズ自動調整(A)", AUTO_ADJUST);
			add("描画サイズ変更(C)", CANVAS_SIZE);
			addSeparator();
			add(makeStatusMenuItem());
		}
	}

	protected class SrcMenu extends AshMenu {
		SrcMenu() {
			setup("ツール(T)");
			setActionListener(ClassEditorFrame.this);
			add("ソースコード生成(J)", OUTPUT_JAVA);
			add(new ClassMenu());
			add(new PackgeMenu());
			add("画像生成(I)", OUTPUT_IMAGE);
			add(new CheckMenu());
		}
	}

	protected class ClassMenu extends AshMenu {
		ClassMenu() {
			setup("クラス図生成(C)");
			setActionListener(ClassEditorFrame.this);
			add("クラスのみ", IMPORT_CLASS);
			add("public",  IMPORT_PUBLIC);
			add("protected", IMPORT_PROTECTED);
			add("package", IMPORT_PACKAGE);
			add("private", IMPORT_PRIVATE);
		}
	}

	protected class PackgeMenu extends AshMenu {
		PackgeMenu() {
			setup("パッケージ図生成(P)");
			setActionListener(ClassEditorFrame.this);
			add("パッケージのみ", IMPORT_P);
			add("参照を含む",  IMPORT_PR);
			add("クラスを含む",  IMPORT_PD);
			add("参照・クラスを含む", IMPORT_PRD);
		}
	}
	protected class CheckMenu extends AshMenu {
		CheckMenu() {
			setup("設計チェック(D)");
			setActionListener(ClassEditorFrame.this);
			add("多重継承チェック", MULTI_INHERIT);
		}
	}

	protected Model m ;
	protected Model getModel() {

		if (m == null) {
			m = new Model();
		}
		return m;
	}
	protected UMLCanvas mainCanvas ;
	protected UMLCanvas getMainCanvas() {

		if (mainCanvas == null) {
			mainCanvas = new UMLCanvas(1, getModel());
		}
		return mainCanvas;
	}
	protected UMLCanvas subCanvas ;
	protected UMLCanvas getSubCanvas() {

		if (subCanvas == null) {
			subCanvas = new UMLCanvas(4, getModel());
		}
		return subCanvas;
	}
	/*
	 * アクションの実行
	 *   ActionListener インタフェースの実装
	 */
	public void actionPerformed(ActionEvent ae) {
		String action = ae.getActionCommand();

		 if (MOD_SELECT.equals(action) || ADD_CLASS.equals(action) || ADD_ASSOC.equals(action) ||
				ADD_EXTENDS.equals(action) || ADD_DEPENDS.equals(action) ) {

			JToggleButton Jtg = (JToggleButton)ae.getSource();
			State.classSelect = false;
			State.arcSelect = null;

			if(action.equals(MOD_SELECT)) {
				Jtg.setSelected(true);
			} else if(action.equals(ADD_CLASS)) {
				State.classSelect = Jtg.isSelected();
			} else if (action.equals(ADD_ASSOC)) {
				State.arcSelect = Jtg.isSelected() ? AssocType.ASSOC : null;
			} else if (action.equals(ADD_EXTENDS)) {
				State.arcSelect = Jtg.isSelected() ? AssocType.EXTENDS : null;
			} else if (action.equals(ADD_DEPENDS)) {
				State.arcSelect = Jtg.isSelected() ? AssocType.DEPENDS : null;
			}
			changeButtonSattus(Jtg);
		} else if (MOD_GRID.equals(action)) {
			JToggleButton Jtg = (JToggleButton)ae.getSource();
			if (Jtg.isSelected()) {
				State.gridFlag = true;
			} else {
				State.gridFlag = false;
			}
			getModel().changeModel();
		} else if (MOD_GRIDLINE.equals(action)) {
			JToggleButton Jtg = (JToggleButton)ae.getSource();
			if (Jtg.isSelected()) {
				State.gridlineFlag = true;
			} else {
				State.gridlineFlag = false;
			}
			getModel().changeModel();

		} else if (VISIBILITY_ATTRIBUTE.equals(action)) {
			State.attributeVisibility = VisibilityType.level(attributeJcb.getSelectedItem().toString());
			getModel().changeModel();
		} else if (VISIBILITY_METHOD.equals(action)) {
			State.methodVisibility = VisibilityType.level(methodJcb.getSelectedItem().toString());
			getModel().changeModel();

		} else if (IMPORT_PUBLIC.equals(action)) { // CA,20111217
			excuteImport("c1");
		} else if (IMPORT_PROTECTED.equals(action)) {
			excuteImport("c2");
		} else if (IMPORT_PACKAGE.equals(action)) {
			excuteImport("c3");
		} else if (IMPORT_PRIVATE.equals(action)) {
			excuteImport("c4");
		} else if (IMPORT_CLASS.equals(action)) {
			excuteImport("c");
		} else if (IMPORT_P.equals(action)) {
			excuteImport("p");
		} else if (IMPORT_PR.equals(action)) {
			excuteImport("pr");
		} else if (IMPORT_PD.equals(action)) {
			excuteImport("pd");
		} else if (IMPORT_PRD.equals(action)) {
			excuteImport("prd");

		} else if (AUTO_ADJUST.equals(action)) {
			mainCanvas.autoAdjust();
			getModel().changeModel();
		} else if (CANVAS_SIZE.equals(action)) {
			Rectangle r = CanvasSizePanel.updateSize(this, new Rectangle(State.width,State.height));
			State.width = r.width;
			State.height = r.height;
			mainCanvas.initialize();
			subCanvas.initialize();
			getModel().changeModel();
		} else if (OUTPUT_JAVA.equals(action)) {
			 try {
				getOutputFileChooser();
				int selected = outputFileChooser.showDialog(this,"選択");
				if (selected == JFileChooser.APPROVE_OPTION) {
					File outputDir = outputFileChooser.getSelectedFile();
					getModel().outputJavaCode(outputDir);
				}
			 } catch (IOException e) {
				 	e.printStackTrace();
			 }
		} else if (OUTPUT_IMAGE.equals(action)) {

			getSaveImgChooser();
			if (imgChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
				File fChoosen = imgChooser.getSelectedFile();
				try {
					ImageIO.write(mainCanvas.getCanvasImg(), "png", fChoosen);
				} catch (IOException ex) {
					ex.printStackTrace();
				}
			}
		} else if (MULTI_INHERIT.equals(action)) {
			getModel().checkMultiInherit();
		} else {
			super.actionPerformed(ae);
		}
	}

	private void getSaveImgChooser() {
		if (imgChooser == null) {
			imgChooser = new JFileChooser(".");
			imgChooser.setSelectedFile(new File("image.png"));
			FileFilter filter = new FileNameExtensionFilter("PNGファイル(*.png)",
			"png");
			imgChooser.setFileFilter(filter);
		}
	}

	private void getOutputFileChooser() {
		if (outputFileChooser == null) {
			outputFileChooser = new JFileChooser(".");
			outputFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);			
		}
	}
	
	/** ファイチューザ */
	JFileChooser filechooser = new JFileChooser(".");
	JFileChooser imgChooser = null;
	JFileChooser outputFileChooser = null;

	/**
	 * AshのUMLファイル生成コマンドを呼び出す
	 * @param option
	 */
	private void excuteImport(String option) {
		PrintStream ps = null;
		try {

			filechooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

			int selected = filechooser.showDialog(this,"選択");
			if (selected == JFileChooser.APPROVE_OPTION) {
				File tmp = File.createTempFile("classde",null);
				tmp.deleteOnExit();
				ps = new PrintStream(tmp);

				// CA,20111217 ADD
				UMLTool uml = new UMLTool();
				uml.setFont(State.font);
				uml.setParams(option);
				uml.parse(filechooser.getSelectedFile().getCanonicalPath());
				uml.generateUML(ps);
				// CA,20111217 TO HERE

				BufferedReader br = new BufferedReader(new FileReader(tmp));
				getModel().read(br, tmp);
			}

		} catch (IOException e) {
			JOptionPane.showMessageDialog(null, "ソースの取込に失敗しました",
										  "エラー", JOptionPane.ERROR_MESSAGE);
		} finally {
			if(ps != null) ps.close();
		}
	}
	private void changeButtonSattus(JToggleButton eventBtn) {

		for (JToggleButton btn: State.toggleBtnList) {
			if (eventBtn != btn)
				btn.setSelected(false);
		}
		isSelectState();
	}
	//何も選択していなければ、選択のトグルを選択する
	private void isSelectState() {
		for (JToggleButton btn: State.toggleBtnList) {
			if (btn.isSelected())
				return ;
		}
		State.selectJtg.setSelected(true);
	}
}

class ClassEditorArea extends AshEditorArea {
	ClassEditorFrame editFrame ;
	ClassDiagramsPanel editorView ;
	ClassEditorArea(ClassEditorFrame editFrame) {
		super(editFrame);
		this.editFrame = editFrame;
		editorView = new ClassDiagramsPanel(editFrame);
	}
	@Override protected Component getEditArea() { return editorView; }

	@Override protected void setEditable(boolean editable) { }
	@Override protected boolean isEditable() { return true; }
	@Override protected boolean isSelectable() { return true; }
	@Override protected void setRowColumn(int rows, int columns) {
		editorView.setSize(columns, rows);
	}
	@Override protected void setFont(Font font) {
		editorView.setFont(font);
	}
	@Override protected void setTextData(String text) { }
	@Override
	public boolean isSelected() { return true; }
	@Override
	public String getSelectedText() { return null; }
	@Override protected int getLineCount() { return 0; }
	@Override protected boolean showLine(int lno) { return true; }

	@Override protected void copy() { editorView.copy(); }
	@Override protected void cut() { editorView.cut(); }
	@Override protected void paste() { editorView.paste(); }
	@Override protected void delete() { editorView.delete();}
	@Override protected void selectAll() { editorView.selectAll();}

	@Override public void undo() { editorView.undo();}
	@Override public void redo() { editorView.redo();}

	@Override protected void resetDocument() {
		setCurrentFile(null);
		editFrame.getModel().clearData();
	}
	@Override protected void readDocument(BufferedReader br, File file)
								throws IOException {
		editFrame.getModel().read(br, file);
	}
	@Override protected void writeDocument(BufferedWriter bw, File file)
								throws IOException {
		editFrame.getModel().save(bw, file);
	}

}
