package com.planimod.core;

import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.junit.Assert;
import org.junit.Test;

import com.patrikdufresne.managers.ManagerException;
import com.patrikdufresne.util.BidiMultiMap;
import com.planimod.core.Employee;
import com.planimod.core.Position;
import com.planimod.core.Qualification;
import com.planimod.core.Section;

/**
 * Test case for the qualification objects.
 * 
 * @author patapouf
 * 
 */
public class QualificationManagerTest extends ManagerTestCase {

	/**
	 * Test adding a qualification.
	 */
	@Test
	public void AddQualification() {
		// Create a new employee.
		Employee e = addEmployee(managers, null);

		// Create a new position.
		Position p = addPosition(managers, null, null, false);

		// Add a new qualification
		Qualification q = new Qualification();
		q.setPosition(p);
		q.setEmployee(e);
		try {
			managers.getQualificationManager().add(Arrays.asList(q));
		} catch (ManagerException e1) {
			fail("Error adding qualification", e1);
		}
	}

	/**
	 * Test adding a qualification object without an employee.
	 */
	@Test
	public void AddQualificationWithoutEmployee() {
		// Create a new position.
		Position p = addPosition(managers, null, null, false);

		// Add a new qualification
		Qualification q = new Qualification();
		q.setPosition(p);
		q.setEmployee(null);
		try {
			managers.getQualificationManager().add(Arrays.asList(q));
			Assert.fail("Error adding qualification without employee should fail.");
		} catch (ManagerException e1) {
			// Expected result
		}
	}

	/**
	 * Test adding a qualification object without a position.
	 */
	@Test
	public void AddQualificationWithoutPosition() {
		// Create a new employee.
		Employee e = addEmployee(managers, null);

		// Add a new qualification
		Qualification q = new Qualification();
		q.setPosition(null);
		q.setEmployee(e);
		try {
			managers.getQualificationManager().add(Arrays.asList(q));
			Assert.fail("Error adding qualification without a position should fail.");
		} catch (ManagerException e1) {
			// Expected result
		}
	}

	/**
	 * Check if the qualification table is working properly.
	 * 
	 * @throws ManagerException
	 */
	@Test
	public void GetQualificationTable() throws ManagerException {

		Employee emp1 = addEmployee(managers, "employee1");
		Employee emp2 = addEmployee(managers, "employee2");
		Employee emp3 = addEmployee(managers, "employee2");
		Section sec1 = addSection(managers, "Section");
		Position pos1 = addPosition(managers, sec1, "pos1", false);
		Position pos2 = addPosition(managers, sec1, "pos2", false);
		Position pos3 = addPosition(managers, sec1, "pos3", false);
		Position pos4 = addPosition(managers, sec1, "pos4", false);
		Position pos5 = addPosition(managers, sec1, "pos5", false);

		addQualification(managers, emp1, pos1, pos2, pos4);
		addQualification(managers, emp2, pos1, pos3);

		BidiMultiMap<Employee, Position> table = managers
				.getQualificationManager().getQualificationTableByPositions(
						Arrays.asList(pos1, pos2, pos3, pos4, pos5));

		assertEquals(5, table.size());
		assertEquals(2, table.keySet().size());
		assertEquals(4, table.valueSet().size());

		assertTrue(table.containsEntry(emp1, pos1));
		assertTrue(table.containsEntry(emp1, pos2));
		assertTrue(table.containsEntry(emp1, pos4));
		assertTrue(table.containsEntry(emp2, pos1));
		assertTrue(table.containsEntry(emp2, pos3));

		assertFalse(table.containsEntry(emp1, pos3));
		assertFalse(table.containsEntry(emp1, pos5));
		assertFalse(table.containsEntry(emp2, pos2));
		assertFalse(table.containsEntry(emp2, pos4));
		assertFalse(table.containsEntry(emp2, pos5));

	}

	/**
	 * Check if the qualification table does not include the archived employee.
	 * 
	 * @throws ManagerException
	 */
	@Test
	public void GetQualificationTable_WithArchivedEmployee()
			throws ManagerException {

		Employee emp1 = addEmployee(managers, "employee1");
		Employee emp2 = addEmployee(managers, "employee2");
		Employee emp3 = addEmployee(managers, "employee2");

		Section sec1 = addSection(managers, "Section");
		Position pos1 = addPosition(managers, sec1, "pos1", false);
		Position pos2 = addPosition(managers, sec1, "pos2", false);
		Position pos3 = addPosition(managers, sec1, "pos3", false);
		Position pos4 = addPosition(managers, sec1, "pos4", false);
		Position pos5 = addPosition(managers, sec1, "pos5", false);

		addQualification(managers, emp1, pos1, pos2, pos4);
		addQualification(managers, emp2, pos1, pos3);
		addQualification(managers, emp3, pos1, pos2);

		// Archive employee 3
		managers.archiveAll(Arrays.asList(emp3));

		// Query qualification
		BidiMultiMap<Employee, Position> table = managers
				.getQualificationManager().getQualificationTableByPositions(
						Arrays.asList(pos1, pos2, pos3, pos4, pos5));

		assertEquals(5, table.size());
		assertEquals(2, table.keySet().size());
		assertEquals(4, table.valueSet().size());

		assertTrue(table.containsEntry(emp1, pos1));
		assertTrue(table.containsEntry(emp1, pos2));
		assertTrue(table.containsEntry(emp1, pos4));
		assertTrue(table.containsEntry(emp2, pos1));
		assertTrue(table.containsEntry(emp2, pos3));

		assertFalse(table.containsEntry(emp1, pos3));
		assertFalse(table.containsEntry(emp1, pos5));
		assertFalse(table.containsEntry(emp2, pos2));
		assertFalse(table.containsEntry(emp2, pos4));
		assertFalse(table.containsEntry(emp2, pos5));

	}

	/**
	 * Check if the qualification table is working properly.
	 * 
	 * @throws ManagerException
	 */
	@Test
	public void GetQualificationTable_WithNoEmployee() throws ManagerException {

		Employee emp1 = addEmployee(managers, "employee1");
		Employee emp2 = addEmployee(managers, "employee2");
		Employee emp3 = addEmployee(managers, "employee2");
		Section sec1 = addSection(managers, "Section");
		Position pos1 = addPosition(managers, sec1, "pos1", false);
		Position pos2 = addPosition(managers, sec1, "pos2", false);
		Position pos3 = addPosition(managers, sec1, "pos3", false);
		Position pos4 = addPosition(managers, sec1, "pos4", false);
		Position pos5 = addPosition(managers, sec1, "pos5", false);

		addQualification(managers, emp1, pos1, pos2, pos4);
		addQualification(managers, emp2, pos1, pos3);

		BidiMultiMap<Employee, Position> table = managers
				.getQualificationManager().getQualificationTableByPositions(
						Collections.EMPTY_SET);
		assertEquals(0, table.size());

	}

	/**
	 * Check if the listByPositionAndEmployee select the right qualification
	 * object.
	 */
	@Test
	public void ListByPositionAndEmployee() {

		Employee emp1 = addEmployee(managers, "employee1");
		Employee emp2 = addEmployee(managers, "employee2");
		Section sec1 = addSection(managers, "Section");
		Position pos1 = addPosition(managers, sec1, "pos1", false);
		Position pos2 = addPosition(managers, sec1, "pos2", false);

		/* Qualification qualif11 = */addQualification(managers, emp1, pos1);
		/* Qualification qualif12 = */addQualification(managers, emp1, pos2);
		Qualification qualif21 = addQualification(managers, emp2, pos1);
		/* Qualification qualif22 = */addQualification(managers, emp2, pos2);

		Qualification q;
		try {
			q = managers.getQualificationManager().listByPositionAndEmployee(
					pos1, emp2);
		} catch (ManagerException e) {
			fail("Error while listing qualifications", e);
			return;
		}

		assertEquals("Wrong element", qualif21, q);

	}

	/**
	 * Test remove a qualification.
	 */
	@Test
	public void RemoveQualification() {
		// Create a new employee.
		Employee e = addEmployee(managers, null);
		// Create a new position.
		Position p = addPosition(managers, null, null, false);
		// Add a new qualification
		Qualification q = new Qualification();
		q.setPosition(p);
		q.setEmployee(e);
		try {
			managers.getQualificationManager().add(Arrays.asList(q));
		} catch (ManagerException e1) {
			fail("Error adding qualification", e1);
		}

		// Keep id for references
		int id = q.getId();
		// Remove qualifications
		try {
			managers.getQualificationManager().remove(Arrays.asList(q));
		} catch (ManagerException e1) {
			fail("Error removing object", e1);
		}

		// Check if removed
		try {
			List<Qualification> list = managers.getQualificationManager()
					.list();

			for (Qualification q1 : list) {
				if (q1.getId() == id) {
					Assert.fail("Object still exists");
				}
			}

		} catch (ManagerException e1) {
			fail("Error listing object", e1);
		}
	}

}
