package jp.sourceforge.acerola3d.a3board;

import jp.sourceforge.acerola3d.*;
import jp.sourceforge.acerola3d.a3.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.swing.*;
import javax.vecmath.*;

public class A3Board implements ActionListener {
    JFrame frame;
    JMenuBar menuBar;
    JMenu fileMenu;
    JMenu configMenu;
    JMenuItem loadMenuItem;
    JMenuItem consoleMenuItem;
    JMenuItem proxyMenuItem;
    JMenuItem resetViewMenuItem;
    JMenuItem snapshotMenuItem;
    JMenuItem backgroundMenuItem;
    JMenuItem exitMenuItem;
    JMenuItem headLightMenuItem;
    JCheckBox simpleModeCheckBox;
    JCheckBox walkModeCheckBox;
    JCheckBox flyModeCheckBox;
    JCheckBox editModeCheckBox;
    JCheckBox examModeCheckBox;
    JFileChooser fileChooser = new JFileChooser(".");;
    A3Canvas a3canvas;
    JLabel objectNameLabel;
    JButton deleteButton;
    JComboBox actionNameCB;
    JButton resetViewButton;
    JLabel statusBarLabel;
    JFrame consoleFrame;
    JTextArea consoleTextArea;
    JButton clearConsoleButton;
    Vector3d cameraV = new Vector3d(0.0,0.0,2.0);
    Quat4d cameraQ = new Quat4d(0.0,0.0,0.0,1.0);
    enum Mode {SIMPLE,WALK,FLY,EDIT,EXAM}
    Mode mode = Mode.SIMPLE;
    boolean headLight = true;

    A3Object selectedA3Object = null;
    String actionName = "0";
    ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);

    public A3Board(String args[]) {
        frame = new JFrame("A3Board");
        Box baseBox = Box.createVerticalBox();
        frame.getContentPane().add(baseBox);

        menuBar = new JMenuBar();
        frame.setJMenuBar(menuBar);

        menuBar.add(Box.createHorizontalGlue());

        fileMenu = new JMenu("File");
        menuBar.add(fileMenu);
        loadMenuItem = new JMenuItem("Load");
        loadMenuItem.addActionListener(this);
        fileMenu.add(loadMenuItem);
        backgroundMenuItem = new JMenuItem("Background");
        backgroundMenuItem.addActionListener(this);
        fileMenu.add(backgroundMenuItem);
        snapshotMenuItem = new JMenuItem("Snapshot");
        snapshotMenuItem.addActionListener(this);
        fileMenu.add(snapshotMenuItem);
        exitMenuItem = new JMenuItem("Exit");
        exitMenuItem.addActionListener(this);
        fileMenu.add(exitMenuItem);

        configMenu = new JMenu("Config");
        menuBar.add(configMenu);
        consoleMenuItem = new JMenuItem("Console");
        consoleMenuItem.addActionListener(this);
        configMenu.add(consoleMenuItem);
        proxyMenuItem = new JMenuItem("Proxy");
        proxyMenuItem.addActionListener(this);
        configMenu.add(proxyMenuItem);
        resetViewMenuItem = new JMenuItem("ResetView");
        resetViewMenuItem.addActionListener(this);
        configMenu.add(resetViewMenuItem);
        headLightMenuItem = new JMenuItem("HeadLight");
        headLightMenuItem.addActionListener(this);
        configMenu.add(headLightMenuItem);
        

        consoleFrame = new JFrame("Console");
        Box b = Box.createVerticalBox();
        consoleTextArea = new JTextArea(20,60);
        consoleTextArea.setEditable(false);
        JScrollPane sp = new JScrollPane(consoleTextArea);
        b.add(sp);
        clearConsoleButton = new JButton("Clear");
        clearConsoleButton.addActionListener(this);
        b.add(clearConsoleButton);
        consoleFrame.getContentPane().add(b);
        consoleFrame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent we) {
                consoleFrame.setVisible(false);
            }
        });
        PrintStream systemOut = System.out;
        JTextAreaOutputStream jtaos = new JTextAreaOutputStream(consoleTextArea,systemOut);
        PrintStream ps = new PrintStream(jtaos,true);
        System.setOut(ps);
        System.setErr(ps);
        consoleFrame.pack();
        
        Box box1 = Box.createHorizontalBox();
        baseBox.add(box1);
        ButtonGroup bg = new ButtonGroup();
        simpleModeCheckBox = new JCheckBox("simple");
        simpleModeCheckBox.addActionListener(this);
        box1.add(simpleModeCheckBox);
        bg.add(simpleModeCheckBox);
        walkModeCheckBox = new JCheckBox("walk");
        walkModeCheckBox.addActionListener(this);
        box1.add(walkModeCheckBox);
        bg.add(walkModeCheckBox);
        flyModeCheckBox = new JCheckBox("fly");
        flyModeCheckBox.addActionListener(this);
        box1.add(flyModeCheckBox);
        bg.add(flyModeCheckBox);
        editModeCheckBox = new JCheckBox("edit");
        editModeCheckBox.addActionListener(this);
        box1.add(editModeCheckBox);
        bg.add(editModeCheckBox);
        examModeCheckBox = new JCheckBox("exam");
        examModeCheckBox.addActionListener(this);
        box1.add(examModeCheckBox);
        bg.add(examModeCheckBox);

        Box box2 = Box.createHorizontalBox();
        baseBox.add(box2);

//A3Canvas.setUpperDirection(A3Canvas.UpperDirection.Z);
        a3canvas = A3Canvas.createA3Canvas(300,300);
        a3canvas.setCameraLocImmediately(cameraV);
        a3canvas.setCameraQuatImmediately(cameraQ);
        a3canvas.addKeyListener(new MyKeyAdapter());
        a3canvas.addA3Listener(new MyA3Adapter());
        a3canvas.setHeadLightEnable(headLight);
        box2.add(a3canvas);

        simpleModeCheckBox.setSelected(true);
        a3canvas.setNavigationMode(A3Canvas.NaviMode.SIMPLE);

        Box controlBox = makeControlBox();
        box2.add(controlBox);

        statusBarLabel = new JLabel("Status:");
        baseBox.add(statusBarLabel);

        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent we) {
                frame.dispose();
                System.exit(0);
            }
        });
        frame.setSize(700,500);
        frame.setVisible(true);

        fileChooser = new JFileChooser();
        fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
        
        //Runnable r = new Runnable() {
        //    public void run() {
        //        loadAction3D();
        //    }
        //};
        //executor.schedule(r,100,TimeUnit.MILLISECONDS);

        frame.setTransferHandler(new A3TransferHandler(this));
    }

    Box makeControlBox() {
        Box controlBox = Box.createVerticalBox();
        controlBox.add(new JLabel("ObjectName:"));
        objectNameLabel = new JLabel("0:null");
        controlBox.add(objectNameLabel);

        deleteButton = new JButton("delete");
        deleteButton.addActionListener(this);
        controlBox.add(deleteButton);

        controlBox.add(new JLabel("ActionName:"));
        actionNameCB = new JComboBox();
actionNameCB.setPreferredSize(new Dimension(150,30));
actionNameCB.setMaximumSize(new Dimension(150,30));
        actionNameCB.addActionListener(this);
        controlBox.add(actionNameCB);

        resetViewButton = new JButton("Reset View");
        resetViewButton.addActionListener(this);
        controlBox.add(resetViewButton);

        controlBox.add(new JLabel("Left drag: rotation"));
        controlBox.add(new JLabel("Center drag: translation"));
        controlBox.add(new JLabel("Right drag: scale"));

        controlBox.add(Box.createVerticalGlue());

        String buildDate = null;
        try {
            URL url = getClass().getClassLoader().getResource("buildDate.txt");
            InputStreamReader isr = new InputStreamReader(url.openStream(),"UTF-8");
            BufferedReader br = new BufferedReader(isr);
            buildDate = br.readLine();
        } catch (Exception e) {
            buildDate = "???";
        }
        controlBox.add(new JLabel("build date:"));
        controlBox.add(new JLabel("   "+buildDate));

        return controlBox;
    }

    public void actionPerformed(ActionEvent ae) {
        if (ae.getSource() == actionNameCB) {
            actionName = (String)actionNameCB.getSelectedItem();
if (actionName == null) {
System.out.println("gaha1");
return;
}
            System.out.println("actionName:"+actionName);
            repaint();
        } else if (ae.getSource() == loadMenuItem) {
            Runnable r = new Runnable() {
                public void run() {
                    loadAction3D();
                }
            };
            executor.schedule(r,100,TimeUnit.MILLISECONDS);
        } else if (ae.getSource() == simpleModeCheckBox) {
            mode = Mode.SIMPLE;
            a3canvas.setNavigationMode(A3Canvas.NaviMode.SIMPLE);
            System.out.println("Mode: SIMPLE");
        } else if (ae.getSource() == walkModeCheckBox) {
            mode = Mode.WALK;
            a3canvas.setNavigationMode(A3Canvas.NaviMode.WALK);
            System.out.println("Mode: WALK");
        } else if (ae.getSource() == flyModeCheckBox) {
            mode = Mode.FLY;
            a3canvas.setNavigationMode(A3Canvas.NaviMode.FLY);
            System.out.println("Mode: FLY");
        } else if (ae.getSource() == editModeCheckBox) {
            mode = Mode.EDIT;
            a3canvas.setNavigationMode(A3Canvas.NaviMode.EDIT);
            System.out.println("Mode: EDIT");
        } else if (ae.getSource() == examModeCheckBox) {
            mode = Mode.EXAM;
            a3canvas.setNavigationMode(A3Canvas.NaviMode.EXAMINE);
            System.out.println("Mode: EXAM");
        } else if (ae.getSource() == deleteButton) {
            if (selectedA3Object!=null)
                a3canvas.del(selectedA3Object);
        } else if (ae.getSource() == resetViewButton) {
            cameraV.set(0.0,0.0,2.0);
            cameraQ.set(0.0,0.0,0.0,1.0);
            a3canvas.setCameraLocImmediately(cameraV);
            a3canvas.setCameraQuatImmediately(cameraQ);
            //a3canvas.resetExamineNaviParameters();
        } else if (ae.getSource() == consoleMenuItem) {
            consoleFrame.setVisible(true);
        } else if (ae.getSource() == clearConsoleButton) {
            consoleTextArea.setText("");
        } else if (ae.getSource() == proxyMenuItem) {
            proxyConfig();
        } else if (ae.getSource() == resetViewMenuItem) {
            cameraV.set(0.0,0.0,2.0);
            cameraQ.set(0.0,0.0,0.0,1.0);
            a3canvas.setCameraLocImmediately(cameraV);
            a3canvas.setCameraQuatImmediately(cameraQ);
            //a3canvas.resetExamineNaviParameters();
        } else if (ae.getSource() == headLightMenuItem) {
            headLight = !headLight;
            a3canvas.setHeadLightEnable(headLight);
        } else if (ae.getSource() == snapshotMenuItem) {
            try {
                File f = new File("snapshot.png");
                a3canvas.saveImage(f);
            } catch (Exception e) {
                System.out.println("A3Board:snapshot");
                e.printStackTrace();
            }
        } else if (ae.getSource() == backgroundMenuItem){
            setBackground();
        } else if (ae.getSource() == exitMenuItem){
            System.exit(0);
        } else {
            System.out.append("gaha???");
        }
    }

    void loadAction3D() {
        int returnVal = fileChooser.showOpenDialog(frame);
        if (returnVal != JFileChooser.APPROVE_OPTION)
            return;

        File f = fileChooser.getSelectedFile();
        loadAction3DFromFile(f);
    }
    void loadAction3DFromFile(File f) {
        Action3D.clearCash();

        URL url = null;
        try{url = new URL(f.toURI().toString());}catch(Exception e){;}
        if (url == null)
            return;
        statusBarLabel.setText("Status: Loading ... ");
        statusBarLabel.repaint();
        Action3D a3 = null;
        try {
        	A23.initA23();
            a3 = Action3D.load(url);
        } catch(Exception e) {
            System.out.println("A3Board.loadAction3D. error!");
            e.printStackTrace();
        }

        actionNameCB.removeAllItems();
        String sss[] = a3.getActionNames();
        for (int i=0;i<sss.length;i++)
            actionNameCB.addItem(sss[i]);
        a3canvas.add(a3);

        if (selectedA3Object!=null)
            selectedA3Object.setSelected(false);
        a3.setSelected(true);
        selectedA3Object = a3;

        statusBarLabel.setText("Status: Loading ... done.");
    }
    void loadAction3D(final File f) throws Exception {
        Runnable r = new Runnable() {
            public void run() {
                loadAction3DFromFile(f);
            }
        };
        executor.schedule(r,100,TimeUnit.MILLISECONDS);
    }

    void repaint() {
        if (selectedA3Object == null)
            return;
        if (!(selectedA3Object instanceof Action3D))
            return;
        ((Action3D)selectedA3Object).changeImmediately(actionName);
    }

    ProxyPanel proxyPanel = null;
    String proxyData[] = {"","","",""};
    void proxyConfig() {
        if (proxyPanel == null) {
            proxyPanel = new ProxyPanel();
            proxyData[0] = System.getProperty("proxyHost");
            proxyData[1] = System.getProperty("proxyPort");
            proxyData[2] = System.getProperty("ftpProxyHost");
            proxyData[3] = System.getProperty("ftpProxyPort");
        }
        proxyPanel.setData(proxyData);

        Object options[] = {"Ok","Cancel"};
        int result = JOptionPane.showOptionDialog(frame,proxyPanel,"proxy",
                                                  JOptionPane.DEFAULT_OPTION,
                                                  JOptionPane.INFORMATION_MESSAGE,
                                                  null,options,options[0]);
        if (result==0) {
            proxyData = proxyPanel.getData();
            if (!proxyData[0].equals("")) {
                System.getProperties().put("proxySet","true");
                System.getProperties().put("proxyHost",proxyData[0]);
                System.getProperties().put("proxyPort",proxyData[1]);
            } else {
                System.getProperties().put("proxySet","false");
                System.getProperties().put("proxyHost","");
                System.getProperties().put("proxyPort","");
            }
            if (!proxyData[2].equals("")) {
                System.getProperties().put("ftpProxySet","true");
                System.getProperties().put("ftpProxyHost",proxyData[2]);
                System.getProperties().put("ftpProxyPort",proxyData[3]);
            } else {
                System.getProperties().put("ftpProxySet","false");
                System.getProperties().put("ftpProxyHost","");
                System.getProperties().put("ftpProxyPort","");
            }
        }
    }

    class ProxyPanel extends JPanel {
        private static final long serialVersionUID = 1L;
        JTextField httpHostTF;
        JTextField httpPortTF;
        JTextField ftpHostTF;
        JTextField ftpPortTF;

        public ProxyPanel() {
            Box b0 = Box.createVerticalBox();
            Box b1 = Box.createHorizontalBox();
            Box b2 = Box.createHorizontalBox();

            this.add(b0);
            b0.add(b1);
            b0.add(b2);

            b1.add(new JLabel("http: host"));
            httpHostTF = new JTextField(40);
            b1.add(httpHostTF);
            b1.add(new JLabel(" port "));
            httpPortTF = new JTextField(5);
            b1.add(httpPortTF);

            b2.add(new JLabel("ftp: host"));
            ftpHostTF = new JTextField(40);
            b2.add(ftpHostTF);
            b2.add(new JLabel(" port "));
            ftpPortTF = new JTextField(5);
            b2.add(ftpPortTF);
        }

        public void setData(String proxyData[]) {
            httpHostTF.setText(proxyData[0]);
            httpPortTF.setText(proxyData[1]);
            ftpHostTF.setText(proxyData[2]);
            ftpPortTF.setText(proxyData[3]);
        }

        public String[] getData() {
            String ret[] = new String[4];
            ret[0] = httpHostTF.getText();
            ret[1] = httpPortTF.getText();
            ret[2] = ftpHostTF.getText();
            ret[3] = ftpPortTF.getText();
            return ret;
        }
    }

    void setBackground() {
        int returnVal = fileChooser.showOpenDialog(frame);
        if (returnVal != JFileChooser.APPROVE_OPTION)
            return;

        File f = fileChooser.getSelectedFile();
        URL url = null;
        try{url = new URL(f.toURI().toString());}catch(Exception e){;}
        if (url == null)
            return;
        Action3D a = null;
        try{
            a = Action3D.load(url);
        } catch(Exception e) {
            e.printStackTrace();
        }
        if (a!=null)
            a3canvas.setBackground(a);
    }

    public static void main(String args[]) {
        // セキュリティマネージャが、
        // LinuxのJava Web Startの時だけ
        // Exceptionを出すので、とりあえずnullに
        // しておく。
        System.setSecurityManager(null);
        final String argsCopy[] = args;
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new A3Board(argsCopy);
            }
        });
    }

    class MyKeyAdapter extends KeyAdapter {
        public void keyTyped(KeyEvent ke) {
            System.out.println("'"+ke.getKeyChar()+"' pressed.");
        }
    }
    class MyA3Adapter extends A3Adapter {
        public void mouseClicked(A3Event ae) {
            A3Object a3 = ae.getA3Object();
            if (a3==null) {
                if (selectedA3Object!=null) {
                    selectedA3Object.setSelected(false);
                    selectedA3Object = null;
                }
            } else {
                if (selectedA3Object!=null)
                    selectedA3Object.setSelected(false);
                a3.setSelected(true);
                selectedA3Object = a3;
                if (a3 instanceof Action3D) {
                    int an = ((Action3D)a3).getActionNo();
                    actionNameCB.removeAllItems();
                    String sss[] = ((Action3D)a3).getActionNames();
                    for (int i=0;i<sss.length;i++)
                        actionNameCB.addItem(sss[i]);
                    actionNameCB.setSelectedIndex(an);
                }
            }
        }
        public void mouseDoubleClicked(A3Event ae) {
            A3Object a3 = ae.getA3Object();
            if (a3==null)
                return;
System.out.println("double clicked!");
        }
    }
}
