/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on ----
!  AUTHOR(S): KOGA, Junichiro
!  File : MainPanel.java
!  
!  Contact address :  Phase System Consortium
!                     E-mail: phase_system@nims.go.jp URL https://azuma.nims.go.jp
!
!
!   Since 2002, this program set had been intensively developed as a part of the following 
!  national projects supported by the Ministry of Education, Culture, Sports, Science and
!  Technology (MEXT) of Japan; "Frontier Simulation Software for Industrial Science
!  (FSIS)" from 2002 to 2005, "Revolutionary Simulation Software (RSS21)" from 2006 to
!  2008. "Research and Development of Innovative Simulation Software (RISS)" from 2008
!  to 2013. These projects is lead by the Center for Research on Innovative Simulation 
!  Software (CISS), the Institute of Industrial Science (IIS), the University of Tokyo.
!   Since 2013, this program set has been further developed centering on PHASE System
!  Consortium. 
!   The activity of development of this program set has been supervised by Takahisa Ohno.
!
!=======================================================================
 */
package ciss.phase_viewer.imageviewer;

import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import ciss.phase_viewer.common.MyMessageBox;
import ciss.phase_viewer.mainpanel.InternalFrameChase;

/**
 * 画像ファイルとそれを操作するためのボタンを配備したGUIを作成するクラス. 画像ファイルを表示したパネルおよびボタンをそれぞれ作成し, コンテントペインに
 * 貼り付ける. 画像ファイルの情報は, 呼び出し元であるImageLoaderクラスから取得する.
 * 
 * @author KOGA Junichiro,
 */
public class MainPanel extends InternalFrameChase implements ComponentListener {

    private final class MyListener extends WindowAdapter {
        public void windowClosing(WindowEvent event) {
            dispose();
        }
    }

    private Container cont;

    private JDesktopPane desktop;

    private String infile;

    private int iwidth;
    private int iheight;
    private int getaw = 0;
    private int getah = 105;

    private double scale = 1.0d;
    private double rotscale = 0.0d;
    private double rot = 0.d;
    private MyMessageBox mbox = new MyMessageBox();

    private boolean status = true;

    private int pageNum = -1;
    private int page = 0;
    private String[] pageArray;

    private ImageLoader loader;

    private String originalName;

    private JButton btnnextPage;
    private JButton btnprevPage;
    private BufferedImage biSave;

    private double prevWidth = -1;
    private double prevHeight = -1;

    /**
     * 表示したいファイルのファイル名を定義し, さらにそこから 画像ファイルを配備したパネルを作成したり, 適切な操作を 行うボタンを配備したりする.
     * 
     * @param infile
     *            表示したいファイル名
     * @param originalName
     *            表示したいファイルが実はghostscriptによって変換されたものだった場合,
     *            オリジナルの画像ファイルのファイル名をこの引数に指定する.
     */
    public MainPanel(String infile, String originalName) {
        super(originalName, true, true, true, true,
                new java.awt.Dimension(0, 0), InternalFrameChase.AUTOMATIC,
                false);
        this.infile = infile;
        this.originalName = originalName;
        setResizable(true);
        createMainPanel();
        redraw(true);
        addComponentListener(this);
        revalidate();
        setVisible(true);
    }

    /**
     * 表示したいファイルのファイル名を定義し, さらにそこから 画像ファイルを配備したパネルを作成したり, 適切な操作を 行うボタンを配備したりする.
     * 
     * @param infile
     *            表示したいファイルのファイル名.
     * @param desktop
     *            本プログラムの大元のJDesktopPane
     */
    public MainPanel(String infile) {
        this(infile, infile);
    }

    /**
     * 表示したい画像ファイルのファイル名.
     * 
     * @param infile
     *            ファイル名
     */
    public void setInfile(String infile) {
        this.infile = infile;
    }

    /**
     * 再描画用メソッド. まず一旦すべてのGUIパーツを削除してから 再構築している. こうしないと表示がおかしくなる?
     */
    public void redraw(boolean from_the_begining) {
        if (from_the_begining) {
            cont.removeAll();
            createMainPanel();
        }
        if (panelImage == null) {
            panelImage = new JPanel();
        }
        panelImage.removeAll();
        JPanel pi = createImagePanel();
        if (pi != null) {
            panelImage.add(pi);
        } else {
            mbox.setText("unsupported file type!");
            status = false;
            return;
        }

        if (pageNum == 1) {
            btnnextPage.setEnabled(false);
            btnprevPage.setEnabled(false);
        }
        // revalidate();
        // this.pack();
    }

    /**
     * 指定のファイルがサポートしている画像ファイルか否かを返す.
     * 
     * @return サポートしていないファイル形式の場合偽を返す.
     */
    public boolean getStatus() {
        return this.status;
    }

    public void redraw() {
        redraw(false);
    }

    /**
     * 呼び出し元のImageLoaderオブジェクトへの参照をセットする.
     * 
     * @param loader
     *            呼び出し元のImageLoader. setLoader(this) などとしたはずである.
     */
    public void setLoader(ImageLoader loader) {
        this.loader = loader;
    }

    /**
     * このGUIを可視にする.
     */
    public void display() {
        setVisible(true);
    }

    /**
     * psやpdfなど, 複数ページを許可する形式の場合に, 「何ページ目を表示中か」という情報をセットする.
     * 
     * @param pageNum
     *            現在のページ数.
     */
    public void setPageNum(int pageNum) {
        this.pageNum = pageNum;
        if (pageNum <= 1) {
            btnnextPage.setEnabled(false);
            btnprevPage.setEnabled(false);
        } else {
            setTitleWithPage();
        }
    }

    /**
     * 複数ページの場合各々のページについて一時ファイルを作成する. そのファイル名を保持した配列, pageArrayを設定する.
     * 
     * @param pageArray
     *            各ページに対応するファイルのファイル名を保持する配列.
     */
    public void setPageArray(String[] pageArray) {
        this.pageArray = pageArray;
    }

    private JPanel panelImage;
    private int buttonWidth;

    private void createMainPanel() {
        if (panelImage == null) {
            panelImage = new JPanel();
        }
        JPanel panel = new JPanel();
        cont = getContentPane();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        JPanel btnpanel = createButtonPanel();
        buttonWidth = btnpanel.getSize().width;
        panel.add(btnpanel);
        JPanel pi = createImagePanel();
        if (pi != null) {
            panelImage.add(pi);
            panel.add(panelImage);
        } else {
            mbox.setText("unsupported file type!");
            status = false;
            return;
        }
        panel.revalidate();
        if (panel.getSize().width < buttonWidth)
            panel.setSize(new Dimension(buttonWidth, panel.getSize().height));

        cont.add(panel);
        revalidate();
        this.pack();
    }

    private void resizeImage() {
        AffineTransform transform = new AffineTransform();
        transform.scale(scale, scale);
        AffineTransformOp transformOp = new AffineTransformOp(transform,
                AffineTransformOp.TYPE_BILINEAR);
        BufferedImage bit = transformOp.filter(biSave, null);
        graphicsPanel.setImage(bit);
    }

    private GraphicsPanel graphicsPanel;
    private BufferedImage bi;

    private JPanel createImagePanel() {

        JPanel pimage = new JPanel();
        pimage.setLayout(new FlowLayout(FlowLayout.CENTER));
        BufferedImage bi;

        try {
            int width, height;
            bi = ImageIO.read(new File(infile));
            width = (int) (bi.getWidth());
            height = (int) (bi.getHeight());
            int irotscale = Math.abs((int) (rotscale / 90.d));

            AffineTransform transform = new AffineTransform();
            transform.scale(scale, scale);
            transform.rotate(Math.PI * rotscale / 180., (int) (width / 2),
                    (int) (height / 2));

            AffineTransformOp transformOp = new AffineTransformOp(transform,
                    AffineTransformOp.TYPE_BILINEAR);
            Rectangle2D rectangle = transformOp.getBounds2D(bi);
            int x = (int) rectangle.getX();
            int y = (int) rectangle.getY();
            width = (int) rectangle.getWidth();
            height = (int) rectangle.getHeight();

            transform = new AffineTransform();
            transform.rotate(Math.PI * rotscale / 180., (int) (width / 2),
                    (int) (height / 2));
            transform.translate(-x, -y);
            transform.scale(scale, scale);
            transformOp = new AffineTransformOp(transform,
                    AffineTransformOp.TYPE_BILINEAR);

            BufferedImage bit = null;
            bit = transformOp.filter(bi, null);
            biSave = bit;

            graphicsPanel = new GraphicsPanel(bit);

            pimage.add(graphicsPanel);

            this.setMinimumSize(new Dimension(120, 350));
            int sizex;
            int sizey;
            if (width + getaw < 120) {
                sizex = 120;
            } else {
                sizex = width + getaw;
            }
            if (height + getah < 350) {
                sizey = 350;
            } else {
                sizey = height + getah;
            }
            this.setPreferredSize(new Dimension(sizex, sizey));
            this.setSize(sizex, sizey);
        } catch (Exception exception) {
            exception.printStackTrace();
            return null;
        }

        return pimage;
    }

    private JPanel createButtonPanel() {

        JPanel pbtn1 = new JPanel();
        pbtn1.setLayout(new BoxLayout(pbtn1, BoxLayout.X_AXIS));
        JPanel pbtn2 = new JPanel();
        pbtn2.setLayout(new BoxLayout(pbtn2, BoxLayout.X_AXIS));
        JPanel pbtn = new JPanel();

        int x = 70;
        int y = 50;

        // pbtn.setLayout(new BoxLayout(pbtn, BoxLayout.Y_AXIS));

        // pbtn.setPreferredSize(new Dimension(x,minSize));
        // pbtn.setLayout(new FlowLayout());
        // pbtn.setLayout(new GridLayout(9,1));
        // pbtn.setMinimumSize(new Dimension(x,minSize));
        // pbtn.setMaximumSize(new Dimension(x,minSize));

        ImageIcon home = new ImageIcon(getClass().getResource(
                "/org/javalobby/icons/20x20/Home.gif"));
        JButton btninitial = new JButton(home);
        btninitial.setToolTipText("restore original size and orientation");
        // btninitial.setPreferredSize(new Dimension(x,y));

        ImageIcon mag = new ImageIcon(getClass().getResource(
                "/org/javalobby/icons/20x20/MagnifyPlus.gif"));
        JButton btnresizep = new JButton(mag);
        btnresizep.setToolTipText("magnify");
        // btnresizep.setPreferredSize(new Dimension(x,y));

        ImageIcon magminus = new ImageIcon(getClass().getResource(
                "/org/javalobby/icons/20x20/MagnifyMinus.gif"));
        JButton btnresizem = new JButton(magminus);
        btnresizem.setToolTipText("shrink");
        // btnresizem.setPreferredSize(new Dimension(x,y));

        ImageIcon rotcw = new ImageIcon(getClass().getResource(
                "/org/javalobby/icons/20x20/RotCWDown.gif"));
        JButton btnrotatep = new JButton(rotcw);
        btnrotatep.setToolTipText("rotate (counter clockwise)");

        ImageIcon rotcc = new ImageIcon(getClass().getResource(
                "/org/javalobby/icons/20x20/RotCCDown.gif"));
        // btnrotatep.setPreferredSize(new Dimension(x,y));
        JButton btnrotatem = new JButton(rotcc);
        btnrotatem.setToolTipText("rotate (clockwise)");
        // btnrotatem.setPreferredSize(new Dimension(x,y));

        ImageIcon back = new ImageIcon(getClass().getResource(
                "/org/javalobby/icons/20x20/VCRBack.gif"));
        btnprevPage = new JButton(back);
        btnprevPage.setToolTipText("previous page");
        // btnprevPage.setPreferredSize(new Dimension(x,y));

        ImageIcon forward = new ImageIcon(getClass().getResource(
                "/org/javalobby/icons/20x20/VCRForward.gif"));
        btnnextPage = new JButton(forward);
        btnnextPage.setToolTipText("next page");
        // btnnextPage.setPreferredSize(new Dimension(x,y));

        ImageIcon fastforward = new ImageIcon(getClass().getResource(
                "/org/javalobby/icons/20x20/VCRFastForward.gif"));
        JButton nextimage = new JButton(fastforward);
        nextimage.setToolTipText("next image");

        ImageIcon rewind = new ImageIcon(getClass().getResource(
                "/org/javalobby/icons/20x20/VCRRewind.gif"));
        JButton previmage = new JButton(rewind);
        previmage.setToolTipText("previous image");

        pbtn.setLayout(new BoxLayout(pbtn, BoxLayout.X_AXIS));
        pbtn1.add(btninitial);
        pbtn1.add(btnresizep);
        pbtn1.add(btnresizem);
        pbtn1.add(btnrotatem);
        pbtn1.add(btnrotatep);
        pbtn1.add(btnprevPage);
        pbtn1.add(btnnextPage);

        ImageIcon print = new ImageIcon(getClass().getResource(
                "/org/javalobby/icons/20x20/Print.gif"));
        JButton btnprint = new JButton(print);
        btnprint.setToolTipText("print image");
        // btnprint.setPreferredSize(new Dimension(x,y));

        ImageIcon exit = new ImageIcon(getClass().getResource(
                "/org/javalobby/icons/20x20/Exit.gif"));
        JButton btnclose = new JButton(exit);
        btnclose.setToolTipText("exit");
        // btnclose.setPreferredSize(new Dimension(x,y));

        pbtn1.add(btnprint);
        pbtn1.add(btnclose);

        JScrollPane scrpane = new JScrollPane(pbtn1);
        // pbtn1.add(previmage);
        // pbtn1.add(nextimage);

        pbtn.setLayout(new BoxLayout(pbtn, BoxLayout.Y_AXIS));
        // pbtn.add(pbtn1);
        pbtn.setPreferredSize(new Dimension(pbtn.getPreferredSize().width, 60));
        pbtn.add(scrpane);

        // JPanel ppbtn = new JPanel();
        // ppbtn.setLayout(new BorderLayout());
        // ppbtn.add(pbtn,BorderLayout.WEST);

        btnprint.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                printImage();
            }
        });

        btninitial.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                initializeImage();
            }
        });

        btnresizep.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                scaleImage(0);
            }
        });

        btnresizem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                scaleImage(1);
            }
        });

        btnrotatep.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                rotateImage(0);
            }
        });

        btnrotatem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                rotateImage(1);
            }
        });

        btnnextPage.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                page++;
                if (page > pageNum - 1) {
                    page = 0;
                }
                try {
                    infile = pageArray[page];
                    setTitleWithPage();
                    redraw();
                } catch (Exception ex) {
                }
            }
        });

        btnprevPage.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                page--;
                if (page < 0) {
                    page = pageNum - 1;
                }
                try {
                    infile = pageArray[page];
                    setTitleWithPage();
                    redraw();
                } catch (Exception ex) {
                }
            }
        });

        btnclose.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        });

        return (pbtn);
    }

    private void printImage() {
        Image image = null;
        try {
            image = (Image) biSave;
            ImagePrinter ip = new ImagePrinter(image);
            ip.printImage();
        } catch (Exception exception) {
            mbox.setText("failed Print");
            exception.printStackTrace();
        }

    }

    private void scaleImage(int magormin) {
        if (magormin == 0) {
            scale = scale * 1.1;
        } else {
            scale = scale / 1.1;
        }
        redraw();
    }

    private void rotateImage(int plusorminus) {
        if (plusorminus == 0) {
            rotscale = rotscale + 90.0d;
        } else {
            rotscale = rotscale - 90.0d;
        }
        if (rotscale >= 360.0d) {
            rotscale = rotscale - 360.0d;
        } else if (rotscale <= -360.0d) {
            rotscale = rotscale + 360.0d;
        }
        redraw();
    }

    private void initializeImage() {
        scale = 1.0d;
        rotscale = 0.0d;
        redraw();
    }

    private void setTitleWithPage() {
        int pageDisplay = page + 1;
        super.setTitle(originalName + ", page " + pageDisplay + "/" + pageNum);
    }

    public void componentShown(ComponentEvent e) {
    }

    public void componentResized(ComponentEvent e) {
        // removeComponentListener(this);
        // if ( prevWidth < 0 ) {
        // prevWidth = getSize().getWidth();
        // addComponentListener(this);
        // return;
        // }
        // double curWidth = getSize().getWidth();
        // scale = curWidth/prevWidth;
        // prevWidth = curWidth;
        // // resizeImage();
        // redraw();
        // addComponentListener(this);
    }

    public void componentMoved(ComponentEvent e) {
    }

    public void componentHidden(ComponentEvent e) {
    }

}
