/*  SimplePageSetupDialog
    (C) Copyright 2009
    Wildcrest Associates
    http://www.wildcrest.com
This source code may be freely used, modified, incorporated, and
distributed without restriction as part of any software that uses
J2PrinterWorks by Wildcrest Associates.
*/

import com.wildcrest.j2printerworks.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.swing.border.TitledBorder;
import javax.swing.event.*;
import javax.print.attribute.HashPrintRequestAttributeSet;
import java.awt.print.PageFormat;

public class SimplePageSetupDialog extends JDialog {
   public static final int CANCEL = 0;
   public static final int OK = 1;

   private J2Printer14 printer;
   private PrintRequestAttributeSet attributeSet;
   private PageFormat pageFormat;
   private int retVal;
   private JRadioButton portraitButton, landscapeButton;
   private JComboBox mediaChoices;
   private String currentMedia;
   private SpinnerNumberModel leftMarginSpinnerModel, rightMarginSpinnerModel;
   private SpinnerNumberModel topMarginSpinnerModel, bottomMarginSpinnerModel;
   private int leftMinimumMargin, rightMinimumMargin, topMinimumMargin, bottomMinimumMargin;
   private JSpinner leftMarginSpinner, rightMarginSpinner, topMarginSpinner, bottomMarginSpinner;
   private JFormattedTextField leftMarginTextField, rightMarginTextField, topMarginTextField, bottomMarginTextField;
   private int halfPage;

   SimplePageSetupDialog(Frame frame, J2Printer14 printer) {
      super(frame, "Page Setup", true); // true = modal
      this.printer = printer;
      this.setResizable(false);

      PrintRequestAttributeSet aset = printer.getPrintRequestAttributeSet(); // pointer to printer's aset
   //tests:
      //aset.add(OrientationRequested.LANDSCAPE);
      //aset.add(MediaSizeName.NA_NUMBER_10_ENVELOPE);  // or MediaSizeName.ISO_A4, etc.
      //aset.add(new Copies(2));
      //aset.add(SheetCollate.COLLATED);
      //aset.add(new PageRanges(2,printer.getPageable().getNumberOfPages()));

      this.attributeSet = new HashPrintRequestAttributeSet(aset);
      this.pageFormat = printer.getPageFormat();
      this.getContentPane().setLayout(new BorderLayout());
      this.setLayout(new BorderLayout());

// Page Setup tab //

 // media
      JPanel selectMediaPanel = new JPanel();
      TitledBorder selectMediaBorder = new TitledBorder("Media");
      selectMediaPanel.setBorder(new TitledBorder("Size:"));
      selectMediaPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
      mediaChoices = new JComboBox(printer.getMediaSizes());
      if (mediaChoices.getItemCount()==0) {
         mediaChoices.addItem("Letter");
         printer.setPaperSize(612.0, 792.0);
         printer.setMediaSize("Letter");
      }
      mediaChoices.setEditable(false);
      currentMedia = printer.getMediaSize();
      mediaChoices.setSelectedItem(currentMedia);
      JPanel mediaField = new JPanel();
      mediaField.add(new JLabel("Name: "));
      mediaField.add(mediaChoices);
      selectMediaPanel.add(mediaField);
      this.add(selectMediaPanel, "North");

      mediaChoices.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) { mediaChanged(); }});

   // orientation
      JPanel orientationPanel = new JPanel();
      orientationPanel.setBorder(new TitledBorder("Orientation"));
      orientationPanel.setLayout(new BorderLayout());

      ButtonGroup orientationGroup = new ButtonGroup();
      portraitButton = new JRadioButton("Portrait");
      landscapeButton = new JRadioButton("Landscape");
      orientationGroup.add(portraitButton);
      orientationGroup.add(landscapeButton);
      // dialog only supports PORTRAIT and LANDSCAPE for now, can add REVERSE_LANDSCAPE if desired
      if (printer.getOrientation()==printer.REVERSE_LANDSCAPE) printer.setOrientation(printer.LANDSCAPE);
      boolean isLandscape = printer.getOrientation()==printer.LANDSCAPE;
      landscapeButton.setSelected(isLandscape);
      portraitButton.setSelected(!isLandscape);

      JPanel portraitLine = new JPanel();
      portraitLine.setLayout(new FlowLayout(FlowLayout.LEFT));
      Image portraitImage = new ImageIcon("orientPortrait.png").getImage();
      ImagePanel portraitImagePanel = new ImagePanel(portraitImage);
      portraitImagePanel.setBackground(this.getContentPane().getBackground());
      portraitLine.add(portraitImagePanel);
      portraitLine.add(portraitButton);

      JPanel landscapeLine = new JPanel();
      landscapeLine.setLayout(new FlowLayout(FlowLayout.LEFT));
      Image landscapeImage = new ImageIcon("orientLandscape.png").getImage();
      ImagePanel landscapeImagePanel = new ImagePanel(landscapeImage);
      landscapeImagePanel.setBackground(this.getContentPane().getBackground());
      landscapeLine.add(landscapeImagePanel);
      landscapeLine.add(landscapeButton);

      orientationPanel.add(portraitLine, "North");
      orientationPanel.add(landscapeLine, "South");

      portraitButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) { orientationChanged(); }});
      landscapeButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) { orientationChanged(); }});

   // margins
      JPanel marginsPanel = new JPanel();
      marginsPanel.setBorder(new TitledBorder("Margins (1/72 inch)"));
      marginsPanel.setLayout(new GridLayout(2,2));
      halfPage = ((int) printer.getBodyWidth()/2)-1; // quick way to prevent margin overlap

      JPanel leftMarginLine = new JPanel();
      leftMarginLine.setLayout(new FlowLayout(FlowLayout.RIGHT));
      leftMarginLine.add(new JLabel("Left: "));
      leftMarginSpinnerModel = new SpinnerNumberModel((int)(printer.getLeftMargin()*72.0), 0, halfPage, 1);
      leftMarginSpinner = new JSpinner(leftMarginSpinnerModel);
      leftMarginLine.add(leftMarginSpinner);
      marginsPanel.add(leftMarginLine);
      leftMarginSpinnerModel.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { marginsChanged(); }});
      leftMarginTextField = ((JSpinner.DefaultEditor)leftMarginSpinner.getEditor()).getTextField();
      leftMarginTextField.addFocusListener(new FocusListener() {
         public void focusLost(FocusEvent fe) { commitMarginEdit(leftMarginSpinnerModel, leftMarginTextField); marginsChanged(); }
         public void focusGained(FocusEvent fe) {}
      });

      JPanel rightMarginLine = new JPanel();
      rightMarginLine.setLayout(new FlowLayout(FlowLayout.RIGHT));
      rightMarginLine.add(new JLabel("Right: "));
      rightMarginSpinnerModel = new SpinnerNumberModel((int)(printer.getRightMargin()*72.0), 0, halfPage, 1);
      rightMarginSpinner = new JSpinner(rightMarginSpinnerModel);
      rightMarginLine.add(rightMarginSpinner);
      marginsPanel.add(rightMarginLine);
      rightMarginSpinnerModel.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { marginsChanged(); }});
      rightMarginTextField = ((JSpinner.DefaultEditor)rightMarginSpinner.getEditor()).getTextField();
      rightMarginTextField.addFocusListener(new FocusListener() {
          public void focusLost(FocusEvent fe) { commitMarginEdit(rightMarginSpinnerModel, rightMarginTextField); marginsChanged(); }
          public void focusGained(FocusEvent fe) {}
       });

      JPanel topMarginLine = new JPanel();
      topMarginLine.setLayout(new FlowLayout(FlowLayout.RIGHT));
      topMarginLine.add(new JLabel("Top: "));
      topMarginSpinnerModel = new SpinnerNumberModel((int)(printer.getTopMargin()*72.0), 0, halfPage, 1);
      topMarginSpinner = new JSpinner(topMarginSpinnerModel);
      topMarginLine.add(topMarginSpinner);
      marginsPanel.add(topMarginLine);
      topMarginSpinnerModel.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { marginsChanged(); }});
      topMarginTextField = ((JSpinner.DefaultEditor)topMarginSpinner.getEditor()).getTextField();
      topMarginTextField.addFocusListener(new FocusListener() {
         public void focusLost(FocusEvent fe) { commitMarginEdit(topMarginSpinnerModel, topMarginTextField); marginsChanged(); }
         public void focusGained(FocusEvent fe) {}
      });

      JPanel bottomMarginLine = new JPanel();
      bottomMarginLine.setLayout(new FlowLayout(FlowLayout.RIGHT));
      bottomMarginLine.add(new JLabel("Bottom: "));
      bottomMarginSpinnerModel = new SpinnerNumberModel((int)(printer.getBottomMargin()*72.0), 0, halfPage, 1);
      bottomMarginSpinner = new JSpinner(bottomMarginSpinnerModel);
      bottomMarginLine.add(bottomMarginSpinner);
      marginsPanel.add(bottomMarginLine);
      bottomMarginSpinnerModel.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { marginsChanged(); }});
      bottomMarginTextField = ((JSpinner.DefaultEditor)bottomMarginSpinner.getEditor()).getTextField();
      bottomMarginTextField.addFocusListener(new FocusListener() {
         public void focusLost(FocusEvent fe) { commitMarginEdit(bottomMarginSpinnerModel, bottomMarginTextField); marginsChanged(); }
         public void focusGained(FocusEvent fe) {}
      });

      calculateMinimumMargins();

   // orientation + margins panel
      JPanel pageSetupOptions = new JPanel();
      pageSetupOptions.setLayout(new GridLayout());
      pageSetupOptions.add(orientationPanel);
      pageSetupOptions.add(marginsPanel);
      this.add(pageSetupOptions, "Center");

   // OK + cancel buttons
      JPanel okCancel = new JPanel();
      JButton okButton = new JButton("OK");
      JButton cancelButton = new JButton("Cancel");
      okCancel.setLayout(new FlowLayout(FlowLayout.RIGHT));
      okCancel.add(okButton);
      okCancel.add(cancelButton);
      this.getContentPane().add(okCancel, "South");

      okButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) { print(); }});
      cancelButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) { cancel(); }});

      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) { cancel(); }});

      updateUI();

      pack();
      Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
      Rectangle frameDim = getBounds();
      setLocation( (screenDim.width - frameDim.width) / 2, (screenDim.height - frameDim.height) / 2);
   }

   void updateUI() {
      // update media sizes UI
      if (mediaChoices==null) mediaChoices = new JComboBox(printer.getMediaSizes());
      else mediaChoices.setModel(new DefaultComboBoxModel(printer.getMediaSizes()));
      if (mediaChoices.getItemCount()==0) {
         mediaChoices.addItem("Letter");
         printer.setPaperSize(612.0, 792.0);
         printer.setMediaSize("Letter");
      }
      currentMedia = printer.getMediaSize();
      mediaChoices.setSelectedItem(currentMedia);

      // update orientation UI
      boolean isLandscape = (printer.getOrientation()==printer.LANDSCAPE);
      if (landscapeButton!=null) landscapeButton.setSelected(isLandscape);
      if (portraitButton!=null) portraitButton.setSelected(!isLandscape);

      // update margins UI
      double inLM = printer.getLeftMargin();
      double inRM = printer.getRightMargin();
      double inTM = printer.getTopMargin();
      double inBM = printer.getBottomMargin();
      if (leftMarginSpinnerModel!=null) leftMarginSpinnerModel.setValue(new Integer((int)(72.0*inLM)));
      if (rightMarginSpinnerModel!=null) rightMarginSpinnerModel.setValue(new Integer((int)(72.0*inRM)));
      if (topMarginSpinnerModel!=null) topMarginSpinnerModel.setValue(new Integer((int)(72.0*inTM)));
      if (bottomMarginSpinnerModel != null) bottomMarginSpinnerModel.setValue(new Integer((int)(72.0*inBM)));

      repaint();
   }

   void mediaChanged() {
      String media = (String)mediaChoices.getSelectedItem();
      printer.setMediaSize(media);
      double paperWidth = printer.getPaperWidth(); // gets values from printer attribute
      double paperHeight = printer.getPaperHeight(); // sets them into take effect
      printer.setPaperSize(paperWidth, paperHeight); // sometimes changes media size to different equivalent name
      printer.setMediaSize(media); // so restore name as selected by user
      halfPage = ((int) (paperWidth - leftMinimumMargin - rightMinimumMargin)/2) - 1;  // new maximum margins
      Integer iVal = new Integer(halfPage);
      leftMarginSpinnerModel.setMaximum(iVal);
      rightMarginSpinnerModel.setMaximum(iVal);
      topMarginSpinnerModel.setMaximum(iVal);
      bottomMarginSpinnerModel.setMaximum(iVal);
      double inLM = printer.getLeftMargin();
      double inRM = printer.getRightMargin();
      double inTM = printer.getTopMargin();
      double inBM = printer.getBottomMargin();
      double halfPageInches = halfPage / 72.0;
      double newLM = inLM<halfPageInches?inLM:halfPageInches;
      double newRM = inRM<halfPageInches?inRM:halfPageInches;
      double newTM = inTM<halfPageInches?inTM:halfPageInches;
      double newBM = inBM<halfPageInches?inBM:halfPageInches;
      printer.setMargins(newLM, newRM, newTM, newBM);
      updateUI();
   }

   void orientationChanged() {
      calculateMinimumMargins();
      double inLM = printer.getLeftMargin();
      double inRM = printer.getRightMargin();
      double inTM = printer.getTopMargin();
      double inBM = printer.getBottomMargin();
      int inOrientation = printer.getOrientation();
      if (portraitButton.isSelected()) printer.setOrientation(printer.PORTRAIT);
      else printer.setOrientation(printer.LANDSCAPE);
      int outOrientation = printer.getOrientation();
      if (inOrientation==printer.PORTRAIT && outOrientation==printer.LANDSCAPE)
         printer.setMargins(inBM, inTM, inLM, inRM);
      if (inOrientation==printer.LANDSCAPE && outOrientation==printer.PORTRAIT)
         printer.setMargins(inTM, inBM, inRM, inLM);
      updateUI();
   }

   void marginsChanged() {
      keepMarginInRange(leftMarginSpinnerModel, leftMinimumMargin, halfPage);
      keepMarginInRange(rightMarginSpinnerModel, rightMinimumMargin, halfPage);
      keepMarginInRange(topMarginSpinnerModel, topMinimumMargin, halfPage);
      keepMarginInRange(bottomMarginSpinnerModel, bottomMinimumMargin, halfPage);
      double leftMargin = leftMarginSpinnerModel.getNumber().intValue()/72.0;
      double rightMargin = rightMarginSpinnerModel.getNumber().intValue()/72.0;
      double topMargin = topMarginSpinnerModel.getNumber().intValue()/72.0;
      double bottomMargin = bottomMarginSpinnerModel.getNumber().intValue()/72.0;
      printer.setMargins(leftMargin, rightMargin, topMargin, bottomMargin);
      updateUI();
   }

   void keepMarginInRange(SpinnerNumberModel snm, int min, int max) {
      int num = snm.getNumber().intValue();
      if (num<min) num = min;
      if (num>max) num = max;
      snm.setValue(new Integer(num));
   }

   void commitMarginEdit(SpinnerNumberModel spinnerModel, JFormattedTextField textField) {
      Integer val;
      try { val = Integer.valueOf(textField.getText());} catch (Exception e) { return; } // retain old value if bad
      spinnerModel.setValue(val);
   }

   void calculateMinimumMargins() {
      int orientation = printer.getOrientation();
      leftMinimumMargin = (int) printer.getMinimumLeftMargin(orientation);
      rightMinimumMargin = (int)  printer.getMinimumRightMargin(orientation);
      topMinimumMargin = (int) printer.getMinimumTopMargin(orientation);
      bottomMinimumMargin = (int) printer.getMinimumBottomMargin(orientation);

      Integer iVal = new Integer(leftMinimumMargin);
      leftMarginSpinnerModel.setMinimum(iVal);
      int leftVal = leftMarginSpinnerModel.getNumber().intValue();
      if (leftVal<leftMinimumMargin) leftMarginSpinnerModel.setValue(iVal);

      iVal = new Integer(rightMinimumMargin);
      rightMarginSpinnerModel.setMinimum(iVal);
      int rightVal = rightMarginSpinnerModel.getNumber().intValue();
      if (rightVal<rightMinimumMargin) rightMarginSpinnerModel.setValue(iVal);

      iVal = new Integer(topMinimumMargin);
      topMarginSpinnerModel.setMinimum(iVal);
      int topVal = topMarginSpinnerModel.getNumber().intValue();
      if (topVal<topMinimumMargin) topMarginSpinnerModel.setValue(iVal);

      iVal = new Integer(bottomMinimumMargin);
      bottomMarginSpinnerModel.setMinimum(iVal);
      int bottomVal = bottomMarginSpinnerModel.getNumber().intValue();
      if (bottomVal<bottomMinimumMargin) bottomMarginSpinnerModel.setValue(iVal);
   }

   public int showDialog() {
      setVisible(true);
      return retVal;
   }

   public void print() {
      retVal = SimplePageSetupDialog.OK;
      setVisible(false);
   }

   public void cancel() {
      printer.setPrintRequestAttributeSet(attributeSet);
      printer.setPageFormat(pageFormat);

      retVal = SimplePageSetupDialog.CANCEL;
      setVisible(false);
   }

}

