package com.refactorerl.ui.logic;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangString;
import com.refactorerl.ui.common.Common;
import com.refactorerl.ui.common.Pair;
import com.refactorerl.ui.communication.ReferlProxy;
import com.refactorerl.ui.communication.process.ReferlProcess;
import com.refactorerl.ui.logic.dependency.DependencyRequest;
import com.refactorerl.ui.logic.dependency.DependencyRequestFactory;
import com.refactorerl.ui.logic.dependency.DependencyRequestFactory.DepType;
import com.refactorerl.ui.logic.dupcode.AlgorithmData;
import com.refactorerl.ui.logic.dupcode.CloneData;
import com.refactorerl.ui.logic.dupcode.CloneIdentifierlRequest;
import com.refactorerl.ui.logic.dupcode.GetAlgorithmDataRequest;
import com.refactorerl.ui.logic.dupcode.GetAlgorithmsRequest;
import com.refactorerl.ui.logic.filelist.AddFileRequest;
import com.refactorerl.ui.logic.filelist.DropFileRequest;
import com.refactorerl.ui.logic.filelist.FileListRequest;
import com.refactorerl.ui.logic.filelist.ResetDbRequest;
import com.refactorerl.ui.logic.investigations.DeleteInvestigationRequest;
import com.refactorerl.ui.logic.investigations.GetInvestigationsListRequest;
import com.refactorerl.ui.logic.investigations.Investigation;
import com.refactorerl.ui.logic.investigations.InvestigationsFactory;
import com.refactorerl.ui.logic.investigations.LoadInvestigationRequest;
import com.refactorerl.ui.logic.investigations.SaveInvestigationRequest;
import com.refactorerl.ui.logic.queries.ListQueryRequest;
import com.refactorerl.ui.logic.refactoring.RefactoringRequest;
import com.refactorerl.ui.logic.refactoring.RefactoringRequestFactory;

public class RequestTest {

	final private static String testModuleName = "test_file";
	final private static String testFunctionName = "test_file";
	final private static String testFileContent = "-module(" + testModuleName
			+ ").\n-export([]).\n" + testFunctionName + "()->\"hello\".";

	private static ReferlProcess process;
	private static ReferlProxy proxy;
	private static String dataDirPath;
	private static String testFilePath;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		System.out.println("// setUpBeforeClass");

		// JVM argument is something like:
		// -Drefactorerl_base="/home/daniel/opt/refactorerl-0.9.14.09"
		String baseDirPath = System.getProperty("refactorerl_base");

		Pair<ReferlProcess, ReferlProxy> pair = Common.startProxy(baseDirPath);

		if (pair == null)
			throw new Exception("Process or proxy was unable to start.");
		process = pair.key;
		proxy = pair.value;

		dataDirPath = System.getProperty("java.io.tmpdir") + File.separator
				+ "com_refactorerl_ui_test_test_files";
		createTestFile();
	}

	private static void createTestFile() throws IOException,
			FileNotFoundException {
		new File(dataDirPath).mkdir();
		File testFile = new File(dataDirPath + File.separator + testModuleName
				+ ".erl");
		testFile.delete();
		testFile.createNewFile();
		PrintWriter pw = new PrintWriter(testFile);
		pw.print(testFileContent);
		pw.flush();
		pw.close();

		testFilePath = testFile.getAbsolutePath();
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
		System.out.println("// tearDownAfterClass");
		proxy.stop();
		process.stop();
	}

	@Before
	public void setUp() throws Exception {
		OtpErlangObject o = proxy.sendRPC("referl_misc", "data_dir",
				new OtpErlangObject[0]);
		if (!(o instanceof OtpErlangString))
			throw new Exception(o.toString());

		createTestFile();
		new AddFileRequest(testFilePath, proxy, null).execute();
	}

	@After
	public void tearDown() throws Exception {
		new ResetDbRequest(proxy, null).execute();
	}

	 @Test
	 public void testAddFileRequest() throws Exception {
	 System.out.println(AddFileRequest.class);
	
	 Assert.assertTrue(new IsFilePresentRequest(testFilePath, proxy, null)
	 .execute());
	 }
	
	 @Test
	 public void testDropFileRequest() throws Exception {
	 System.out.println(DropFileRequest.class);
	
	 new DropFileRequest(testFilePath, proxy, null).execute();
	 Assert.assertFalse(new IsFilePresentRequest(testFilePath, proxy, null)
	 .execute());
	 }
	
	 @Test
	 public void testFileListRequest() throws Exception {
	 System.out.println(FileListRequest.class);
	
	 List<String> files = new FileListRequest(proxy, null).execute();
	 Assert.assertEquals(files.iterator().next(), testFilePath);
	 }
	
	 @Test
	 public void testRefactoringRequest() throws Exception {
	 System.out.println(RefactoringRequest.class);
	
	 RefactoringRequestFactory.createRenameFunctionRequest(testFunctionName,
	 0,
	 "addisabeba", testFilePath, proxy, null).execute();
	
	 File testFile = new File(testFilePath);
	
	
	 String content = Common.readFileContents(testFile);
	 Assert.assertTrue(Pattern.compile("addisabeba").matcher(content).find());
	
	 }
	 // TODO DependencyRequestFactory összes
	 @Test
	 public void testDependencyRequest() throws Exception {
	 Pair<DependencyRequest, String> pair = DependencyRequestFactory
	 .createSVGDrawFunctionRequest(DepType.ALL, Common.createRandomName(),
	 false,
	 new ArrayList<String>(), new ArrayList<String>(), new
	 ArrayList<String>(), proxy, null);
	 DependencyRequest req = pair.key;
	 String dotFilePath = pair.value;
	 req.execute();
	
	 File dotFile = new File(dotFilePath);
	 Assert.assertTrue(dotFile.exists());
	
	 String content = Common.readFileContents(dotFile);
	 Assert.assertTrue(Pattern.compile("graph").matcher(content).find());
	 }
	
	 @Test
	 public void testCreateNewInvestigation() throws Exception{
	 Investigation inv = InvestigationsFactory.createNewInvestigation("test1",
	 "test", testModuleName, testFunctionName, 0, proxy, null);
	 Assert.assertNotNull(inv);
	 Assert.assertEquals(inv.getName(), "test1");
	 Assert.assertTrue(inv.getNodes().size() == 1);
	
	 Assert.assertTrue(inv.getRoot().filePath.equals(testFilePath));
	 Assert.assertTrue(inv.getRoot().getChildren().isEmpty());
	
	 inv.addMemo(proxy.generatePid(), inv.getRoot(), "test memo", new
	 Pair<>(0,0));
	 Assert.assertTrue(inv.getRoot().getChildren().size() == 1);
	 }
	
	 @Test
	 public void testSaveInvestigationRequest() throws Exception{
	 Investigation inv = InvestigationsFactory.createNewInvestigation("test1",
	 "test", testModuleName, testFunctionName, 0, proxy, null);
	 SaveInvestigationRequest.createSaveInvestigationRequest(inv, proxy,
	 null).execute();
	 List<String> invs = new GetInvestigationsListRequest(proxy,
	 null).execute();
	 Assert.assertTrue(invs.contains("test1"));
	 }
	
	 @Test
	 public void testLoadInvestigationRequest() throws Exception{
	 Investigation inv = InvestigationsFactory.createNewInvestigation("test1",
	 "test", testModuleName, testFunctionName, 0, proxy, null);
	 SaveInvestigationRequest.createSaveInvestigationRequest(inv, proxy,
	 null).execute();
	
	 Investigation invReloaded = new LoadInvestigationRequest("test1", proxy,
	 null).execute();
	 Assert.assertNotNull(invReloaded);
	 Assert.assertTrue(invReloaded.equals(inv));
	 }
	
	 @Test
	 public void testDeleteInvestigationRequest() throws Exception{
	 Investigation inv = InvestigationsFactory.createNewInvestigation("test1",
	 "test", testModuleName, testFunctionName, 0, proxy, null);
	 SaveInvestigationRequest.createSaveInvestigationRequest(inv, proxy,
	 null).execute();
	
	 List<String> invs = new GetInvestigationsListRequest(proxy,
	 null).execute();
	 Assert.assertTrue(invs.contains("test1"));
	
	 new DeleteInvestigationRequest("test1", proxy, null).execute();
	 invs = new GetInvestigationsListRequest(proxy, null).execute();
	 Assert.assertFalse(invs.contains("test1"));
	 }

	@Test
	public void testCloneIdentifierlRequest() throws Exception {
		List<Pair<String, String>> algs = new GetAlgorithmsRequest(proxy, null)
				.execute();

		for (Pair<String, String> pair : algs) {
			
			String selected = pair.key;

			List<AlgorithmData> datas = new GetAlgorithmDataRequest(selected,
					proxy, null).execute();
			
			// to avoid 'name is already used' error
			for (AlgorithmData data : datas) {
				if(data.key.equals("enforce")){
					data.setValue(true);
				}
			}
			
			CloneData cd = new CloneIdentifierlRequest(selected, datas, proxy,
					null).execute();

			System.out.println(cd);
		}
	}

	@Test
	public void testListQueryRequest() throws Exception {
		List<String> ls = ListQueryRequest.createModuleListQueryRequest(proxy,
				null).execute();
		
		boolean found = false;
		for (String s : ls) {
			if (s.contains(testModuleName)) {
				found = true;
				break;
			}
		}
		
		Assert.assertTrue(found);

		ls = ListQueryRequest.createFunctionListQueryRequest(proxy, null)
				.execute();
		found = false;
		for (String s : ls) {
			if (s.contains(testFunctionName)) {
				found = true;
				break;
			}
		}
		Assert.assertTrue(found);

		ls = ListQueryRequest.createDirectoryListQueryRequest(proxy, null)
				.execute();
		Assert.assertTrue(ls.contains(dataDirPath));
	}

}
