package com.planimod.core;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.junit.Before;
import org.junit.Test;

import com.planimod.core.ProblemBuilder.Table;

/**
 * Test case for {@link Table}.
 * 
 * <ul>
 * <li>Position #1 is swappable</li>
 * <li>Position #2 is not-swappable</li>
 * </ul>
 * 
 * <h4>Production Events</h4>
 * <table border=1>
 * <tr>
 * <th>Day \ Shift</th>
 * <th>weekDay</th>
 * <th>weekEvening</th>
 * </tr>
 * <tr>
 * <td>mon</td>
 * <td>product#1</td>
 * <td>product#3</td>
 * </tr>
 * <tr>
 * <td>tue</td>
 * <td>product#1</td>
 * <td>product#3</td>
 * </tr>
 * <tr>
 * <td>wed</td>
 * <td>product#1</td>
 * <td></td>
 * </tr>
 * <tr>
 * <td>thu</td>
 * <td>product#2</td>
 * <td>product#3</td>
 * </tr>
 * </table>
 * 
 * <h4>Expected results</h4>
 * <table border=1>
 * <tr>
 * <th>Day \ Shift</th>
 * <th >weekDay</th>
 * <th >weekDayRep</th>
 * </tr>
 * <tr>
 * <td>mon</td>
 * <td>position#1</td>
 * <td>position#2</td>
 * </tr>
 * <tr>
 * <td></td>
 * <td>position#1</td>
 * <td>position#2</td>
 * </tr>
 * <tr>
 * <td></td>
 * <!-- Day -->
 * <td>position#2</td>
 * <td></td>
 * </tr>
 * <tr>
 * <td>tue</td>
 * <td>position#1</td>
 * <td>position#2</td>
 * </tr>
 * <tr>
 * <td></td>
 * <td>position#1</td>
 * <td>position#2</td>
 * </tr>
 * <tr>
 * <td></td>
 * <td>position#2</td>
 * <td></td>
 * </tr>
 * <tr>
 * <td>wed</td>
 * <td>position#1</td>
 * <td></td>
 * </tr>
 * <tr>
 * <td></td>
 * <td>position#1</td>
 * <td></td>
 * </tr>
 * <tr>
 * <td></td>
 * <td>position#2</td>
 * <td></td>
 * </tr>
 * <tr>
 * <td>thu</td>
 * <td>position#2</td>
 * <td>position#2</td>
 * </tr>
 * <tr>
 * <td></td>
 * <td>position#2</td>
 * <td>position#2</td>
 * </tr>
 * <tr>
 * <td></td>
 * <td>position#2</td>
 * <td></td>
 * </tr>
 * </table>
 * 
 * 
 * @author ikus060
 * 
 */
public class TableTest extends ManagerTestCase {

	private static final Integer ONE = Integer.valueOf(1);

	/**
	 * Class holding all the shift event
	 */
	protected ShiftUtils shifts;

	Task[] t;

	List<Task> tasks;

	Table table;

	/**
	 * Create the required shifts.
	 */
	@Before
	public void createTable() {
		shifts = new ShiftUtils();
		shifts.addShifts(managers);
		shifts.addExtendedShifts(managers);

		Position pos1 = addPosition(managers, null, "position#1", false, true);
		Position pos2 = addPosition(managers, null, "position#2", false, false);

		Product pro1 = addProduct(managers, "product1");
		addProductPosition(managers, pro1, pos1, 2);
		addProductPosition(managers, pro1, pos2, 1);

		Product pro2 = addProduct(managers, "product2");
		addProductPosition(managers, pro2, pos2, 3);

		Product pro3 = addProduct(managers, "product3");
		addProductPosition(managers, pro3, pos2, 2);

		ProductionEvent event1 = addProductionEvent(managers, pro1,
				shifts.monDay);
		ProductionEvent event2 = addProductionEvent(managers, pro3,
				shifts.monRep);
		ProductionEvent event3 = addProductionEvent(managers, pro1,
				shifts.tueDay);
		ProductionEvent event4 = addProductionEvent(managers, pro3,
				shifts.tueRep);
		ProductionEvent event5 = addProductionEvent(managers, pro1,
				shifts.wedDay);
		ProductionEvent event7 = addProductionEvent(managers, pro2,
				shifts.thuDay);
		ProductionEvent event8 = addProductionEvent(managers, pro3,
				shifts.thuRep);

		t = new Task[18];
		t[0] = addTask(managers, event1, pos1);
		t[1] = addTask(managers, event1, pos1);
		t[2] = addTask(managers, event1, pos2);
		t[3] = addTask(managers, event2, pos2);
		t[4] = addTask(managers, event2, pos2);
		t[5] = addTask(managers, event3, pos1);
		t[6] = addTask(managers, event3, pos1);
		t[7] = addTask(managers, event3, pos2);
		t[8] = addTask(managers, event4, pos2);
		t[9] = addTask(managers, event4, pos2);
		t[10] = addTask(managers, event5, pos1);
		t[11] = addTask(managers, event5, pos1);
		t[12] = addTask(managers, event5, pos2);
		t[13] = addTask(managers, event7, pos2);
		t[14] = addTask(managers, event7, pos2);
		t[15] = addTask(managers, event7, pos2);
		t[16] = addTask(managers, event8, pos2);
		t[17] = addTask(managers, event8, pos2);

		/*
		 * Create the Table.
		 */
		this.tasks = Arrays.asList(t);
		this.table = Table.create(shifts.getShifts(), tasks);

	}

	/**
	 * test the function {@link Table#teamIntersect(List)}.
	 */
	@Test
	public void testTeams() {
		Collection<Team> teams = table.teams();
		assertEquals(2, teams.size());
		assertTrue(teams.contains(shifts.weekDay));
		assertTrue(teams.contains(shifts.weekDayRep));
	}

	@Test
	public void testGl() {

		// Check size
		assertEquals(8, table.gl().size());

		// Check content of the gl
		List<List<Task>> expectedGls = Arrays
				.asList(Arrays.asList(t[0], t[1], t[2]),
						Arrays.asList(t[0], t[1], t[3], t[4]),
						Arrays.asList(t[5], t[6], t[7]),
						Arrays.asList(t[5], t[6], t[8], t[9]),
						Arrays.asList(t[10], t[11], t[12]),
						Arrays.asList(t[10], t[11]),
						Arrays.asList(t[13], t[14], t[15]),
						Arrays.asList(t[16], t[17]));
		for (List<Task> expectedGl : expectedGls) {
			Integer[] coefs = new Integer[tasks.size()];
			Arrays.fill(coefs, Integer.valueOf(0));
			for (Task t : expectedGl) {
				coefs[tasks.indexOf(t)] = Integer.valueOf(1);
			}

			assertTrue(table.gl().contains(Arrays.asList(coefs)));
		}

	}

	/**
	 * Test the function {@link Table#glIntersectTask(int)} with swappable task.
	 */
	@Test
	public void testGlIntersectTask_withSwappableTask() {

		// Check number of gls intersecting
		Collection<List<Integer>> gls = table.glIntersectTask(tasks
				.indexOf(t[1]));
		assertEquals(2, gls.size());

		// Check content of the gls.
		List<List<Task>> expectedGls = Arrays.asList(
				Arrays.asList(t[0], t[1], t[2]),
				Arrays.asList(t[0], t[1], t[3], t[4]));
		for (List<Task> expectedGl : expectedGls) {
			Integer[] coefs = new Integer[tasks.size()];
			Arrays.fill(coefs, Integer.valueOf(0));
			for (Task t : expectedGl) {
				coefs[tasks.indexOf(t)] = Integer.valueOf(1);
			}

			assertTrue(table.gl().contains(Arrays.asList(coefs)));
		}

	}

	/**
	 * Test the function {@link Table#glIntersectTask(int)}.
	 */
	@Test
	public void testGlIntersectTask_withNotSwappableTask() {

		// Check number of gls intersecting
		Collection<List<Integer>> gls = table.glIntersectTask(tasks
				.indexOf(t[2]));
		assertEquals(1, gls.size());

		// Check content of the gls.
		List<List<Task>> expectedGls = Arrays.asList(Arrays.asList(t[0], t[1],
				t[2]));
		for (List<Task> expectedGl : expectedGls) {
			Integer[] coefs = new Integer[tasks.size()];
			Arrays.fill(coefs, Integer.valueOf(0));
			for (Task t : expectedGl) {
				coefs[tasks.indexOf(t)] = Integer.valueOf(1);
			}
			assertTrue(table.gl().contains(Arrays.asList(coefs)));
		}

	}

	/**
	 * Test the function {@link Table#kInTj(int, int)}
	 */
	@Test
	public void testKInTj() {

		/*
		 * Check team 1
		 */
		for (Task k : Arrays.asList(t[0], t[1], t[2], t[5], t[6], t[7], t[10],
				t[11], t[12], t[13], t[14], t[15])) {
			assertTrue(table.kInTj(tasks.indexOf(k),
					table.indexOf(shifts.weekDay)));
		}
		for (Task k : Arrays.asList(t[3], t[4], t[8], t[9], t[16], t[17])) {
			assertTrue(!table.kInTj(tasks.indexOf(k),
					table.indexOf(shifts.weekDay)));
		}

		/*
		 * Check team2
		 */
		for (Task k : Arrays.asList(t[0], t[1], t[3], t[4], t[5], t[6], t[8],
				t[9], t[10], t[11], t[16], t[17])) {
			assertTrue(table.kInTj(tasks.indexOf(k),
					table.indexOf(shifts.weekDayRep)));
		}
		for (Task k : Arrays.asList(t[2], t[7], t[12], t[13], t[14], t[15])) {
			assertTrue(!table.kInTj(tasks.indexOf(k),
					table.indexOf(shifts.weekDayRep)));
		}

	}

	/**
	 * Test the function {@link Table#kInRTj(int, int)}
	 */
	@Test
	public void testKInRTj() {

		/*
		 * Check team 1
		 */
		for (Task k : Arrays.asList(t[0], t[1], t[2], t[5], t[6], t[7], t[10],
				t[11], t[12], t[13], t[14], t[15])) {
			assertTrue(table.kInRTj(tasks.indexOf(k),
					table.indexOf(shifts.weekDay)));
		}
		for (Task k : Arrays.asList(t[3], t[4], t[8], t[9], t[16], t[17])) {
			assertTrue(!table.kInRTj(tasks.indexOf(k),
					table.indexOf(shifts.weekDay)));
		}

		/*
		 * Check team2
		 */
		for (Task k : Arrays.asList(t[3], t[4], t[8], t[9], t[16], t[17])) {
			assertTrue(table.kInRTj(tasks.indexOf(k),
					table.indexOf(shifts.weekDayRep)));
		}
		for (Task k : Arrays.asList(t[0], t[1], t[2], t[5], t[6], t[7], t[10],
				t[11], t[12], t[13], t[14], t[15])) {
			assertTrue(!table.kInRTj(tasks.indexOf(k),
					table.indexOf(shifts.weekDayRep)));
		}

	}

	/**
	 * Test the tj() function.
	 */
	@Test
	public void testTj() {

		// Check number of Tj
		assertEquals(2, table.tj().size());

		// Check content of Tj
		// Check content of the gls.
		List<List<Task>> expectedTjs = Arrays.asList(
		// Team 1
				Arrays.asList(t[0], t[1], t[2], t[5], t[6], t[7], t[10], t[11],
						t[12], t[13], t[14], t[15]),
				// Team 2
				Arrays.asList(t[0], t[1], t[3], t[4], t[5], t[6], t[8], t[9],
						t[10], t[11], t[16], t[17]));
		for (List<Task> expectedTj : expectedTjs) {
			Integer[] coefs = new Integer[tasks.size()];
			Arrays.fill(coefs, Integer.valueOf(0));
			for (Task t : expectedTj) {
				coefs[tasks.indexOf(t)] = Integer.valueOf(1);
			}

			assertTrue(table.tj().contains(Arrays.asList(coefs)));
		}
	}

	/**
	 * Test the rtj() function.
	 */
	@Test
	public void testRTj() {

		// Check number of Tj
		assertEquals(2, table.rtj().size());

		// Check content of Tj
		// Check content of the gls.
		List<List<Task>> expectedTjs = Arrays.asList(
		// Team 1
				Arrays.asList(t[0], t[1], t[2], t[5], t[6], t[7], t[10],
						t[11], t[12], t[13], t[14], t[15]),
				// Team 2
				Arrays.asList(t[3], t[4], t[8], t[9], t[16], t[17]));
		for (List<Task> expectedTj : expectedTjs) {
			Integer[] coefs = new Integer[tasks.size()];
			Arrays.fill(coefs, Integer.valueOf(0));
			for (Task t : expectedTj) {
				coefs[tasks.indexOf(t)] = Integer.valueOf(1);
			}
			assertTrue(table.rtj().contains(Arrays.asList(coefs)));
		}
	}

}
