package kiyut.sketsa.modules.pdfexport.actions;

import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JRootPane;
import javax.swing.KeyStroke;
import kiyut.sketsa.io.DefaultFileFilter;
import kiyut.sketsa.util.DOMUtilities;
import kiyut.sketsa.util.IOUtilities;
import kiyut.sketsa.util.UnitConversion;
import kiyut.swing.combo.SeparatorComboBox;
import org.apache.batik.transcoder.DefaultErrorHandler;
import org.apache.batik.transcoder.SVGAbstractTranscoder;
import org.apache.batik.transcoder.Transcoder;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.fop.svg.PDFTranscoder;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.NbBundle;
import org.w3c.dom.svg.SVGDocument;

/** ExportAsPDFWindow
 *
 * @author  Kiyut
 */
public class ExportAsPDFWindow extends javax.swing.JDialog {
    private SVGDocument svgDocument;
    
    private static ResourceBundle bundle = ResourceBundle.getBundle("kiyut.sketsa.modules.pdfexport.actions.ExportAsPDFWindow");
    
    private List<String[]> sizeList;
    private List<String[]> unitList;
    private List<String> dpiList;
    private String oldUnit;
    
    /** Creates new dialog  */
    public ExportAsPDFWindow(java.awt.Frame parent, boolean modal) {
        super(parent, modal);
        initComponents();
        initCustomComponents();
        setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        this.getRootPane().setDefaultButton(exportButton);
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        optionPane = new javax.swing.JPanel();
        executeOnloadCheck = new javax.swing.JCheckBox();
        javax.swing.JPanel aoiPane = new javax.swing.JPanel();
        javax.swing.JLabel jLabel7 = new javax.swing.JLabel();
        javax.swing.JLabel jLabel8 = new javax.swing.JLabel();
        javax.swing.JLabel jLabel9 = new javax.swing.JLabel();
        javax.swing.JLabel jLabel10 = new javax.swing.JLabel();
        areaXField = new javax.swing.JTextField();
        areaYField = new javax.swing.JTextField();
        areaWidthField = new javax.swing.JTextField();
        areaHeightField = new javax.swing.JTextField();
        javax.swing.JPanel outputPane = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        javax.swing.JLabel jLabel2 = new javax.swing.JLabel();
        javax.swing.JLabel jLabel3 = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        jLabel5 = new javax.swing.JLabel();
        sizeCombo = new SeparatorComboBox();
        unitCombo = new javax.swing.JComboBox();
        dpiCombo = new javax.swing.JComboBox();
        outputWidthField = new javax.swing.JTextField();
        outputHeightField = new javax.swing.JTextField();
        progressBar = new javax.swing.JProgressBar();
        buttonPane = new javax.swing.JPanel();
        exportButton = new javax.swing.JButton();
        closeButton = new javax.swing.JButton();

        setTitle(bundle.getString("CTL_Title.Text")); // NOI18N
        setResizable(false);

        optionPane.setBorder(javax.swing.BorderFactory.createEmptyBorder(12, 12, 12, 12));
        optionPane.setLayout(new java.awt.GridBagLayout());

        executeOnloadCheck.setText(bundle.getString("CTL_ExecuteOnloadCheck.Text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        optionPane.add(executeOnloadCheck, gridBagConstraints);

        aoiPane.setBorder(javax.swing.BorderFactory.createCompoundBorder(javax.swing.BorderFactory.createTitledBorder(bundle.getString("CTL_AOI.Text")), javax.swing.BorderFactory.createEmptyBorder(6, 12, 12, 12))); // NOI18N
        aoiPane.setLayout(new java.awt.GridBagLayout());

        jLabel7.setText(bundle.getString("CTL_AreaX.Text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(0, 6, 0, 6);
        aoiPane.add(jLabel7, gridBagConstraints);

        jLabel8.setText(bundle.getString("CTL_AreaY.Text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(6, 6, 0, 6);
        aoiPane.add(jLabel8, gridBagConstraints);

        jLabel9.setText(bundle.getString("CTL_AreaWidth.Text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(6, 6, 0, 6);
        aoiPane.add(jLabel9, gridBagConstraints);

        jLabel10.setText(bundle.getString("CTL_AreaHeight.Text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(6, 6, 0, 6);
        aoiPane.add(jLabel10, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.weightx = 1.0;
        aoiPane.add(areaXField, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0);
        aoiPane.add(areaYField, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0);
        aoiPane.add(areaWidthField, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0);
        aoiPane.add(areaHeightField, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.ipadx = 160;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.weightx = 0.1;
        gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0);
        optionPane.add(aoiPane, gridBagConstraints);

        outputPane.setBorder(javax.swing.BorderFactory.createCompoundBorder(javax.swing.BorderFactory.createTitledBorder(bundle.getString("CTL_Output.Text")), javax.swing.BorderFactory.createEmptyBorder(6, 12, 12, 12))); // NOI18N
        outputPane.setLayout(new java.awt.GridBagLayout());

        jLabel1.setText(bundle.getString("CTL_OutputSize.Text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(0, 6, 0, 6);
        outputPane.add(jLabel1, gridBagConstraints);

        jLabel2.setText(bundle.getString("CTL_OutputWidth.Text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(6, 6, 0, 6);
        outputPane.add(jLabel2, gridBagConstraints);

        jLabel3.setText(bundle.getString("CTL_OutputHeight.Text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 4;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(6, 6, 0, 6);
        outputPane.add(jLabel3, gridBagConstraints);

        jLabel4.setText(bundle.getString("CTL_OutputUnit.Text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(6, 6, 0, 6);
        outputPane.add(jLabel4, gridBagConstraints);

        jLabel5.setText(bundle.getString("CTL_OutputUnit.Text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(6, 6, 0, 6);
        outputPane.add(jLabel5, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.weightx = 1.0;
        outputPane.add(sizeCombo, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0);
        outputPane.add(unitCombo, gridBagConstraints);

        dpiCombo.setEditable(true);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0);
        outputPane.add(dpiCombo, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0);
        outputPane.add(outputWidthField, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 4;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0);
        outputPane.add(outputHeightField, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0);
        optionPane.add(outputPane, gridBagConstraints);

        progressBar.setStringPainted(true);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(12, 0, 12, 0);
        optionPane.add(progressBar, gridBagConstraints);

        buttonPane.setLayout(new java.awt.GridLayout(1, 0, 5, 0));

        exportButton.setText(bundle.getString("CTL_ExportButton.Text")); // NOI18N
        exportButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                exportButtonActionPerformed(evt);
            }
        });
        buttonPane.add(exportButton);

        closeButton.setText(bundle.getString("CTL_CloseButton.Text")); // NOI18N
        closeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                closeButtonActionPerformed(evt);
            }
        });
        buttonPane.add(closeButton);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 4;
        gridBagConstraints.weightx = 1.0;
        optionPane.add(buttonPane, gridBagConstraints);

        getContentPane().add(optionPane, java.awt.BorderLayout.CENTER);

        pack();
    }// </editor-fold>//GEN-END:initComponents
    
    private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed
        setVisible(false);
        dispose();
    }//GEN-LAST:event_closeButtonActionPerformed
    
    private void exportButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportButtonActionPerformed
        try {
            validateOption();
        } catch (Exception ex) {
            NotifyDescriptor nd =  new NotifyDescriptor.Message(ex.getMessage(), NotifyDescriptor.ERROR_MESSAGE);
            DialogDisplayer.getDefault().notify(nd);
            return;
        }
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                generate();
            }
        });
    }//GEN-LAST:event_exportButtonActionPerformed
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JTextField areaHeightField;
    private javax.swing.JTextField areaWidthField;
    private javax.swing.JTextField areaXField;
    private javax.swing.JTextField areaYField;
    private javax.swing.JPanel buttonPane;
    private javax.swing.JButton closeButton;
    private javax.swing.JComboBox dpiCombo;
    private javax.swing.JCheckBox executeOnloadCheck;
    private javax.swing.JButton exportButton;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JPanel optionPane;
    private javax.swing.JTextField outputHeightField;
    private javax.swing.JTextField outputWidthField;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JComboBox sizeCombo;
    private javax.swing.JComboBox unitCombo;
    // End of variables declaration//GEN-END:variables
    
    @Override
    protected JRootPane createRootPane() { 
        JRootPane theRootPane = super.createRootPane();
        KeyStroke stroke = KeyStroke.getKeyStroke("ESCAPE");
        Action actionListener = new AbstractAction() { 
            public void actionPerformed(ActionEvent evt) { 
                setVisible(false);
            } 
        };
        InputMap inputMap = theRootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        inputMap.put(stroke, "ESCAPE");
        theRootPane.getActionMap().put("ESCAPE", actionListener);

        return theRootPane;
    } 
    
    private void initCustomComponents() {
        sizeList = new ArrayList<String[]>();
        sizeList.add(new String[] {"Custom","","","" });
        sizeList.add(new String[] {"--","","","" });
        sizeList.add(new String[] {"640 x 480","640","480",UnitConversion.PX});
        sizeList.add(new String[] {"800 x 600","800","600",UnitConversion.PX});
        sizeList.add(new String[] {"1024 x 768","1024","768",UnitConversion.PX});
        sizeList.add(new String[] {"--","","","" });
        sizeList.add(new String[] {"A3 [297.01 x 419.95 mm]","297.01","419.950",UnitConversion.MM});
        sizeList.add(new String[] {"A4 [209.97 x 297.01 mm]","209.97","297.01",UnitConversion.MM});
        sizeList.add(new String[] {"A5 [148.51 x 209.97 mm]","148.51","209.97",UnitConversion.MM});
        sizeList.add(new String[] {"A6 [104.99 x 148.51 mm]","104.99","148.51",UnitConversion.MM});
        sizeList.add(new String[] {"B4 [250.02 x 352.98 mm]","250.02","352.98",UnitConversion.MM});
        sizeList.add(new String[] {"B5 [176.02 x 250.00 mm]","176.02","250.00",UnitConversion.MM});
        sizeList.add(new String[] {"US-Letter [8.50 x 11.00 in]","8.50","11.00",UnitConversion.IN});
        sizeList.add(new String[] {"US-Legal [8.50 x 14.00 in]","8.50","14.00",UnitConversion.IN});
        sizeList.add(new String[] {"--","","","" });
        sizeList.add(new String[] {"CD Cover [120.99 x 119.97 mm]","120.99","119.97",UnitConversion.MM});
        
        unitList = new ArrayList<String[]>();
        unitList.add(new String[] {"pixel",UnitConversion.PX});
        unitList.add(new String[] {"millimeter",UnitConversion.MM});
        unitList.add(new String[] {"centimeter",UnitConversion.CM});
        unitList.add(new String[] {"inch",UnitConversion.IN});
        unitList.add(new String[] {"point",UnitConversion.PT});
        
        dpiList = new ArrayList<String>();
        dpiList.add("72");
        dpiList.add("96");
        dpiList.add("300");
        
        for (int i=0; i<sizeList.size(); i++) {
            String[] item = sizeList.get(i);
            sizeCombo.addItem(item[0]);
        }
        
        for (int i=0; i<unitList.size(); i++) {
            String[] item = unitList.get(i);
            unitCombo.addItem(item[0]);
        }
        
        for (int i=0; i<dpiList.size(); i++) {
            dpiCombo.addItem(dpiList.get(i));
        }
        
        sizeCombo.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent evt) {
                if (evt.getStateChange()==ItemEvent.DESELECTED) { return; }
                int index = sizeCombo.getSelectedIndex();
                if (index == 0) {
                    return;
                }
                
                String[] item = sizeList.get(index);
                
                // change unit
                String unit = item[3];
                if (unit.length() < 1) {
                    unit = UnitConversion.PX;
                }
                for (int i=0; i<unitList.size(); i++) {
                    if (unit.equals((unitList.get(i))[1])) {
                        unitCombo.setSelectedIndex(i);
                        break;
                    }
                }
                
                // change width & height
                if (item[1].length()>1) {
                    outputWidthField.setText(item[1]);
                }
                if (item[2].length()>1) {
                    outputHeightField.setText(item[2]);
                }
            }
        });
        
        unitCombo.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent evt) {
                if (evt.getStateChange()==ItemEvent.DESELECTED) { return; }
                int index = unitCombo.getSelectedIndex();
                String unit = (unitList.get(index))[1];
                try {
                    validateOption();
                    float dpi = Float.parseFloat(dpiCombo.getSelectedItem().toString());
                    float value;
                    value = Float.parseFloat(outputWidthField.getText());
                    outputWidthField.setText(Float.toString((float)UnitConversion.convert(value, oldUnit, unit, dpi)));
                    value = Float.parseFloat(outputHeightField.getText());
                    outputHeightField.setText(Float.toString((float)UnitConversion.convert(value, oldUnit, unit, dpi)));
                } catch (Exception ex) {
                    NotifyDescriptor nd =  new NotifyDescriptor.Message(ex.getMessage(), NotifyDescriptor.ERROR_MESSAGE);
                    DialogDisplayer.getDefault().notify(nd);
                }
                oldUnit = unit;
            }
        });
        
        ActionListener sizeActionListener = new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                if (sizeCombo.getSelectedIndex() != 0) {
                    sizeCombo.setSelectedIndex(0);
                }
            }
        };
        
        outputWidthField.addActionListener(sizeActionListener);
        outputHeightField.addActionListener(sizeActionListener);
        
        oldUnit = UnitConversion.PX;
        sizeCombo.setSelectedIndex(0);  // custom
        unitCombo.setSelectedIndex(0);   // px
        dpiCombo.setSelectedItem("300");
    }
    
    public void setArea(Rectangle2D area) {
        //this.area = area;
        
        if (area!=null) {
            areaXField.setText(Float.toString((float)area.getX()));
            areaYField.setText(Float.toString((float)area.getY()));
            areaWidthField.setText(Float.toString((float)area.getWidth()));
            areaHeightField.setText(Float.toString((float)area.getHeight()));
            outputWidthField.setText(Float.toString((float)area.getWidth()));
            outputHeightField.setText(Float.toString((float)area.getHeight()));
        }
    }
    
    public void setSVGDocument(SVGDocument doc) {
        this.svgDocument = doc;
    }
    
    private void validateOption() {
        float f = -1;
        
        try {
            f = Float.parseFloat(areaXField.getText());
            if (f < 0) {
               throw new RuntimeException();
            }
        } catch (Exception ex) {
            throw new RuntimeException(NbBundle.getMessage(this.getClass(), "MSG_InvalidAOIX.Text"));
        }
        
        try {
            f = Float.parseFloat(areaYField.getText());
            if (f < 0) {
               throw new RuntimeException();
            }
        } catch (Exception ex) {
            throw new RuntimeException(NbBundle.getMessage(this.getClass(), "MSG_InvalidAOIY.Text"));
        }
        
        try {
            f = Float.parseFloat(areaWidthField.getText());
            if (f <= 0) {
               throw new RuntimeException();
            }
        } catch (Exception ex) {
            throw new RuntimeException(NbBundle.getMessage(this.getClass(), "MSG_InvalidAOIWidth.Text"));
        }
        
        try {
            f = Float.parseFloat(areaHeightField.getText());
            if (f <= 0) {
               throw new RuntimeException();
            }
        } catch (Exception ex) {
            throw new RuntimeException(NbBundle.getMessage(this.getClass(), "MSG_InvalidAOIHeight.Text"));
        }
        
        try {
            f = Float.parseFloat(dpiCombo.getSelectedItem().toString());
            if (f <= 0) {
               throw new RuntimeException();
            }
        } catch (Exception ex) {
            throw new RuntimeException(NbBundle.getMessage(this.getClass(), "MSG_InvalidOutputDPI.Text"));
        }
        
        try {
            f = Float.parseFloat(outputWidthField.getText());
            if (f <= 0) {
               throw new RuntimeException();
            }
        } catch (Exception ex) {
            throw new RuntimeException(NbBundle.getMessage(this.getClass(), "MSG_InvalidOutputWidth.Text"));
        }
        
        try {
            f = Float.parseFloat(outputHeightField.getText());
            if (f <= 0) {
               throw new RuntimeException();
            }
        } catch (Exception ex) {
            throw new RuntimeException(NbBundle.getMessage(this.getClass(), "MSG_InvalidOutputHeight.Text"));
        }
    }
    
    private Transcoder createTranscoder() {
        PDFTranscoder t = new PDFTranscoder();
        t.setErrorHandler(new DefaultErrorHandler());
        t.setLogger(new org.apache.commons.logging.impl.NoOpLog());
        
        //Logger.
        
        t.addTranscodingHint(SVGAbstractTranscoder.KEY_EXECUTE_ONLOAD, new Boolean(executeOnloadCheck.isSelected()));
        
        // transcoder only accept unit in PX
        
        float width = Float.parseFloat(outputWidthField.getText());
        float height = Float.parseFloat(outputHeightField.getText());
        float dpi = Float.parseFloat(dpiCombo.getSelectedItem().toString());
        String dstUnit = UnitConversion.PX;
        
        int index = unitCombo.getSelectedIndex();
        String srcUnit = ((String[])unitList.get(index))[1];
        width = (float)UnitConversion.convert(width, srcUnit, dstUnit, dpi);
        height = (float)UnitConversion.convert(height, srcUnit, dstUnit, dpi);
        
        t.addTranscodingHint(SVGAbstractTranscoder.KEY_WIDTH, new Float(width));
        t.addTranscodingHint(SVGAbstractTranscoder.KEY_HEIGHT, new Float(height));
        t.addTranscodingHint(SVGAbstractTranscoder.KEY_MAX_WIDTH, new Float(width));
        t.addTranscodingHint(SVGAbstractTranscoder.KEY_MAX_HEIGHT, new Float(height));
        
        Rectangle2D rect = new Rectangle2D.Float(Float.parseFloat(areaXField.getText()),Float.parseFloat(areaYField.getText()),
                Float.parseFloat(areaWidthField.getText()), Float.parseFloat(areaHeightField.getText()));
        
        t.addTranscodingHint(SVGAbstractTranscoder.KEY_AOI, rect);
        
        return t;
    }
    
    /** Paint immediately */
    private void updateProgress(int value) {
        java.awt.Container container = getContentPane();
        if (container instanceof JComponent ) {
            Dimension dim = getPreferredSize();
            JComponent comp = (JComponent)container;
            progressBar.setValue(value);
            comp.paintImmediately(0,0,(int)dim.getWidth(),(int)dim.getHeight());
        }
    }
    
    private void generate() {
        System.gc();
        
        DefaultFileFilter fileFilter = new DefaultFileFilter();
        
        String extension="pdf";
        fileFilter.addExtension(extension);
        fileFilter.setDescription("PDF - Portable Document Format");
        
        JFileChooser fc = IOUtilities.getFileChooser();
        fc.setFileFilter(fileFilter);
        fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
        int choice = fc.showSaveDialog(this);
        if (choice != JFileChooser.APPROVE_OPTION) {
            return;
        }
        
        File file = fc.getSelectedFile();
        IOUtilities.setUserDir(file);
        
        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        updateProgress(0);
        exportButton.setEnabled(false);
        closeButton.setEnabled(false);
        
        String filename = file.toString();
        if (!filename.endsWith("." + extension)) {
            filename = filename + "." + extension;
        }
        
        OutputStream ostream = null;
        SVGDocument doc = null;
        try {
            Transcoder trans = createTranscoder();
            
            updateProgress(5);
            
            doc = (SVGDocument)DOMUtilities.deepCloneDocument(svgDocument); // needed so it will not use canvas GVT
            
            TranscoderInput input = new TranscoderInput(doc);
            
            updateProgress(25);
            
            ostream = new FileOutputStream(filename);
            TranscoderOutput output = new TranscoderOutput(ostream);
            
            updateProgress(30);
            
            trans.transcode(input, output);
            ostream.flush();
            updateProgress(95);
            
        } catch (OutOfMemoryError ex) {
            String msg = NbBundle.getMessage(this.getClass(), "MSG_OutOfMemoryError.Text");
            NotifyDescriptor nd =  new NotifyDescriptor.Message(msg, NotifyDescriptor.ERROR_MESSAGE);
            DialogDisplayer.getDefault().notify(nd);
        } catch (Exception ex) {
            NotifyDescriptor nd =  new NotifyDescriptor.Message(ex.getMessage(), NotifyDescriptor.ERROR_MESSAGE);
            DialogDisplayer.getDefault().notify(nd);
        } finally {
            doc = null;
            if (ostream != null) {
                try {
                    ostream.close();
                } catch (IOException ex) { }
            }
            
            System.gc();
            
            exportButton.setEnabled(true);
            closeButton.setEnabled(true);
            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            
            updateProgress(0);
        }
    }
}
