package com.ftinc.si.assist.test.web;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

import javax.imageio.ImageIO;

import org.openqa.selenium.OutputType;
import org.openqa.selenium.Point;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import com.ftinc.si.assist.run.Messages;
import com.ftinc.si.assist.test.TestLogger;
import com.ftinc.si.assist.test.Tool;

public class Snap extends PageAction {
	private PageAction cur_action = null;

	public Snap() {
	}

	public Snap(PageAction caction) {
		cur_action = caction;
	}

	//画面の準備ができるまで待つ。Actionごとに待ち方が異なる。
	protected WebElement waitUntil(WebDriver drv) {
		return null;
	}

	@Override
	protected void doCore(WebDriver drv, WebElement elm) {
		if(drv instanceof TakesScreenshot) {
			//ScrollはwaitUntilで実施済み。

			String fname = makeFileName(drv);
			File t_f = createJPEGFile(drv, fname);

			//messageがあればコメントに記入する。
			String t_msg = ""; //$NON-NLS-1$
			if (cur_action != null) {
				//errorを感知した時、PagePlayerがcur_actionを渡す。
				t_msg += cur_action.getClass().getSimpleName() + "(" + cur_action.getTarget() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
			}
			String t_msg2 = "";
			if (arg_map.containsKey("value")) {
				t_msg2 = arg_map.get("value").toString();//valueはsnapshot(msg)のmsg
			}
			if (t_msg2 == null || t_msg.length() == 0) {
				if (arg_map.containsKey("message")) {
					t_msg2 = arg_map.get("message").toString();
				}
			}

			addMessage(t_f, Tool.curCase + "(" + Integer.toString(Tool.curID) + "): " + t_msg + t_msg2); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		} else {
			throw new SnapshotException("\t\tsnap " + Messages.getString("Snap.10")); //$NON-NLS-1$ //$NON-NLS-2$
		}
	}

	//ファイル名(フルパス)を指定し、jpegを得る。
	private File createJPEGFile(WebDriver drv, String fname) {
		File t_out = new File(fname);
		File temp_png = null;

		//まず、pngファイルを作る。seleniumのスクリーンショットは正式なjpeg書式ではなく、png準拠を偽装しているらしい。
		try {
			temp_png = ((TakesScreenshot)drv).getScreenshotAs(OutputType.FILE);

			//出力した画像を一旦生画像にして、それをjpg書式に書く。
			BufferedImage t_image = ImageIO.read(temp_png);
			BufferedImage tmp_raw = null;

			Object path = arg_map.get("xpath");
			if (path != null && path.toString().length() > 0) {
				//Elementが指定されているので、その要素のみをCaptureする。
				WebElement elm = drv.findElement(getLocator());
				if (elm != null) {
					//二重のnullエラー対策

					int iWidth = elm.getSize().getWidth();
					int iHeight = elm.getSize().getHeight();

					Point point = elm.getLocation();
					int xcord = point.getX();
					int ycord = point.getY();

					//要素の解決ができなければ、全画面キャプチャ―する。
					tmp_raw = new BufferedImage(t_image.getWidth(), t_image.getHeight(), BufferedImage.TYPE_INT_RGB);

					//背景を白く塗ってからイメージを貼り付ける。
					Graphics2D t_g2d = tmp_raw.createGraphics();
					t_g2d.drawImage(t_image, 0, 0, Color.WHITE, null);

					tmp_raw = tmp_raw.getSubimage(xcord, ycord, iWidth, iHeight);
				}
			}
			if (tmp_raw == null) {
				//要素の解決ができなければ、全画面キャプチャ―する。
				tmp_raw = new BufferedImage(t_image.getWidth(), t_image.getHeight(), BufferedImage.TYPE_INT_RGB);

				//背景を白く塗ってからイメージを貼り付ける。
				Graphics2D t_g2d = tmp_raw.createGraphics();
				t_g2d.drawImage(t_image, 0, 0, Color.WHITE, null);
			}

			ImageIO.write(tmp_raw, "jpg", t_out); //$NON-NLS-1$

		} catch (IOException e) {
			throw new SnapshotException("\t\tsnap file=" + fname + Messages.getString("Snap.2") + " msg =" + e.getMessage());  //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		}

		return t_out;
	}

	//実行中のテストコマンド、時刻などから、作成するファイル名（拡張子なし）を合成する。
	private String makeFileName(WebDriver drv) {
		String t_header = ""; //$NON-NLS-1$
		if (arg_map.get("file_header") != null) { //$NON-NLS-1$
			t_header = arg_map.get("file_header").toString() + "!"; //$NON-NLS-1$
		}
		//TestCase名ではなく、TestCommandのIDを使う。OSSの外部アプリでは、日本語ファイル名を処理できない場合があるため。
		t_header += Tool.replaceB(TestLogger.cmdName(), ".", "_"); //$NON-NLS-1$

		Date t_date = new Date();
		SimpleDateFormat t_sfmt = new SimpleDateFormat("yyyyMMddhhmmssSSS"); //$NON-NLS-1$

		//保存するPathを決める。
		String f_name = null;

		f_name = PagePlayer.getProperty("webtest.snap.folder"); //$NON-NLS-1$
		//それでもないなら実行中フォルダに決める。
		if (f_name == null) {
			f_name = Tool.s_userdir + "\\snap"; //$NON-NLS-1$ //$NON-NLS-2$
		}
		//別名が設定されていれば変更する。
		f_name = Tool.convert2Alias(f_name); //$NON-NLS-1$

		File t_snapdir = new File(f_name);
		if (!t_snapdir.exists()) {
			t_snapdir.mkdir();
		}

		//拡張子は付加しない。
		f_name +="\\" + Tool.repairFileName(t_header + "@" + t_sfmt.format(t_date)) + ".jpg"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

		//禁止文字を除く
		return f_name;
	}

	//このPageActionではフォーカスする対象を持たない。あるいは、WebDriverから情報を取得する必要はない。
	protected boolean getFocussingElements(WebDriver drv, ArrayList<WebElement> el_list, ArrayList<String> xp_list, String xpaths) {
		return false;//WebElementGetterを開かないサイン
	}

	//メッセージがあれば、登録している外部コマンドを用いて、jpegにメッセージを追加する。
	private void addMessage(File fin, Object msg) {
		if (PagePlayer.getProperty("webtest.exifcmd").length() > 0) { //$NON-NLS-1$
			String[] t_params = PagePlayer.getProperty("webtest.exifcmd").split("\\\\,"); //$NON-NLS-1$ //$NON-NLS-2$

			File cmd_file = Tool._libfile(t_params[0]);
			if (!cmd_file.exists()) {
				//exifコマンドのパスをログに出力
				Tool.logIfDebug(null, "not found exif_exe=" + cmd_file.getAbsolutePath());

				//コマンドが見つからない。
				throw new SnapshotException(t_params[0] + Messages.getString("Snap.11") + msg + "]"); //$NON-NLS-1$ //$NON-NLS-2$
			}

			ArrayList<String> t_cmds = new ArrayList<String>();

			String t_msg = msg.toString();
			t_msg = t_msg.replaceAll("[\\s\"']", "_");//"'空白タブを、コマンドラインにおける無害文字に変換する。 //$NON-NLS-1$ //$NON-NLS-2$
			t_msg = Tool.esq4CMD(t_msg);

			for (int i = 0; i < t_params.length; i++) {
				String t_str = t_params[i];
				if (t_str.matches("^.*\\$MSG.*$")) {
					t_str = t_str.replace("$MSG", t_msg); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
					try {
						//exifのコード系はusc-2なので変換する。
						t_str = new String(t_str.getBytes("ISO-10646-UCS-2"), "ISO-10646-UCS-2");
					} catch (UnsupportedEncodingException e) {
						throw new SnapshotException("Failed to translate '" + t_str + "' to UTF-16.");
					}
				}
				t_cmds.add(t_str);
			}
			//加工対象のファイル
			String f_name = fin.getAbsolutePath();
			t_cmds.add("\"" + f_name + "\""); //$NON-NLS-1$ //$NON-NLS-2$

			StringBuilder t_result = new StringBuilder();

			//現在のフォルダを画像保存先に設定
			int t_res = 0;
			try {
				t_res = Tool.executeCommand(t_result, fin.getParent(), t_cmds.toArray(new String[t_cmds.size()]));
				if (t_res != 0) {
					throw new SnapshotException(t_result.toString() + "[\n" + msg + "]"); //$NON-NLS-1$ //$NON-NLS-2$
				}
			} catch (Exception e) {
				throw new SnapshotException(t_result.toString() + "[\n" + msg + "]"); //$NON-NLS-1$ //$NON-NLS-2$
			}
			Tool.logIfDebug(null, "succeeded to edit exif area:" + msg);
		}
	}
}
