package charactermanaj.graphics.io;

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.event.IIOWriteWarningListener;
import javax.imageio.stream.ImageOutputStream;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileFilter;

import charactermanaj.model.AppConfig;

/*
 * イメージを保存するためのヘルパークラス.<br>
 */
public class ImageSaveHelper {

	/**
	 * PNGファイルフィルタ
	 */
	protected static final FileFilter pngFilter = new FileFilter() {
		@Override
		public boolean accept(File f) {
			return f.isDirectory() || f.getName().endsWith(".png");
		}
		@Override
		public String getDescription() {
			return "PNG(*.png)";
		}
	};

	/**
	 * JPEGファイルフィルタ
	 */
	protected static final FileFilter jpegFilter = new FileFilter() {
		@Override
		public boolean accept(File f) {
			return f.isDirectory() || f.getName().endsWith(".jpg") || f.getName().endsWith(".jpeg");
		}
		@Override
		public String getDescription() {
			return "JPEG(*.jpg;*.jpeg)";
		}
	};

	/**
	 * 最後に使用したディレクトリ
	 */
	protected File lastUseSaveDir;
	
	/**
	 * 最後に使用したフィルタ
	 */
	protected FileFilter lastUseFilter = pngFilter;
	
	/**
	 * 最後に使用したディレクトリを設定する
	 * @param lastUseSaveDir 最後に使用したディレクトリ、設定しない場合はnull
	 */
	public void setLastUseSaveDir(File lastUseSaveDir) {
		this.lastUseSaveDir = lastUseSaveDir;
	}
	
	/**
	 * 最後に使用したディレクトリを取得する
	 * @return 最後に使用したディレクトリ、なければnull
	 */
	public File getLastUsedSaveDir() {
		return lastUseSaveDir;
	}
	

	/**
	 * 画像ファイルの保存用ダイアログを表示する.
	 * @param parent 親ウィンドウ
	 * @return ファイル名
	 */
	public File showSaveFileDialog(Component parent) {
		JFileChooser fileChooser = new JFileChooser(lastUseSaveDir) {
			private static final long serialVersionUID = -9091369410030011886L;

			@Override
			public void approveSelection() {
				File outFile = getSelectedFile();
				if (outFile == null) {
					return;
				}
				String lcName = outFile.getName().toLowerCase();
				FileFilter selfilter = getFileFilter();
				if (selfilter == pngFilter) {
					if (!lcName.endsWith(".png")) {
						outFile = new File(outFile.getPath() + ".png");
						setSelectedFile(outFile);
					}
				} else if (selfilter == jpegFilter) {
					if (!lcName.endsWith(".jpeg") && !lcName.endsWith(".jpg")) {
						outFile = new File(outFile.getPath() + ".jpeg");
						setSelectedFile(outFile);
					}
				}
				
				if (outFile.exists()) {
					if (JOptionPane.showConfirmDialog(this, "上書きしてもよろしいですか?",
							"確認", JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
						return;
					}
				}
				
				super.approveSelection();
			}
		};
		fileChooser.setAcceptAllFileFilterUsed(false);
		fileChooser.addChoosableFileFilter(jpegFilter);
		fileChooser.addChoosableFileFilter(pngFilter);
		if (lastUseFilter != pngFilter && lastUseFilter != jpegFilter) {
			lastUseFilter = pngFilter;
		}
		fileChooser.setFileFilter(lastUseFilter);
		int ret = fileChooser.showSaveDialog(parent);
		if (ret != JFileChooser.APPROVE_OPTION) {
			return null;
		}
		
		File outFile = fileChooser.getSelectedFile();
		lastUseSaveDir = outFile.getParentFile();
		lastUseFilter = fileChooser.getFileFilter();
		return outFile; 
	}
	
	public void savePicture(BufferedImage img, Color imgBgColor, File outFile, final StringBuilder warnings) throws IOException {
		if (img == null || outFile == null) {
			throw new IllegalArgumentException();
		}
		String fname = outFile.getName();
		int extpos = fname.lastIndexOf(".");
		if (extpos < 0) {
			throw new IOException("missing file extension.");
		}
		String ext = fname.substring(extpos + 1).toLowerCase();
		
		Iterator<ImageWriter> ite = ImageIO.getImageWritersBySuffix(ext);
		if (!ite.hasNext()) {
			throw new IOException("unsupported file extension: " + ext);
		}
		
		ImageWriter iw = ite.next();
		savePicture(img, imgBgColor, iw, outFile, warnings);
	}
	
	public void savePicture(BufferedImage img, Color imgBgColor,
			OutputStream outstm, String mime, final StringBuilder warnings)
			throws IOException {
		if (img == null || outstm == null || mime == null) {
			throw new IllegalArgumentException();
		}
		
		Iterator<ImageWriter> ite = ImageIO.getImageWritersByMIMEType(mime);
		if (!ite.hasNext()) {
			throw new IOException("unsupported mime: " + mime);
		}

		ImageWriter iw = ite.next();
		savePicture(img, imgBgColor, iw, outstm, warnings);
		outstm.flush();
	}
	
	protected void savePicture(BufferedImage img, Color imgBgColor, ImageWriter iw,
			Object output, final StringBuilder warnings)
			throws IOException {
		try {
			if (warnings != null) {
				iw.addIIOWriteWarningListener(new IIOWriteWarningListener() {
					public void warningOccurred(ImageWriter source, int imageIndex,
							String warning) {
						if (warnings.length() > 0) {
							warnings.append(System.getProperty("line.separator"));
						}
						warnings.append(warning);
					}
				});
			}

			boolean jpeg = false;
			boolean png = false;
			for (String mime : iw.getOriginatingProvider().getMIMETypes()) {
				if (mime.contains("image/jpeg")) {
					jpeg = true;
					break;
				}
				if (mime.contains("image/png") || mime.contains("image/x-png")) {
					png = true;
					break;
				}
			}

			ImageWriteParam iwp = iw.getDefaultWriteParam();
			IIOImage ioimg;

			if (jpeg) {
				AppConfig appConfig = AppConfig.getInstance();
				iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
				iwp.setCompressionQuality(appConfig.getCompressionQuality());
			}

			if (!png) {
				// PNG以外(JPEG等)は透過色をサポートしていないので。
				ioimg = new IIOImage(createJpegFormatPicture(img, imgBgColor), null, null);

			} else {
				ioimg = new IIOImage(img, null, null);
			}

			ImageOutputStream bos = ImageIO.createImageOutputStream(output);
			try {
				iw.setOutput(bos);
				iw.write(null, ioimg, iwp);
			} finally {
				bos.close();
			}

		} finally {
			iw.dispose();
		}
	}
	
	public BufferedImage createJpegFormatPicture(BufferedImage img, Color imgBgColor) {
		if (img == null) {
			throw new IllegalArgumentException();
		}
		int w = img.getWidth();
		int h = img.getHeight();
		BufferedImage tmpImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_BGR);
		Graphics2D g = tmpImg.createGraphics();
		try {
			if (imgBgColor == null) {
				g.setColor(Color.white);
			} else {
				g.setColor(imgBgColor);
			}
			g.fillRect(0, 0, w, h);
			g.drawImage(img, 0, 0, w, h, 0, 0, w, h, null);
		} finally {
			g.dispose();
		}
		return tmpImg;
	}

}
