package interactivefeaturelocator.actions;

import interactivefeaturelocator.model.Feature;
import interactivefeaturelocator.model.DerivationManager;
import interactivefeaturelocator.model.Pattern;
import interactivefeaturelocator.model.ProgressMonitor;
import interactivefeaturelocator.test.Test;
import interactivefeaturelocator.views.InteractiveDerivationView;
import interactivefeaturelocator.views.TraceView;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;

import javax.xml.parsers.ParserConfigurationException;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.ui.PartInitException;
import org.ntlab.trace.IMethodExecutionVisitor;
import org.ntlab.trace.MethodExecution;
import org.ntlab.trace.SoftwareReconnaissance;
import org.ntlab.trace.ThreadInstance;
import org.ntlab.trace.Trace;
import org.xml.sax.SAXException;

public class InteractiveFeatureLocatorAction implements IWorkbenchWindowActionDelegate {
	private IWorkbenchWindow window;
	private Display display;
	 private String featureFolderPath = null; // 本番用
//	private String featureFolderPath = "C:\\Users\\student\\git\\org.ntlab.interactiveFeatureLocator\\InteractiveFeatureLocator\\Feature\\Feature1593375"; // テスト用
	private String featureXMLPath = null;
	private String otherfeatureTraceName = null;
	// private int featureNo = 0; // 本番用
	private int featureNo = 1593375; // テスト用
	private DerivationManager derivationManager;
	private TraceView threadListView;
	private IWorkbenchPage page;
	private ProgressMonitor monitor;

	@Override
	public void run(IAction action) {
		// TODO Auto-generated method stub

		final int width = 700;
		final int height = 600;
		page = window.getActivePage();

		final Shell shell = new Shell(SWT.SHELL_TRIM | SWT.APPLICATION_MODAL);
		shell.setText("機能抽出");
		display = shell.getDisplay();

		// Shell全体のレイアウト
		shell.setLayout(new FormLayout());

		// 上部のテキスト
		Label topLabel = new Label(shell, SWT.NONE);
		topLabel.setText("\n関心のある機能に関連するメソッドを抽出するツールです。\n ");
		topLabel.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
		topLabel.setFont(new Font(display, "", 8, SWT.BOLD));
		FormData topLabelForm = new FormData();
		topLabelForm.top = new FormAttachment(0, 0);
		topLabelForm.left = new FormAttachment(0, 0);
		topLabelForm.right = new FormAttachment(100, 0);
		topLabel.setLayoutData(topLabelForm);

		// キャンセルボタン
		final Button canselButton = new Button(shell, SWT.PUSH);
		canselButton.setText("キャンセル");
		canselButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent arg0) {
				shell.dispose();
			}
		});
		// キャンセルボタンのレイアウト
		FormData canselButtonForm = new FormData();
		canselButtonForm.bottom = new FormAttachment(100, -10);
		canselButtonForm.right = new FormAttachment(100, -20);
		canselButtonForm.left = new FormAttachment(100, -120);
		canselButton.setLayoutData(canselButtonForm);

		// 解析ボタン
		final Button analysisButton = new Button(shell, SWT.PUSH);
		analysisButton.setText("解析");
		// 解析ボタンのレイアウト
		FormData analysisButtonForm = new FormData();
		analysisButtonForm.bottom = new FormAttachment(100, -10);
		analysisButtonForm.right = new FormAttachment(canselButton, -20);
		analysisButtonForm.left = new FormAttachment(canselButton, -220);
		analysisButton.setLayoutData(analysisButtonForm);

		// 実行トレース入力部分のレイアウト
		Composite bodyComposite = new Composite(shell, SWT.NONE);
		bodyComposite.setLayout(new FormLayout());
		FormData bodyForm = new FormData();
		bodyForm.top = new FormAttachment(topLabel, 0);
		bodyForm.left = new FormAttachment(0, 0);
		bodyForm.right = new FormAttachment(100, 0);
		bodyForm.bottom = new FormAttachment(canselButton, -10);
		bodyComposite.setLayoutData(bodyForm);

		// 対象機能フォルダ選択部分のレイアウト
		Group featureGroup = new Group(bodyComposite, SWT.NONE);
		featureGroup.setLayout(new FormLayout());
		featureGroup.setText("対象機能ファイル");
		FormData featureGroupForm = new FormData();
		featureGroupForm.top = new FormAttachment(topLabel, 5);
		featureGroupForm.left = new FormAttachment(0, 10);
		featureGroupForm.right = new FormAttachment(100, -10);
		featureGroupForm.bottom = new FormAttachment(featureGroup, 100);
		featureGroup.setLayoutData(featureGroupForm);

		// テキストのレイアウト
		Label featureGroupLabel = new Label(featureGroup, SWT.NONE);
		featureGroupLabel.setText("対象機能に関するfeatureファイルなどを持つフォルダを選択してください。");
		FormData labelForm = new FormData();
		labelForm.top = new FormAttachment(0, 10);
		labelForm.left = new FormAttachment(0, 10);
		labelForm.right = new FormAttachment(100, -100);
		labelForm.bottom = new FormAttachment(featureGroupLabel, 30);
		featureGroupLabel.setLayoutData(labelForm);

		// フォルダ名表示
		Label folderNameLabel = new Label(featureGroup, SWT.BORDER);
		folderNameLabel.setText(featureFolderPath);
		FormData folderNameForm = new FormData();
		folderNameForm.top = new FormAttachment(featureGroupLabel, 0);
		folderNameForm.left = new FormAttachment(0, 10);
		folderNameForm.right = new FormAttachment(100, -100);
		folderNameForm.bottom = new FormAttachment(folderNameLabel, 30);
		folderNameLabel.setLayoutData(folderNameForm);

		// フォルダ選択ボタンのレイアウト
		Button selectButton = new Button(featureGroup, SWT.PUSH);
		selectButton.setText("選択");
		selectButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				DirectoryDialog f = new DirectoryDialog(shell, SWT.OPEN);
				f.setText("対象機能のフォルダを選択してください。");
				if (f.open() == null) return;
				featureFolderPath = f.getFilterPath();
				String[] fragments = featureFolderPath.split("\\\\");
				String[] fragments2 = fragments[fragments.length - 1].split("Feature");
				featureNo = Integer.parseInt(fragments2[fragments2.length - 1]);
				folderNameLabel.setText(featureFolderPath);
				System.out.println(featureFolderPath);
			}
		});
		FormData selectButtonForm = new FormData();
		selectButtonForm.top = new FormAttachment(0, 40);
		selectButtonForm.left = new FormAttachment(folderNameLabel, 20);
		selectButtonForm.right = new FormAttachment(100, -10);
		selectButton.setLayoutData(selectButtonForm);

		// その他の機能の実行トレース
		Group otherFeatureGroup = new Group(bodyComposite, SWT.NONE);
		otherFeatureGroup.setLayout(new FormLayout());
		otherFeatureGroup.setText("その他の機能の実行トレース");
		FormData otherFeatureGroupForm = new FormData();
		otherFeatureGroupForm.top = new FormAttachment(featureGroup, 5);
		otherFeatureGroupForm.left = new FormAttachment(0, 10);
		otherFeatureGroupForm.right = new FormAttachment(100, -10);
		otherFeatureGroupForm.bottom = new FormAttachment(100, -5);
		otherFeatureGroup.setLayoutData(otherFeatureGroupForm);

		// テキストのレイアウト
		Label otherFeatureGroupLabel = new Label(otherFeatureGroup, SWT.NONE);
		otherFeatureGroupLabel.setText("対象機能に影響を与える実行トレースを追加してください。");
		otherFeatureGroupLabel.setLayoutData(labelForm);

		// 実行トレース追加ボタンのレイアウト
		Button addButton = new Button(otherFeatureGroup, SWT.PUSH);
		addButton.setText("追加");
		FormData addButtonForm = new FormData();
		addButtonForm.top = new FormAttachment(otherFeatureGroupLabel, 10);
		addButtonForm.left = new FormAttachment(0, 10);
		addButtonForm.right = new FormAttachment(addButton, 110);
		addButton.setLayoutData(addButtonForm);

		// 削除ボタンのレイアウト
		Button deleteButton = new Button(otherFeatureGroup, SWT.PUSH);
		deleteButton.setText("削除");
		FormData deleteButtonForm = new FormData();
		deleteButtonForm.top = new FormAttachment(otherFeatureGroupLabel, 10);
		deleteButtonForm.left = new FormAttachment(addButton, 10);
		deleteButtonForm.right = new FormAttachment(deleteButton, 110);
		deleteButton.setLayoutData(deleteButtonForm);

		// 全て削除ボタンのレイアウト
		Button allDeleteButton = new Button(otherFeatureGroup, SWT.PUSH);
		allDeleteButton.setText("全て削除");
		FormData allDeleteButtonForm = new FormData();
		allDeleteButtonForm.top = new FormAttachment(otherFeatureGroupLabel, 10);
		allDeleteButtonForm.left = new FormAttachment(deleteButton, 10);
		allDeleteButtonForm.right = new FormAttachment(allDeleteButton, 110);
		allDeleteButton.setLayoutData(allDeleteButtonForm);

		// 追加された実行トレースリストのレイアウト
		List list = new List(otherFeatureGroup, SWT.BORDER | SWT.SINGLE | SWT.V_SCROLL);
		FormData listForm = new FormData();
		listForm.top = new FormAttachment(addButton, 10);
		listForm.left = new FormAttachment(0, 10);
		listForm.right = new FormAttachment(100, -10);
		listForm.bottom = new FormAttachment(100, -10);
		list.setLayoutData(listForm);

		// 追加ボタン押下時の処理
		addButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				FileDialog f = new FileDialog(shell, SWT.OPEN);
				f.setText("対象機能に影響を与える実行トレースを選択してください。");
				if (f.open() == null) return;
				otherfeatureTraceName = f.getFileName(); // テスト用
				// otherFeatureGroupLabel.setText(otherfeatureTraceName); // 本番用
				list.add(otherfeatureTraceName);
			}
		});

		// 削除ボタン押下時の処理
		deleteButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				try {
					list.remove(list.getSelectionIndex());
				} catch (IllegalArgumentException e) {
					MessageDialog.openError(shell, "エラー",
							"削除する実行トレースを選択してください。");
				}
			}
		});

		// 全て削除ボタン押下時の処理
		allDeleteButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if (list.getItemCount() != 0) {
					boolean ok = MessageDialog.openConfirm(shell, "確認",
							"その他の実行トレースを全て削除してよろしいですか？");
					if (ok) {
						list.removeAll();
					}
				}
			}
		});

		// 解析ボタン押下時の処理
		analysisButton.addSelectionListener(new SelectionAdapter() {

			public void widgetSelected(SelectionEvent arg0) {
				featureXMLPath = featureFolderPath + "\\feature" + featureNo + ".xml";
				File featureFile = new File(featureXMLPath);
				// feature.xmlが存在するかの判定
				if (featureFile.exists()) {
					boolean ok = MessageDialog.openConfirm(shell, "確認",
							"対象機能フォルダ : " + folderNameLabel.getText() + "\n解析を始めます。");
					if (ok) {
						threadListView = TraceView.theInstance;
						if (threadListView == null) {
							try {
								page.showView(TraceView.ID, null, IWorkbenchPage.VIEW_VISIBLE);
								System.out.println("ThreadListViewを開きます。");
							} catch (PartInitException e) {
								page.findView(TraceView.ID);
							}
						}
						InteractiveDerivationView.theInstance.reset();
						shell.dispose();
						try {
							Feature feature = new Feature(featureFolderPath);
							derivationManager = new DerivationManager(feature);
							derivationManager.firstInference();
							
							threadListView.setInferanceManager(derivationManager);
							threadListView.updateViewer();
						} catch (ParserConfigurationException | SAXException | IOException e2) {
							e2.printStackTrace();
						}
					}
				} else {
					MessageDialog.openError(shell, "エラー",
							"対象機能フォルダを選択してください。(feature.xmlを持つフォルダを選択してください。)");
				}
			}
		});

		// 実行トレース入力シェルの表示処理
		// shell.pack();
		shell.setSize(width, height);
		shell.open();

		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}

	}

	@Override
	public void selectionChanged(IAction action, ISelection selection) {
		// TODO Auto-generated method stub

	}

	@Override
	public void dispose() {
		// TODO Auto-generated method stub

	}

	@Override
	public void init(IWorkbenchWindow window) {
		// TODO Auto-generated method stub
		this.window = window;
	}

	// scenario.xmlをもとに解析
	public DerivationManager doAnalyze(Feature feature) {
		System.out.println("解析開始");
//		monitor = new ProgressMonitor(window.getShell());
//		monitor.getMonitor().worked(1);

		DerivationManager im = new DerivationManager(feature);

		// 進捗ダイアログ
		im.firstInference();
//		HashMap<Trace, HashSet<ThreadInstance>> threadsWithSRMethodsMap = new HashMap<>(); // SR結果を含むTraceとそのThreads
//		HashMap<ThreadInstance, HashSet<MethodExecution>> threadToSRMethods = new HashMap<>(); // SR結果を含むThreadとそのMethods

//		selectMethodView.setThreadToMethods(threadToSRMethods);
					
		return im;
	}

	public ArrayList<File> getFolder(File[] files) {
		ArrayList<File> dir = new ArrayList<>();
		for (File f : files) {
			if (f.isDirectory()) {
				dir.add(f);
			}
		}
		return dir;
	}

	public ArrayList<File> getFile(File[] files) {
		ArrayList<File> fil = new ArrayList<>();
		for (File f : files) {
			if (f.isFile()) {
				fil.add(f);
			}
		}
		return fil;
	}
	
	public ProgressMonitor getMonitor() {
		return monitor;
	}

}
