
package jp.riken.brain.ni.samuraigraph.application;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.PrintJob;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Area;
import java.awt.geom.Line2D;
import java.awt.print.PrinterJob;
import java.io.File;
import java.util.Properties;

import javax.print.PrintService;
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import jp.riken.brain.ni.samuraigraph.base.SGDialog;
import jp.riken.brain.ni.samuraigraph.base.SGDrawingWindow;
import jp.riken.brain.ni.samuraigraph.base.SGIConstants;
import jp.riken.brain.ni.samuraigraph.base.SGIImageExportManager;
import jp.riken.brain.ni.samuraigraph.base.SGUtility;

import org.freehep.graphicsio.ImageGraphics2D;
import org.freehep.graphicsio.PageConstants;
import org.freehep.graphicsio.cgm.CGMGraphics2D;
import org.freehep.graphicsio.emf.EMFGraphics2D;
import org.freehep.graphicsio.pdf.PDFGraphics2D;
import org.freehep.graphicsio.ps.PSGraphics2D;
import org.freehep.graphicsio.svg.SVGGraphics2D;
import org.freehep.graphicsio.swf.SWFGraphics2D;
import org.freehep.util.UserProperties;
import org.freehep.util.export.ExportDialog;


/**
 * A class used to preview, print and export an image.
 */
public class SGImageExportManager
	implements SGIImageExportManager, SGIConstants
{

	/**
	 * 
	 */
	public static final String DEFAULT_EXPORT_FILE_NAME = "export";
	
	
	/**
	 * 
	 */
	public static final String DEFAULT_TITLE_NAME = "Export view as ...";


	/**
	 * Static constants for VectorGraphics
	 */
	private static final String PREFIX = ImageGraphics2D.rootKey + ".";
	private static final String BG_SUFFIX = "." + PageConstants.BACKGROUND;
	private static final String BG_COLOR_SUFFIX = "." + PageConstants.BACKGROUND_COLOR;
	private static final String GIF = "gif";
	private static final String JPG = "jpg";
	private static final String PNG = "png";
	private static final String RAW = "raw";
	private static final String PPM = "ppm";
	private static final String[][] BG_KEY_ARRAY = {
		{ CGMGraphics2D.BACKGROUND, CGMGraphics2D.BACKGROUND_COLOR },
		{ PSGraphics2D.BACKGROUND, PSGraphics2D.BACKGROUND_COLOR },
		{ SWFGraphics2D.BACKGROUND, SWFGraphics2D.BACKGROUND_COLOR },
		{ PDFGraphics2D.BACKGROUND, PDFGraphics2D.BACKGROUND_COLOR },
		{ SVGGraphics2D.BACKGROUND, SVGGraphics2D.BACKGROUND_COLOR },
		{ EMFGraphics2D.BACKGROUND, EMFGraphics2D.BACKGROUND_COLOR },
		{ PREFIX + GIF + BG_SUFFIX, PREFIX + GIF + BG_COLOR_SUFFIX },
		{ PREFIX + JPG + BG_SUFFIX, PREFIX + JPG + BG_COLOR_SUFFIX },
		{ PREFIX + PNG + BG_SUFFIX, PREFIX + PNG + BG_COLOR_SUFFIX },
		{ PREFIX + RAW + BG_SUFFIX, PREFIX + RAW + BG_COLOR_SUFFIX },
		{ PREFIX + PPM + BG_SUFFIX, PREFIX + PPM + BG_COLOR_SUFFIX }
	};


	/**
	 * An export dialog.
	 */
	private final ExportDialog mExportDialog = new ExportDialog();


	/**
	 * 
	 */
	private String mBaseDirectoryName = null;


	/**
	 * 
	 */
	private String mExportFileName = DEFAULT_EXPORT_FILE_NAME;


	/**
	 * 
	 */
	private Component mTarget = null;


	/**
	 * Default constructor.
	 *
	 */
	public SGImageExportManager()
	{
		ExportDialogActionListener bl = new ExportDialogActionListener();
		this.mExportDialog.addActionListener(bl);
	}


	/**
	 * Export as image the target object.
	 * @param target - target object for export
	 * @param owner - owner object
	 * @param w - width of image
	 * @param h - height of image
	 * @return true:succeeded, false:failed
	 */
	public boolean export(
		Component target, Frame owner, final int w, final int h )
	{
		String title = "Export as Image";

		this.mTarget = target;

//target = new ExportTestPanel();

		// preview
		if( this.preview(
			target, owner, w, h, w, h,
			title, SGDialog.NEXT_BUTTON_TEXT, SGDialog.CANCEL_BUTTON_TEXT
			) == CANCEL
		)
		{
			return true;
		}

		if( this.mBaseDirectoryName==null )
		{
			this.mBaseDirectoryName = System.getProperty("user.dir");
		}

		ExportDialog ed = mExportDialog;
		Color bg = target.getBackground();
		Properties p = ed.getUserProperties();


		// directory
		String key = ExportDialog.SAVE_AS_FILE;
		String baseDir = this.mBaseDirectoryName;
		String path = ed.getUserProperties().getProperty(key);
		if( path!=null )
		{
			String parent = new File(path).getParent();
			String pathNew = baseDir + FILE_SEPARATOR + this.mExportFileName;
			ed.setUserProperty( key, pathNew );
		}
		String defFile = baseDir + FILE_SEPARATOR + this.mExportFileName;


		// background color
		String[][] bgArray = BG_KEY_ARRAY;
		for( int ii=0; ii<bgArray.length; ii++ )
		{
			String[] array = bgArray[ii];
			UserProperties.setProperty( p, array[0], true );
			UserProperties.setProperty( p, array[1], bg );
		}


		// show the modal export dialog
		ed.showExportDialog
		(
			owner,
			DEFAULT_TITLE_NAME,
			target,
			defFile
		);


		// get current directory
		String path_ = p.getProperty(key);
		if( path_!=null )
		{
			String parent = new File( path_ ).getParent();
			String name = path_.substring( parent.length() + 1 );
			this.setBaseDirectory( parent );
			this.mExportFileName = name;
		}


		return true;
	}


	// An action listener class for the export file dialog.
	private class ExportDialogActionListener implements ActionListener
	{
		public void actionPerformed( ActionEvent e )
		{
			Object source = e.getSource();
			if( source instanceof JComboBox )
			{
				JComboBox cb = (JComboBox)source;
				Object obj = cb.getSelectedItem();

				Component target = SGImageExportManager.this.mTarget;
				if( target instanceof SGDrawingWindow.ExportPanel )
				{
					SGDrawingWindow.ExportPanel p
						= (SGDrawingWindow.ExportPanel)target;
					final boolean b
						= ( obj instanceof org.freehep.graphicsio.ps.EPSExportFileType )
						| ( obj instanceof org.freehep.graphicsio.ps.PSExportFileType )
						| ( obj instanceof org.freehep.graphicsio.pdf.PDFExportFileType );
					p.setClipFlag(!b);
				}
			}
		}
	}


	/**
	 * 
	 * @param dir
	 */
	public void setBaseDirectory( String dir )
	{
		this.mBaseDirectoryName = new String(dir);
	}


	/**
	 * 
	 * @return
	 */
	public String getBaseDirectory()
	{
		return this.mBaseDirectoryName;
	}



	/**
	 * The OK button is pressed.
	 */
	public static final int OK = 0;

	/**
	 * The Cancel button is pressed or the window is closed.
	 */
	public static final int CANCEL = 1;


	/**
	 * Preview image of the target object.
	 * @param target - target object for export
	 * @param owner - owner object
	 * @param w - width of image
	 * @param h - height of image
	 * @return status
	 */
	private int preview(
		Component target, Frame owner,
		final int imageWidth, final int imageHeight,
		final int paperWidth, final int paperHeight,
		final String title, final String textOK, final String textCancel )
	{
		// create and show a modal preview dialog
		SGPreviewDialog dg = this.createPreviewDialog(
			target, owner, imageWidth, imageHeight, paperWidth, paperHeight,
			title, true );
		dg.setOKButtonText( textOK );
		dg.setCancelButtonText( textCancel );
		dg.setVisible(true);

		final int ret = dg.getCloseOption();
		if( ret==SGDialog.CANCEL_OPTION )
		{
			return CANCEL;
		}
		
		return OK;
	}



	/**
	 * Print image of the target object.
	 * @param target - target object for export
	 * @param owner - owner object
	 * @param w - width of image
	 * @param h - height of image
	 * @return true:succeeded, false:failed
	 */
	public boolean print( Component target, Frame owner, int w, int h )
	{
		
		// get available printers
		PrintService[] pArray = PrinterJob.lookupPrintServices();
		if( pArray.length==0 )
		{
			SGUtility.showMessageDialog(
				owner, "No printer is available.", "Error",
				JOptionPane.ERROR_MESSAGE
			);
			return false;
		}


		// create attributes objects
//		JobAttributes ja
//			= new JobAttributes(
//				1,
//				JobAttributes.DefaultSelectionType.ALL,
//				JobAttributes.DestinationType.PRINTER,
//				JobAttributes.DialogType.NATIVE,
//				null,
//				Integer.MAX_VALUE,
//				1,
//				JobAttributes.MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES,
//				new int[][]{ new int[]{ 1, 1 } },
//				null,
//				JobAttributes.SidesType.ONE_SIDED
//			);
//
//		PageAttributes pa
//			= new PageAttributes(
//				PageAttributes.ColorType.MONOCHROME,
//				PageAttributes.MediaType.A4,
//				PageAttributes.OrientationRequestedType.PORTRAIT,
//				PageAttributes.OriginType.PHYSICAL,
//				PageAttributes.PrintQualityType.HIGH,
//				new int[]{ 72, 72, 3 }
//			);


		//
		// preview
		//

		String title = "Print as Image";
		PrintJob job = null;
//		while( true )
		{
			job = Toolkit.getDefaultToolkit().getPrintJob(
				owner, "", null, null );
			if( job==null )
			{
				// returned value is equal to null when the print job is canceled
				return true;
			}

			Dimension paperSize = job.getPageDimension();
			final int ret = this.preview(
				target, owner, w, h,
				paperSize.width, paperSize.height,
				title,
				"Print",
				SGWizardDialog.CANCEL_BUTTON_TEXT );

			if( ret==OK )
			{
//				break;
			}
			else if( ret==CANCEL )
			{
				return true;
			}
		}


		//
		// print
		//

		// get a Graphics object to print
		Graphics g = job.getGraphics();

		// print objects
		target.printAll(g);

		//dispose a graphic object
		g.dispose();

		// end the print job
		job.end();

		return true;
	}



	/**
	 * Create a preview dilaog.
	 * @param target - target object for export
	 * @param owner - owner object
	 * @param w - width of image
	 * @param h - height of image
	 * @param modal - whether the preview dialog is modal
	 * @return true:succeeded, false:failed
	 */
	private SGPreviewDialog createPreviewDialog(
		Component target, Frame owner,
		final int imageWidth, final int imageHeight,
		final int paperWidth, final int paperHeight,
		final String title,
		final boolean modal )
	{
		SGPreviewDialog dg = new SGPreviewDialog( owner, title, modal );
		dg.pack();

		dg.setLocation( owner.getLocation() );
		dg.setTargetObject(
			target, imageWidth, imageHeight, paperWidth, paperHeight,
			target.getBackground() );

		return dg;		
	}



	/**
	 * A class for testing.
	 *
	 */
	private class ExportTestPanel extends JPanel
	{
		private ExportTestPanel()
		{
			super();
			this.init();
		}

		private void init()
		{
			this.setSize( 800, 800 );
			this.setOpaque(false);
		}

		public void paintComponent( Graphics g )
		{
			super.paintComponent(g);
			Graphics2D g2d = (Graphics2D)g;
			final float width = 24.0f;

			Rectangle rect = new Rectangle( 55, 40, 350, 420 );
			g2d.setStroke(
				new BasicStroke(
					1.0f,
					BasicStroke.CAP_BUTT,
					BasicStroke.JOIN_ROUND
				)
			);
			g2d.setPaint( Color.BLUE );
			g2d.draw(rect);

//			Line2D line0 = new Line2D.Float( 0.0f, 0.0f, 220.0f, 700.0f );
//			g2d.setPaint( Color.YELLOW );
//			g2d.draw(line0);
//
//			g2d.setClip(rect);
//
//			Line2D line1 = new Line2D.Float( 0.0f, 0.0f, 420.0f, 350.0f );
//			g2d.setPaint( Color.BLUE );
//			g2d.draw(line1);
//
//			g2d.setClip( new Rectangle( 0, 0, 500, 600 ) );
//
//			Line2D line2 = new Line2D.Float( 0.0f, 0.0f, 420.0f, 560.0f );
//			g2d.setPaint( Color.GREEN );
//			g2d.draw(line2);

			float dash[] = {10.0f, 5.0f};
			Stroke stroke = new BasicStroke(
				width,
				BasicStroke.CAP_BUTT,
				BasicStroke.JOIN_ROUND,
				10.0f, dash, 0.0f
			);


			Line2D.Float line = new Line2D.Float( 30.0f, 40.0f, 230.0f, 500.0f );

			g2d.setStroke( stroke );
			g2d.setPaint( Color.RED );
			g2d.draw(line);

			g2d.setPaint( Color.BLACK );
			g2d.setStroke( new BasicStroke( 2.0f ) );

//			SGDrawingElementLine2D el = new SGDrawingElementLine2D();
//			el.setTermPoints( line.x1, line.y1, line.x2, line.y2 );
//			el.setLineWidth( width );
//			Shape sh = el.getShapeWithThickness();
//			g2d.draw(sh);

			Area rectArea = new Area( rect );
//			Area shArea = new Area( sh );
//			shArea.intersect( rectArea );
//			g2d.draw( shArea );

			Shape shNew = stroke.createStrokedShape( line );
			Area areaNew = new Area(shNew);
			areaNew.intersect( rectArea );
			g2d.draw( areaNew );
			g2d.setPaint( Color.GREEN );
			g2d.fill( areaNew );

		}

	}


}

