//
// Created by Grishul Eugeny
//
// Copyright © Grishul Eugeny 2008
//

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

public class DbLayerTest {
	private DbLayer DbLayerInstance = new DbLayer();
	
	public DbLayerTest() {
	}

	@Before
	public void setUp() throws Throwable {
		DbLayerInstance.cleanup();
	}

	@After
	public void tearDown() throws Throwable {
		DbLayerInstance.cleanup();
	}
	private String[] _stringTestParameters = new String[] { "\b\t3454~!@#$%^&*()_+|\\`\0", "\"; DELETE FROM СОТРУДНИК;", "'; DELETE FROM СОТРУДНИК;", "; DELETE FROM СОТРУДНИК;" };

	@Test
	public void login() throws Throwable {
		for( String injection1 : _stringTestParameters )
			for( String injection2 : _stringTestParameters )
				assertEquals( false, DbLayerInstance.tryToLogin( injection1, injection2 ) );

		assertEquals( true, DbLayerInstance.tryToLogin( "root", "yoyoyo" ) );
	}

	@Test( expected = java.sql.SQLException.class )
	public void employsTransactionRollback() throws Throwable {
		DbEmployee employee = newEmployee();
		employee.Login = new String( "---------------------------------------------------------------------------------------------------------------" );

		DbLayerInstance.addEmployee( employee );
	}

	@Test
	public void employsCreation() throws Throwable {
		DbEmployee beforeFiring = newEmployee();
		DbEmployee afterFiring = beforeFiring.clone();

		DbLayerInstance.addEmployee( beforeFiring );
		DbLayerInstance.fireEmployee( beforeFiring.ID );
		DbLayerInstance.fireEmployee( 1 );

		assertEquals( null, DbLayerInstance.getEmployeeByID( -1 ) );

		afterFiring.Name = dateToTicks() + "";
		afterFiring.Surname = dateToTicks() + "";
		afterFiring.Patronymic = dateToTicks() + "";
		afterFiring.Description = dateToTicks() + "";
		afterFiring.Password = dateToTicks() + "";
		afterFiring.BirthDate = dateTimeNow();
		afterFiring.Photography = null;
		DbLayerInstance.addEmployee( afterFiring );

		// Сотрудник будучи нанят еще раз использует одну и ту же запись из таблицы ЧЕЛОВЕК
		assertFalse( beforeFiring.ID == afterFiring.ID );
		assertTrue( beforeFiring.HumanID == afterFiring.HumanID );

		// а сведения о человеке - обновляются
		beforeFiring = DbLayerInstance.getEmployeeByID( beforeFiring.ID );

		assertEquals( beforeFiring.Name, afterFiring.Name );
		assertEquals( beforeFiring.Surname, afterFiring.Surname );
		assertEquals( beforeFiring.Patronymic, afterFiring.Patronymic );
		assertEquals( beforeFiring.Description, afterFiring.Description );
		assertEquals( beforeFiring.BirthDate, afterFiring.BirthDate );

		afterFiring.Password = ( dateToTicks() ^ 37894657L ) + "";
		afterFiring.Passport = dateToTicks() + "";
		DbLayerInstance.addEmployee( afterFiring );

		// после смены паспорта - эт уже другой челове
		assertFalse( beforeFiring.ID == afterFiring.ID );
		assertFalse( beforeFiring.HumanID == afterFiring.HumanID );

		// injection-test
		for( String injection : _stringTestParameters ) {
			DbEmployee injected = beforeFiring.clone();

			injected.Login = injection + dateToTicks();
			injected.Password = injection + dateToTicks();
			injected.Passport = injection;
			injected.Name = injection;
			injected.Surname = injection;
			injected.Patronymic = injection;
			injected.Description = injection;

			DbLayerInstance.addEmployee( injected );
		}

		assertEquals( 7, DbLayerInstance.getAllEmploys().size() );
		assertEquals( 6, DbLayerInstance.getTotalEmployees() );
	}

	@Test
	public void employsUpdate() throws Throwable {
		DbEmployee before = newEmployee();
		DbLayerInstance.addEmployee( before );

		before.Name = dateToTicks() + "";
		before.Surname = dateToTicks() + "";
		before.Patronymic = dateToTicks() + "";
		before.Description = dateToTicks() + "";
		before.Password = dateToTicks() + "";
		before.BirthDate = dateTimeNow();
		before.PlacementDate = dateTimeNow();

		DbLayerInstance.updateEmployeeInfo( before );

		DbEmployee after = DbLayerInstance.getEmployeeByID( before.ID );

		assertEquals( before.Name, after.Name );
		assertEquals( before.Surname, after.Surname );
		assertEquals( before.Patronymic, after.Patronymic );
		assertEquals( before.Description, after.Description );
		assertEquals( before.Password, after.Password );
		assertEquals( before.BirthDate, after.BirthDate );
		assertEquals( before.PlacementDate.toString(), after.PlacementDate.toString() );

		DbEmployee byPassport = DbLayerInstance.getEmployeeInfoByPassport( before.Passport );
		assertEquals( byPassport.Name, after.Name );
		assertEquals( byPassport.Surname, after.Surname );
		assertEquals( byPassport.Patronymic, after.Patronymic );
		assertEquals( byPassport.Description, after.Description );
		assertEquals( byPassport.Password, after.Password );
		assertEquals( byPassport.BirthDate, after.BirthDate );
		assertEquals( byPassport.PlacementDate.toString(), after.PlacementDate.toString() );

		assertEquals( null, DbLayerInstance.getEmployeeInfoByPassport( "wlegljerhilh" ) );
	}

	@Test
	public void taskCirculation() throws Throwable {
		DbLayer scientistLayer = null, testerLayer = null, securityLayer = null, techsupportLayer = null;

		try {
			DbEmployee scientist = newEmployee();
			scientist.Role = EnterpriseRole.Scientist;
			DbLayerInstance.addEmployee( scientist );
			scientistLayer = new DbLayer( scientist );

			DbEmployee tester = newEmployee();
			tester.Role = EnterpriseRole.Tester;
			DbLayerInstance.addEmployee( tester );
			testerLayer = new DbLayer( tester );

			DbEmployee security = newEmployee();
			security.Role = EnterpriseRole.SecurityMan;
			DbLayerInstance.addEmployee( security );
			securityLayer = new DbLayer( security );

			DbEmployee techsupport = newEmployee();
			techsupport.Role = EnterpriseRole.TechnicalSupport;
			DbLayerInstance.addEmployee( techsupport );
			techsupportLayer = new DbLayer( techsupport );

			DbTask newTask = new DbTask( "Таска, хозяина!" );
			DbMessage taskMessage = new DbMessage( 1, "yo task" );
			taskMessage.Attachments = new ArrayList<DbAttachment>();
			taskMessage.Attachments.add( new DbAttachment( "yo", new byte[100] ) );
			DbLayerInstance.addNewTask( newTask, taskMessage );

			assertEquals( 1, DbLayerInstance.getTotalTasks() );
			assertEquals( 0, DbLayerInstance.getTotalFinishedTasks() );

			assertEquals( 0, DbLayerInstance.getTaskProgressPercentage( newTask.ID ) );
			assertEquals( false, testerLayer.fetchNewTask( tester ) );
			assertEquals( false, securityLayer.fetchNewTask( security ) );
			assertEquals( false, techsupportLayer.fetchNewTask( techsupport ) );
			assertEquals( true, scientistLayer.fetchNewTask( scientist ) );

			// на 50%
			scientistLayer.reportTaskProgress( new DbTaskProgress( new DbMessage( 1, "yo" ), 50, newTask.ID ) );
			assertEquals( 50, DbLayerInstance.getTaskProgressPercentage( newTask.ID ) );
			assertEquals( 1, DbLayerInstance.getAllTasks( false, false, TaskType.VirusCreation ).size() );

			// теперь уходит тестеру
			scientistLayer.reportTaskProgress( new DbTaskProgress( new DbMessage( 1, "yo" ), 100, newTask.ID ) );
			assertEquals( 100, DbLayerInstance.getTaskProgressPercentage( newTask.ID ) );

			assertEquals( scientistLayer.fetchNewTask( scientist ), false );
			assertEquals( securityLayer.fetchNewTask( security ), false );
			assertEquals( techsupportLayer.fetchNewTask( techsupport ), false );
			assertEquals( testerLayer.fetchNewTask( tester ), true );

			// снова уходит к научному сотруднику
			testerLayer.reportTaskProgress( new DbTaskProgress( new DbMessage( 1, "yo" ), 75, newTask.ID ) );
			assertEquals( DbLayerInstance.getTaskProgressPercentage( newTask.ID ), 75 );

			assertEquals( false, testerLayer.fetchNewTask( tester ) );
			assertEquals( false, securityLayer.fetchNewTask( security ) );
			assertEquals( false, techsupportLayer.fetchNewTask( techsupport ) );
			assertEquals( true, scientistLayer.fetchNewTask( scientist ) );

			scientistLayer.reportTaskProgress( new DbTaskProgress( new DbMessage( 1, "yo" ), 100, newTask.ID ) );
			// тестер завершает работу
			testerLayer.reportTaskProgress( new DbTaskProgress( new DbMessage( 1, "yo" ), 100, newTask.ID ) );

			assertEquals( false, testerLayer.fetchNewTask( tester ) );
			assertEquals( false, securityLayer.fetchNewTask( security ) );
			assertEquals( false, techsupportLayer.fetchNewTask( techsupport ) );
			assertEquals( false, scientistLayer.fetchNewTask( scientist ) );

			assertEquals( 0, DbLayerInstance.getTotalTasks() );
			assertEquals( 1, DbLayerInstance.getTotalFinishedTasks() );

			ArrayList<DbTaskProgress> progresses = DbLayerInstance.getTaskProgress( newTask.ID );
			assertEquals( 100, progresses.get( 0 ).Percentage );
			assertEquals( 100, progresses.get( 1 ).Percentage );
			assertEquals( 75, progresses.get( 2 ).Percentage );
			assertEquals( 100, progresses.get( 3 ).Percentage );
			assertEquals( 50, progresses.get( 4 ).Percentage );
			assertEquals( 0, progresses.get( 5 ).Percentage );

			assertEquals( 0, DbLayerInstance.getAllTasks( false, false, TaskType.VirusCreation ).size() );
			assertEquals( 0, DbLayerInstance.getAllTasks( false, true, TaskType.VirusCreation ).size() );
			assertEquals( 1, DbLayerInstance.getAllTasks( true, false, TaskType.VirusCreation ).size() );
			assertEquals( 1, DbLayerInstance.getAllTasks( true, true, TaskType.VirusCreation ).size() );

			assertEquals( 0, DbLayerInstance.getAllTasks( false, false, TaskType.TechsupportRequest ).size() );
			assertEquals( 0, DbLayerInstance.getAllTasks( false, true, TaskType.TechsupportRequest ).size() );
			assertEquals( 0, DbLayerInstance.getAllTasks( true, false, TaskType.TechsupportRequest ).size() );
			assertEquals( 0, DbLayerInstance.getAllTasks( true, true, TaskType.TechsupportRequest ).size() );

			assertEquals( 0, DbLayerInstance.getAllTasks( false, false, TaskType.SecurityRequest ).size() );
			assertEquals( 0, DbLayerInstance.getAllTasks( false, true, TaskType.SecurityRequest ).size() );
			assertEquals( 0, DbLayerInstance.getAllTasks( true, false, TaskType.SecurityRequest ).size() );
			assertEquals( 0, DbLayerInstance.getAllTasks( true, true, TaskType.SecurityRequest ).size() );

			DbLayerInstance.deleteTask( newTask.ID );
		} finally {
			if( scientistLayer == null )
				scientistLayer.close();
			if( testerLayer == null )
				testerLayer.close();
			if( securityLayer == null )
				securityLayer.close();
			if( techsupportLayer == null )
				techsupportLayer.close();
		}
	}
	// <editor-fold defaultstate="collapsed" desc="Trash">                          
	private static long dateToTicks( java.util.Date original ) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime( original );
		return calendar.getTimeInMillis();
	}

	private static Long dateToTicks() {
		return Calendar.getInstance().getTimeInMillis();
	}

	private Timestamp dateTimeNow() {
		Timestamp result = new Timestamp( Calendar.getInstance().getTimeInMillis() );

		//System.out.println(result);

		return result;
	}

	private DbEmployee newEmployee() {
		DbEmployee result = new DbEmployee();

		result.Login = dateToTicks().toString();
		result.Password = dateToTicks().toString();
		result.Name = dateToTicks().toString();
		result.Surname = dateToTicks().toString();
		result.Patronymic = dateToTicks().toString();
		result.Passport = dateToTicks().toString();
		result.Role = EnterpriseRole.Chief;
		result.BirthDate = dateTimeNow();
		result.Photography = new byte[100];

		return result;
	}// </editor-fold>    
}