/* 
 * Distributed as part of AVS 3.0.0
 * 
 * Copyright (C) 2008 QArks.com
 *
 * Author: Pierre Meyer <support@qarks.com>
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 2.1, as 
 * published by the Free Software Foundation.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
 * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this software; see the file LICENSE.  If not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 */
package com.qarks.util.ui.swing;

import javax.print.attribute.*;
import javax.print.attribute.standard.*;

import java.awt.*;
import java.awt.print.*;
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import com.qarks.util.ui.DialogUtilities;
import java.awt.event.AdjustmentListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

public class PrintManager extends JPanel implements Printable {

  private JTextPane printTextArea;
  private Paper currentPrintJobPaper;
  private JScrollBar scrollBar;
  private JDialog dialog;
  private boolean cancelled = false;
  private int cols,rows;

  public static void print(String htmlString, Window parent) {
    print(htmlString, parent, true, false);
  }

  public static void print(String htmlString, Window parent, boolean landscape) {
    print(htmlString, parent, true, landscape);
  }

  public static void print(String htmlString, Window parent, boolean preview, boolean landscape) {

    PrinterJob job = PrinterJob.getPrinterJob();

    double mmToSize = 2.83411155;
    //double inchToSize = 71.98643;
    PageFormat pageFormat = job.defaultPage();
    HashPrintRequestAttributeSet attributeSet = new HashPrintRequestAttributeSet();
    if (landscape){
      attributeSet.add(OrientationRequested.LANDSCAPE);
    }
    if (job.printDialog(attributeSet)){
      for (Attribute attribute : attributeSet.toArray()) {
        if (attribute == OrientationRequested.LANDSCAPE) {
          pageFormat.setOrientation(PageFormat.LANDSCAPE);
        }
        else if (attribute == OrientationRequested.PORTRAIT) {
          pageFormat.setOrientation(PageFormat.PORTRAIT);
        }
        else if (attribute == OrientationRequested.REVERSE_LANDSCAPE) {
          pageFormat.setOrientation(PageFormat.REVERSE_LANDSCAPE);
        }
      }
      for (Attribute attribute : attributeSet.toArray()) {
        if (attribute instanceof MediaPrintableArea) {
          MediaPrintableArea media = (MediaPrintableArea) attribute;
          Paper paper = new Paper();
          if (pageFormat.getOrientation() == PageFormat.LANDSCAPE ||
              pageFormat.getOrientation() == PageFormat.REVERSE_LANDSCAPE) {
            paper.setImageableArea(0, 0,
                                   mmToSize *
                                   media.getHeight(MediaPrintableArea.MM),
                                   mmToSize *
                                   media.getWidth(MediaPrintableArea.MM));
          }
          else {
            paper.setImageableArea(0, 0,
                                   mmToSize *
                                   media.getWidth(MediaPrintableArea.MM),
                                   mmToSize *
                                   media.getHeight(MediaPrintableArea.MM));

          }
          pageFormat.setPaper(paper);
        }
      }
      PrintManager printManager = new PrintManager(htmlString, pageFormat.getPaper(), parent);
      job.setPrintable(printManager);
      if (preview) {
        printManager.showPreview();
      }
      if (!printManager.cancelled) {
        try {
          job.print(attributeSet);
        }
        catch (PrinterException e) {
          e.printStackTrace();
        }
      }
    }
  }

  public PrintManager(String htmlText, Paper currentPrintJobPaper, Window parent) {
    this.currentPrintJobPaper = currentPrintJobPaper;
    printTextArea = new JTextPane();
    printTextArea.setContentType("text/html");
    printTextArea.setText(htmlText);
    printTextArea.setEditable(false);
    MouseListener listeners[]=printTextArea.getMouseListeners();
    for(MouseListener listener:listeners){
      printTextArea.removeMouseListener(listener);
    }
    MouseMotionListener moListeners[]=printTextArea.getMouseMotionListeners();
    for(MouseMotionListener moListener:moListeners){
      printTextArea.removeMouseMotionListener(moListener);
    }

    int h = (int)currentPrintJobPaper.getImageableHeight();
    int w = (int)currentPrintJobPaper.getImageableWidth();

    Dimension prefSize = new Dimension( (int) w, (int) h);

    setLayout(new BorderLayout(5,5));
    JScrollPane scrollPane = new JScrollPane(printTextArea);
    scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
    scrollPane.setBorder(null);

    JPanel scrollPanel = new JPanel(new BorderLayout(0,0));
    scrollPanel.add(scrollPane, BorderLayout.CENTER);
    scrollBar = new JScrollBar(JScrollBar.HORIZONTAL);
    scrollPanel.add(scrollBar,BorderLayout.SOUTH);
    scrollBar.setVisible(false);

    add(scrollPanel, BorderLayout.CENTER);
    scrollPane.setPreferredSize(prefSize);

    JPanel toolbar = new JPanel(new FlowLayout(FlowLayout.RIGHT,5,5));
    JButton ok = new JButton("Ok");
    JButton cancel = new JButton("Cancel");
    toolbar.add(ok);
    toolbar.add(cancel);
    add(toolbar,BorderLayout.SOUTH);
    ok.addActionListener(new ActionListener(){
      public void actionPerformed(ActionEvent e){
        dialog.dispose();
      }
    });
    cancel.addActionListener(new ActionListener(){
      public void actionPerformed(ActionEvent e){
        dialog.dispose();
        cancelled = true;
      }
    });

    if (parent!=null){
      if (parent instanceof Frame) {
        dialog = new JDialog( (Frame) parent, "Print preview", true);
      }
      else {
        dialog = new JDialog( (Dialog) parent, "Print preview", true);
      }
    }
    else{
      dialog = new JDialog();
      dialog.setTitle("Print preview");
      dialog.setModal(true);
    }
    dialog.getContentPane().setLayout(new GridLayout(1, 1));
    dialog.getContentPane().add(this);
    dialog.pack();
    dialog.setResizable(false);

    Dimension viewDim = printTextArea.getSize();
    double nh = ((double)viewDim.height)/((double)h);
    double nw = ((double)viewDim.width)/((double)w);
    rows = (int)Math.ceil(nh);
    cols = (int)Math.ceil(nw);

    if (viewDim.width>printTextArea.getParent().getSize().width){
      scrollBar.setVisible(true);
      scrollBar.addAdjustmentListener(new AdjustmentListener(){
        public void adjustmentValueChanged(AdjustmentEvent e) {
          int value = scrollBar.getValue();
          double rate = scrollBar.getMaximum()-scrollBar.getVisibleAmount();
          JViewport viewPort = (JViewport)printTextArea.getParent();
          int min = viewPort.getSize().width;
          int max = printTextArea.getSize().width;
          double amountPerPercent = (((double)(max-min))/rate);
          printTextArea.setLocation((int)(-amountPerPercent*((double)value)),0);
        }
      });

    }
  }

  private void showPreview(){
    Window parent = dialog.getOwner();
    if (parent!=null && parent.isShowing()){
      DialogUtilities.centerWindow(dialog,parent);
    }
    else{
      DialogUtilities.centerOnScreen(dialog);
    }
  }

  public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
    double pageHeight = currentPrintJobPaper.getImageableHeight();
    double pageWidth = currentPrintJobPaper.getImageableWidth();

    if (pageIndex<rows*cols){
      Graphics2D g2d = (Graphics2D) graphics;

      double translationX = ((double)(pageIndex%cols))*pageWidth;
      double translationY = ((double)(pageIndex/cols))*pageHeight;

      g2d.translate(pageFormat.getImageableX() - translationX, pageFormat.getImageableY() - translationY);
      disableDoubleBuffering(this);
      printTextArea.paint(g2d);
      enableDoubleBuffering(this);
      return PAGE_EXISTS;
    }
    else {
      return NO_SUCH_PAGE;
    }
  }

  private void disableDoubleBuffering(Component c) {
    RepaintManager currentManager = RepaintManager.currentManager(c);
    currentManager.setDoubleBufferingEnabled(false);
  }

  private void enableDoubleBuffering(Component c) {
    RepaintManager currentManager = RepaintManager.currentManager(c);
    currentManager.setDoubleBufferingEnabled(true);
  }

}
