package edu.sc.seis.gee.task;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterJob;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import org.apache.log4j.Category;
import edu.iris.Fissures.IfParameterMgr.ParameterRef;
import edu.sc.seis.fissuresUtil.exceptionHandler.GlobalExceptionHandler;
import edu.sc.seis.fissuresUtil.xml.DataSet;
import edu.sc.seis.fissuresUtil.xml.StdDataSetParamNames;
import edu.sc.seis.gee.CommonAccess;
import edu.sc.seis.gee.configurator.ConfigurationException;
import edu.sc.seis.gee.task.dataSetBrowser.DataSetBrowser;
import edu.sc.seis.gee.task.dataSetBrowser.ParameterSelectedListener;
import edu.sc.seis.gee.task.dataSetBrowser.ParameterSelectionEvent;

/**
 * Description: Display one image loaded from an URL or local file that is
 * provided from the xml file.
 * 
 * 
 * @Created Jul 10, 2002
 * 
 * @author Philip Crotwell
 * @version $Id: ImageViewer.java 15535 2005-12-13 13:48:33 -0500 (Tue, 13 Dec
 *          2005) groves $
 * 
 */
public class ImageViewer extends JPanel implements Task, Printable {

    public ImageViewer() {
        super(new BorderLayout());
        addComponentListener(new ComponentAdapter() {

            public void componentResized(ComponentEvent e) {
                checkSizing = true;
                repaint();
            }
        });
    }

    PrinterJob printerJob = null;

    // for PDF's what percentage of full screen do we want the image to be.
    double screenRatio = 0.80;

    // these ints set the maximum size the frame will be made if setFrameSize is
    // true
    int maxWidth = 1024, maxHeight = 768;

    JScrollPane scroll = null;

    public int print(Graphics graphics, PageFormat pf, int pageIndex) {
        if(pageIndex > 0) /* 1 page only */
            return Printable.NO_SUCH_PAGE;
        Graphics2D g2 = (Graphics2D)graphics;
        g2.translate(pf.getImageableX(), pf.getImageableY());
        double scaleX, scaleY;
        // Whole screen is selected
        scaleX = pf.getImageableWidth() / getWidth();
        scaleY = pf.getImageableHeight() / getHeight();
        if(scaleX < 1.0 || scaleY < 1.0) { // Does it need to scale down?
            if(scaleX < scaleY)
                g2.scale(scaleX, scaleX); // Aspect ratio based on X.
            else
                g2.scale(scaleY, scaleY); // Aspect ratio based on Y.
        }
        paint(g2);
        return Printable.PAGE_EXISTS;
    }

    public void repaint() {
        if(checkSizing) {
            fixSize();
        }
        super.repaint();
    }

    /**
     * pass in my parent window size, and check the image size to make sure it
     * fits on the screen, Scale it down if need be.
     * 
     * @param wSize
     * @return
     */
    private void checkImageSize(JFrame frame) {
        Dimension desiredImageSize = imageLabel.getPreferredSize();
        // fix the imageLabel, both image ,and size
        add(imageLabel);
        Dimension curPanelSize = getSize();
        Dimension internalFrame = frame.getContentPane().getSize();
        int newWidth = curPanelSize.width, newHeight = curPanelSize.height;
        if(curPanelSize.width < desiredImageSize.width) {
            int otherWidth = internalFrame.width - curPanelSize.width;
            newWidth = desiredImageSize.width + otherWidth;
        }
        if(curPanelSize.height < desiredImageSize.height) {
            int otherHeight = internalFrame.height - curPanelSize.height;
            newHeight = desiredImageSize.height + otherHeight;
        }
        if(newWidth > curPanelSize.width || newHeight > curPanelSize.height) {
            removeAll();
            if(newWidth < maxWidth && newHeight < maxHeight && setFrameSize) {
                add(imageLabel);
            } else {
                if(maxWidth < newWidth && maxWidth > internalFrame.width)
                    newWidth = maxWidth;
                if(maxHeight < newHeight && maxHeight > internalFrame.height)
                    newHeight = maxHeight;
                if(scroll == null)
                    scroll = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                                             JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
                add(scroll);
                scroll.getViewport().removeAll();
                scroll.getViewport()
                        .setPreferredSize(imageLabel.getPreferredSize());
                scroll.getViewport().add(imageLabel);
            }
            if(setFrameSize)
                frame.setSize(newWidth, newHeight);
        } else {
            removeAll();
            add(imageLabel);
        }
        revalidate();
    }

    /**
     * fix the image size. calls checkImageSize, but first makes sure that the
     * image is currently visible.
     */
    private void fixSize() {
        if(image == null)
            return;
        Container con = this.getParent();
        if(con == null) {
            return;
        }
        while(!(con instanceof JFrame)) {
            con = con.getParent();
            if(con == null) {
                return;
            }
        }
        checkSizing = false;
        // we only get here if the ultimate parent is a JFrame.
        checkImageSize((JFrame)con);
    }

    /** Receives the URL to where it will load an image from */
    public void configure(Map params) throws ConfigurationException {
        this.params = params;
        if(params.containsKey("resizeFrame"))
            setFrameSize = Boolean.valueOf((String)params.get("resizeFrame"))
                    .booleanValue();
        if(params.containsKey("datasetbrowser")) {
            String browserId = (String)params.get("datasetbrowser");
            TaskAction browserAction = CommonAccess.getCommonAccess()
                    .getTaskAction(browserId);
            browser = (DataSetBrowser)browserAction.getTask();
            browser.addParameterSelectedListener(new ParameterSelectedListener() {

                public void parameterSelected(ParameterSelectionEvent p) {
                    if(p.isSelected()) {
                        Object param = p.getValue();
                        String st_url;
                        if(param instanceof String) {
                            st_url = (String)param;
                        } else if(param instanceof ParameterRef) {
                            st_url = ((ParameterRef)param).creator;
                        } else {
                            st_url = "none";
                        } // end of else
                        URL given_url;
                        try {
                            Object o = p.getDataSet().getParameter("xml:base");
                            if(o != null && o instanceof String) {
                                String baseStr = (String)o;
                                URL base = new URL(baseStr);
                                given_url = new URL(base, st_url);
                            } else {
                                given_url = new URL(st_url);
                            }
                            addURL(p.getName(), given_url);
                            setImage(given_url);
                            imageLabel.repaint();
                        } catch(MalformedURLException e) {
                            logger.error("Bad image url, " + st_url, e);
                        }
                    } // end of if (e.isSelected())
                }
            });
        }
        Iterator it = params.keySet().iterator();
        while(it.hasNext()) {
            Object key = it.next();
            String stkey = (String)key;
            if(stkey.startsWith("url_image")) {
                String name = stkey.substring(8);
                String st_url = (String)params.get(key);
                try {
                    URL given_url = new URL(st_url);
                    addURL(name, given_url);
                    if(image == null) {
                        setImage(given_url);
                    } // end of if (image == null)
                } catch(java.net.MalformedURLException e) {
                    throw new ConfigurationException("Image Viewer could not parse url "
                                                             + st_url,
                                                     e);
                }
            } else if(stkey.startsWith("image_jar_")) {
                String name = stkey.substring("image_jar_".length());
                String st_url = (String)params.get(key);
                URL given_url = getClass().getClassLoader().getResource(st_url);
                addURL(name, given_url);
                if(image == null) {
                    setImage(given_url);
                } // end of if (image == null)
            }
        } // end of while (it.hasNext())
        TaskAction taskAction = (TaskAction)params.get(TASK_ACTION);
        taskAction.addToToolBar(comboBox);
        comboBox.addItemListener(new ItemListener() {

            public void itemStateChanged(ItemEvent e) {
                if(e.getStateChange() == ItemEvent.SELECTED) {
                    logger.debug("select " + e.getItem());
                    setImage((URL)nameURLMap.get(e.getItem()));
                } // end of if (e.getStateChange() == ItemEvent.SELECTED)
            }
        });
    }

    public void destroy() {}

    public void retrieveImages(DataSet dataSet) {
        logger.debug("The NAME of THE dataset in RETRIEVE IMAGES is "
                + dataSet.getName());
        String[] paramNames = dataSet.getParameterNames();
        URL base = null;
        Object o = dataSet.getParameter("xml:base");
        if(o != null && o instanceof String) {
            String baseStr = (String)o;
            try {
                base = new URL(baseStr);
            } catch(MalformedURLException e) {
                logger.warn("Problem with url: " + baseStr, e);
            }
        }
        for(int i = 0; i < paramNames.length; i++) {
            logger.debug("Param name=" + paramNames[i]);
            // skip standard things known not to be images
            if(paramNames[i].startsWith(StdDataSetParamNames.EVENT)
                    || paramNames[i].startsWith(StdDataSetParamNames.CHANNEL)) {
                continue;
            } // end of if (paramStr.startsWith(StdDataSetParamNames.EVENT))
            Object param = dataSet.getParameter(paramNames[i]);
            String paramStr = null;
            if(param instanceof String) {
                paramStr = (String)param;
            } else if(param instanceof ParameterRef) {
                paramStr = ((ParameterRef)param).creator;
            }
            if(paramStr != null
                    && paramStr.length() != 0
                    && (paramStr.endsWith(".gif") || paramStr.endsWith(".png")
                            || paramStr.endsWith(".jpg")
                            || paramStr.endsWith(".pdf") || paramStr.endsWith(".jpeg"))) {
                try {
                    URL url;
                    if(base != null) {
                        url = new URL(base, paramStr);
                    } else {
                        url = new URL(paramStr);
                    }
                    logger.debug("Adding to image viewer " + paramNames[i]
                            + " " + url.toString());
                    addURL(paramNames[i], url);
                } catch(MalformedURLException e) {
                    GlobalExceptionHandler.handle(e);
                } // end of try-catch
            }
        } // end of for (int i=0; i<paramNames.length; i++)
    }

    /** Called everytime user clicks on the gee|Extras|ImageViewer */
    public void invoke() {
        if(browser != null) {
            DataSet[] datasets = browser.getSelectedDataSets();
            if(datasets == null || datasets.length == 0) {
                DataSet dataset = CommonAccess.getCommonAccess()
                        .getDataSetRoot();
                retrieveImages(dataset);
                String[] dsNames = dataset.getDataSetNames();
                if(dsNames.length == 1) {
                    DataSet child = dataset.getDataSet(dsNames[0]);
                    retrieveImages(child);
                } else {
                    String dsNameStr = "";
                    for(int j = 0; j < dsNames.length; j++) {
                        dsNameStr += dsNames[j] + " ";
                    }
                    JOptionPane.showMessageDialog(null,
                                                  "There are "
                                                          + dsNames.length
                                                          + " datasets, and none is selected."
                                                          + dsNameStr,
                                                  "alert",
                                                  JOptionPane.ERROR_MESSAGE);
                }
            } else {
                for(int counter = 0; counter < datasets.length; counter++) {
                    DataSet dataset = datasets[counter];
                    retrieveImages(dataset);
                }
            }
        }
        doGuiInit();
    }

    /**
     * Gui initialization was pulled out of main initialization method for
     * clarity and for testing.
     */
    private void doGuiInit() {
        if(!guiInit) {
            guiInit = true;
            if(image == null) {
                imageLabel.setText("No Image");
            } else {
                imageLabel.setIcon(new ImageIcon(image));
            } // end of else
        }
    }

    protected JPanel pdfPanel = new JPanel();

    static URI URI_DEMO = URI.create("http://www.sc.edu");

    public void setImage(URL url) {
        if(url.getPath().endsWith(".pdf")) {
            logger.debug(url.getPath());
            // testPDF(url);
            // at this point I want to unpack the jlabel, and pack the jpanel
            // that holds
            // the multivalent pdf viewer.
        } else {
            image = Toolkit.getDefaultToolkit().getImage(url);
        }
        imageLabel.setIcon(new ImageIcon(image));
        imageLabel.setText(null);
        checkSizing = true;
        repaint();
    }

    private boolean checkSizing = false, setFrameSize = true;

    public void addURL(String name, URL url) {
        String urlName = url.toString();
        if(urlName != null
                && urlName.length() != 0
                && (urlName.endsWith(".gif") || urlName.endsWith(".png")
                        || urlName.endsWith(".jpg") || urlName.endsWith(".pdf") || urlName.endsWith(".jpeg"))) {
            nameURLMap.put(name, url);
            for(int i = 0; i < comboBox.getItemCount(); i++) {
                if(((String)comboBox.getItemAt(i)).equals(name)) {
                    return;
                } // end of if (comboBox.getItemAt(i).equals(name))
            } // end of for (int i = 0; i < comboBox.getItemCount(); i++)
            comboBox.addItem(name);
        }
    }

    protected HashMap nameURLMap = new HashMap();

    boolean guiInit = false;

    private Image image = null;

    protected JLabel imageLabel = new JLabel("no image");

    protected Map params;

    protected JComboBox comboBox = new JComboBox();

    protected DataSetBrowser browser;

    static Category logger = Category.getInstance(ImageViewer.class.getName());
} // class
