package jp.sourceforge.cfneo.at4ie2.api.browser.impl.ie;

import java.util.ArrayList;
import java.util.List;

import jp.sourceforge.cfneo.at4ie2.BTRuntimeError;
import jp.sourceforge.cfneo.at4ie2.api.browser.AlertDialog;
import jp.sourceforge.cfneo.at4ie2.api.browser.Anchor;
import jp.sourceforge.cfneo.at4ie2.api.browser.Browser;
import jp.sourceforge.cfneo.at4ie2.api.browser.Button;
import jp.sourceforge.cfneo.at4ie2.api.browser.CheckBox;
import jp.sourceforge.cfneo.at4ie2.api.browser.ConfirmDialog;
import jp.sourceforge.cfneo.at4ie2.api.browser.Hidden;
import jp.sourceforge.cfneo.at4ie2.api.browser.HtmlDataComponent;
import jp.sourceforge.cfneo.at4ie2.api.browser.HtmlElement;
import jp.sourceforge.cfneo.at4ie2.api.browser.Radio;
import jp.sourceforge.cfneo.at4ie2.api.browser.Select;
import jp.sourceforge.cfneo.at4ie2.api.browser.Span;
import jp.sourceforge.cfneo.at4ie2.api.browser.TextField;

import org.apache.log4j.Logger;

import watij.elements.Checkbox;
import watij.elements.Checkboxes;
import watij.finders.SymbolFactory;
import watij.runtime.ie.IE;
import watij.time.TimeException;

public class BTInternetExplorer implements Browser {

	static int _browserId;

	Logger logger = Logger.getLogger(BTInternetExplorer.class);
	private int browserId;
	private IE ie;
	private boolean opened;

	public BTInternetExplorer() {
		this(null);
		logger.debug("public BTInternetExplorer()@" + opened);
	}
	BTInternetExplorer(IE ie) {
		logger.debug("BTInternetExplorer(IE ie)@" + opened);
		try {
			this.ie = ie;
			if (ie != null && ie.exists()) {
				this.opened = true;
			}
			_browserId++;
			this.browserId = _browserId;
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}

	protected void sendKey(String key) {
		try {
			Thread t = new Thread(new Sender(ie, key));
			t.start();
			Thread.sleep(500L);
			t = null;
			logger.debug("*** BTInternetExplorer:Thread killed.");
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	class Sender implements Runnable {
		IE ie;
		String keys;
		public Sender(IE ie, String keys) {
			this.ie = ie;
			this.keys = keys;
		}
		public void run() {
			logger.debug("*** Sender#run()");
			try {
				ie.sendKeys(keys);
				System.err.println("ie.sendKeys(keys);");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/*
	 * ブラウザへの操作。
	 */
	@Override
	public void open(String url) {
		try {
			if (opened) {
				this.ie.goTo(url);
			} else {
				this.ie = new IE();
				this.ie.start(url);
				this.opened = true;
			}
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public void goTo(String url) {
		this.open(url);
	}
	@Override
	public void close() {
		logger.debug("public void close()@" + this.opened);
		try {
			if (this.opened) {
				this.ie.close();
			}
			this.opened = false;
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public void saveScreenShot(String filepath) {
		try {
			this.ie.windowCapture(filepath);
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public void clickBrowserBack() {
		this.sendKey("{BS}");
	}
	@Override
	public void clickBrowserNext() {
		this.sendKey("%{RIGHT}");
	}

	/*
	 * ブラウザの情報。
	 */
	@Override
	public int getBrowserId() {
		return this.browserId;
	}
	@Override
	public boolean isOpened() {
		return this.opened;
	}
	@Override
	public String getTitle() {
		try {
			return this.ie.title();
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public String getUrl() {
		try {
			return this.ie.url();
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public int getChildBrowserCount() {
		try {
			int childCount = 0;
			if (this.ie.childBrowserCount() > 0) {
				for (int i = 0; i < this.ie.childBrowserCount(); i++) {
					if (new BTInternetExplorer(this.ie.childBrowser(i)).isOpened()) {
						childCount++;
					}
				}
			}
			return childCount;
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public Browser getChildeBrowser(int index) {
		if (this.getChildBrowserCount() == 0) {
			return null;
		}
		try {
			Browser b = new BTInternetExplorer(this.ie.childBrowser(index));
			if (b.isOpened()) {
				return b;
			}
			return null;
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}

	/*
	 * ポップアップコンポーネントへのアクセス。
	 */
	public AlertDialog getAlertDialog() {
		try {
			return new BTAlertDialog(this.ie.alertDialog());
		} catch (Exception e) {
			if (e instanceof TimeException &&
					e.getMessage().equals("Timeout exceeded.  Reason= Could not find Dialog with title = Microsoft Internet Explorer")) {
			} else {
				throw new BTRuntimeError(e);
			}
		}
		return new BTAlertDialog(null);
	}
	@Override
	public ConfirmDialog getConfirmDialog() {
		try {
			return new BTConfirmDialog(this.ie.confirmDialog());
		} catch (Exception e) {
			if (e instanceof TimeException &&
					e.getMessage().equals("Timeout exceeded.  Reason= Could not find Dialog with title = Microsoft Internet Explorer")) {
			} else {
				throw new BTRuntimeError(e);
			}
		}
		return new BTConfirmDialog(null);
	}

	/*
	 * UIコンポーネントへのアクセス。
	 */
	@Override
	public HtmlElement getHtmlElement(String id) {
		try {
			return new BTHtmlElement(this.ie.htmlElement(SymbolFactory.id, id));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public HtmlElement getHtmlElementByName(String name) {
		try {
			return new BTHtmlElement(this.ie.htmlElement(SymbolFactory.name, name));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public HtmlElement getHtmlElementByDom(String dom) {
		// TODO WatijがDOM非対応？なので何か考えるなり何なりしる＞＜
		return null;
	}
	@Override
	public HtmlElement getHtmlElementByXPath(String xpath) {
		try {
			return new BTHtmlElement(this.ie.htmlElement(SymbolFactory.xpath, xpath));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public HtmlElement getHtmlElementByLink(String url) {
		try {
			return new BTHtmlElement(this.ie.htmlElement(SymbolFactory.href, url));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public HtmlElement getHtmlElementByValue(String value) {
		try {
			return new BTHtmlElement(this.ie.htmlElement(SymbolFactory.value, value));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public HtmlDataComponent getHtmlDataComponent(String id) {
		try {
			return new BTHtmlDataComponent(this.ie.htmlElement(SymbolFactory.id, id));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public HtmlDataComponent gethtmlDataComponentByName(String name) {
		try {
			return new BTHtmlDataComponent(this.ie.htmlElement(SymbolFactory.name, name));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public TextField getTextField(String id) {
		try {
			return new BTTextField(this.ie.textField(SymbolFactory.id, id));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public TextField getTextFieldByName(String name) {
		try {
			return new BTTextField(this.ie.textField(SymbolFactory.name, name));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public Button getButton(String id) {
		try {
			return new BTButton(this.ie.button(SymbolFactory.id, id));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public Button getButtonByName(String name) {
		try {
			return new BTButton(this.ie.button(SymbolFactory.name, name));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public Button getButtonByValue(String value) {
		try {
			return new BTButton(this.ie.button(SymbolFactory.value, value));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public Anchor getAnchor(String id) {
		try {
			return new BTAnchor(this.ie.link(SymbolFactory.id, id));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public Anchor getAnchorByName(String name) {
		try {
			return new BTAnchor(this.ie.link(SymbolFactory.name, name));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public Anchor getAnchorByUrl(String url) {
		try {
			return new BTAnchor(this.ie.link(SymbolFactory.url, url));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public Anchor getAnchorByLabel(String label) {
		try {
			return new BTAnchor(this.ie.link(SymbolFactory.text, label));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public Span getSpan(String id) {
		try {
			return new BTSpan(this.ie.span(SymbolFactory.id, id));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public Span getSpanByName(String name) {
		try {
			return new BTSpan(this.ie.span(SymbolFactory.name, name));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public Hidden getHidden(String id) {
		try {
			return new BTHidden(this.ie.hidden(SymbolFactory.id, id));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public Hidden getHiddenByName(String name) {
		try {
			return new BTHidden(this.ie.hidden(SymbolFactory.name, name));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public Select getSelect(String id) {
		try {
			return new BTSelect(this.ie.selectList(SymbolFactory.id, id));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public Select getSelectByName(String name) {
		try {
			return new BTSelect(this.ie.selectList(SymbolFactory.name, name));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public Radio getRadioByName(String name) {
		try {
			return new BTRadio(this.ie.radios(SymbolFactory.name, name));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public CheckBox getCheckBox(String id) {
		try {
			return new BTCheckBox(this.ie.checkbox(SymbolFactory.id, id));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public CheckBox getCheckBoxByName(String name) {
		try {
			return new BTCheckBox(this.ie.checkbox(SymbolFactory.name, name));
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public List<CheckBox> getCheckBoxListByName(String name) {
		try {
			List<CheckBox> checkedList = new ArrayList<CheckBox>();
			Checkboxes checkboxes = this.ie.checkboxes();
			for (Checkbox checkbox: checkboxes) {
				if (name.equals(checkbox.name())) {
					checkedList.add(new BTCheckBox(checkbox));
				}
			}
			return checkedList;
		} catch (Exception e) {
			throw new BTRuntimeError(e);
		}
	}
	@Override
	public List<CheckBox> getCheckedCheckBoxByName(String name) {
		List<CheckBox> checkedList = new ArrayList<CheckBox>();
		List<CheckBox> baseList = this.getCheckBoxListByName(name);
		for (CheckBox checkBox: baseList) {
			if (checkBox.isChecked()) {
				checkedList.add(checkBox);
			}
		}
		return checkedList;
	}

}
