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

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;


//Locatorの指定のFrameに移す。もしくはタイトルが指定されていたら、そのFrameに移す。
//どちらも指定されていない場合は、TOPに戻す。
public class ToFrame extends PageAction {
	@Override
	protected void doCore(WebDriver drv, WebElement elm) {
		//フォーカスをトップに戻す。
		drv.switchTo().defaultContent();

		int t_sec = getTimeout();
		WebDriverWait wait = new WebDriverWait(drv, t_sec);

		final String t_title = (String)arg_map.get("title");
		final String t_src = (String)arg_map.get("src");
		final String t_name = (String)arg_map.get("name");
		if (t_title == null && t_src == null && t_name == null) {
			//titleが指定されていなければ、次の二つのケースが考えられる。
			//　　(1)WebElementGetterで編集されたものである。
			//　　(2)frame/iframeタグ＋id属性などを使用したxpathを指定している。
			if (getLocator() != null) {
				String frame_paths[] = getXpath().split("//iframe", -1);
				if (frame_paths.length > 1) {
					// iframeが複数階層になっている場合。
					for (int i = 1; i < frame_paths.length; i++) {
						//iframe階層ごとにフォーカスを順次移していく。
						wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt("//iframe" + frame_paths[i]));
					}
				} else {
					// frame/iframe階層が１の場合
					wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(getLocator()));
				}
			}
		} else if (t_src != null || t_name != null) {
			String sttr = "src";
			if (t_name != null) {
				sttr = "name";
			}
			final String attr_name = sttr;
			//srcが指定されている場合、URLにマッチしたフレームにフォーカスを移す。。
			ExpectedCondition<Boolean> t_ec = new ExpectedCondition<Boolean>() {
				public Boolean apply(WebDriver drv) {
					//frame（普通のフレーム）
					List<WebElement> t_list1 = drv.findElements(By.xpath("//frame"));
					for (int i = 0; i < t_list1.size(); i++) {
						String temp_src = t_list1.get(i).getAttribute(attr_name);
						if (t_src.equals(temp_src)) {
							wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(t_list1.get(i)));
							return true;
						}
					}

					//iframe(インナーフレーム)
					List<WebElement> t_list2 = drv.findElements(By.xpath("//iframe"));
					for (int i = 0; i < t_list2.size(); i++) {
						String temp_src = t_list1.get(i).getAttribute(attr_name);
						if (t_src.equals(temp_src)) {
							wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(t_list2.get(i)));
							return true;
						}
					}
					return false;
				}
			};
			wait.until(t_ec);
		} else {
			//titleが指定されている場合、正規表現にマッチしたフレームにフォーカスを移す。。
			ExpectedCondition<Boolean> t_ec = new ExpectedCondition<Boolean>() {
				public Boolean apply(WebDriver drv) {
					//frame（普通のフレーム）
					List<WebElement> t_list1 = drv.findElements(By.xpath("//frame"));
					for (int i = 0; i < t_list1.size(); i++) {
						if (matchTitle(drv, t_list1.get(i), t_title)) {
							return true;
						}
					}

					//iframe(インナーフレーム)
					List<WebElement> t_list2 = drv.findElements(By.xpath("//iframe"));
					for (int i = 0; i < t_list2.size(); i++) {
						if (matchTitle(drv, t_list2.get(i), t_title)) {
							return true;
						}
					}
					//失敗したので、元に戻す。
					drv.switchTo().defaultContent();
					return false;
				}
			};
			wait.until(t_ec);
		}
	}

	//parentは入れ子Frameの親。targetにフォーカスし、titleがマッチしていればtrueを返す。
	//trueの場合、switchしたままとする。falseの場合、フォーカスを親に移す。
	private static boolean matchTitle(WebDriver drv, WebElement target, String title) {
		Pattern t_pat = Pattern.compile(title);

		//最上位のフレーム
		WebDriverWait wait = new WebDriverWait(drv, 10);
		wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(target));

		Matcher t_m = t_pat.matcher(drv.getTitle());
		if (t_m.find()) {
			return true;
		}
		return false;
	}

	//以下、Assertと二重の書き込みになるが自動的に整合性は保たれる。
	//WebElementGetterのArgument欄の値を指定する。
	protected ArrayList<String> getLabelAndParams() {
		return null;
	}

	//xpath検索の手がかりを指定する。WebElementGetterでは、入れ子の(i)ftameについてはサポートしない。
	//このPageActionが対象とするXPathの配列を返す。frame以外に対象としないので引数に影響されない。
	protected String[] getFocussingXPaths(String xpath) {
		String[] t_result = {"//frame", "//iframe"};
		return t_result;
	}

}
