/**
 * Copyright (C) 2019 Patrik Dufresne Service Logiciel <info@patrikdufresne.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package com.planimod.core;

import static com.planimod.core.TimeUtils.time;
import static org.junit.Assert.assertEquals;

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

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

import com.patrikdufresne.managers.ManagerException;
import com.patrikdufresne.util.BidiMultiMap;

/**
 * This class intend to test functionalities related to products.
 * 
 * @author patapouf
 * 
 */
public class ProductManagerTest extends ManagerTestCase {

    public static void assertPP(List<ProductPosition> listPp, Product product, Position position, int number) {
        for (ProductPosition pp : listPp) {
            if (pp.getNumber() == number && pp.getPosition().getName() == position.getName() && pp.getProduct().getName() == product.getName()) {
                return;
            }
        }
        fail("Wrong productPosition", null);
    }

    @Test
    public void testAdd() {
        Product product = new Product();
        try {
            managers.getProductManager().add(Arrays.asList(product));
        } catch (ManagerException e) {
            fail("Error adding object", e);
        }
    }

    @Test
    public void testByShifts() throws ManagerException {

        Team shift = addTeam(managers, "shift");
        Shift monDay = addShift(managers, shift, time("mon 6:00"), time("mon 16:00"));
        Shift tueDay = addShift(managers, shift, time("tue 6:00"), time("tue 16:00"));

        Product product = addProduct(managers, "product");
        Position pos1 = addPosition(managers, null, "pos1", false);
        Position pos2 = addPosition(managers, null, "pos2", false);
        addProductPosition(managers, product, pos1, 2);
        addProductPosition(managers, product, pos2, 1);
        ProductionEvent prod1 = addProductionEvent(managers, product, monDay);
        ProductionEvent prod2 = addProductionEvent(managers, product, tueDay);

        BidiMultiMap<Shift, Entry<Product, Integer>> table = managers.getProductManager().listProductTableByShifts(Arrays.asList(monDay, tueDay));

        assertEquals(2, table.size());

    }

    @Test
    public void testCopy() throws ManagerException {

        Product product = addProduct(managers, "001", "product", "test");
        Position pos1 = addPosition(managers, null, "pos1", false);
        Position pos2 = addPosition(managers, null, "pos2", false);
        ProductPosition pp1 = addProductPosition(managers, product, pos1, 2);
        ProductPosition pp2 = addProductPosition(managers, product, pos2, 1);

        Product newProduct = managers.getProductManager().copy(product);

        assertEquals("Products names not equals", product.getName(), newProduct.getName());
        assertEquals("Products familys not equals", product.getFamily(), newProduct.getFamily());
        assertEquals("Products familys not equals", null, newProduct.getRefId());

        List<ProductPosition> results;
        try {
            results = managers.getProductPositionManager().listByProduct(newProduct);
        } catch (ManagerException e) {
            fail("Error listing product-position", e);
            return;
        }
        assertEquals("Wrong number of element in the list", 2, results.size());
        assertPP(results, product, pos1, 2);
        assertPP(results, product, pos2, 1);
    }

    @Test
    public void testRemove() {
        Product p1 = new Product();
        try {
            managers.getProductManager().add(Arrays.asList(p1));
        } catch (ManagerException e) {
            fail("Error adding object", e);
        }

        int id = p1.getId();

        try {
            managers.getProductManager().remove(Arrays.asList(p1));
        } catch (ManagerException e) {
            fail("Error removing object", e);
        }

        try {
            List<Product> list = managers.getProductManager().list();

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

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

    @Test
    public void testTable() throws ManagerException {

        Team shift = addTeam(managers, "shift");
        Shift monDay = addShift(managers, shift, time("mon 6:00"), time("mon 16:00"));
        Shift tueDay = addShift(managers, shift, time("tue 6:00"), time("tue 16:00"));

        Product product = addProduct(managers, "product");
        Position pos1 = addPosition(managers, null, "pos1", false);
        Position pos2 = addPosition(managers, null, "pos2", false);
        addProductPosition(managers, product, pos1, 2);
        addProductPosition(managers, product, pos2, 1);
        ProductionEvent prod1 = addProductionEvent(managers, product, monDay);
        ProductionEvent prod2 = addProductionEvent(managers, product, tueDay);

        Collection<ProductEntry> table = managers.getProductManager().listProductTable(Arrays.asList(product));

        assertEquals(1, table.size());

    }

    @Test
    public void testUpdate() {
        Product p1 = new Product();
        try {
            managers.getProductManager().add(Arrays.asList(p1));
        } catch (ManagerException e) {
            fail("Error adding object", e);
        }

        p1.setName("test1");
        p1.setRefId("refid1");

        // Save modification
        try {
            managers.getProductManager().update(Arrays.asList(p1));
        } catch (ManagerException e) {
            fail("Error updating object", e);
        }

        // Reload product
        Product p2;
        try {
            p2 = managers.getProductManager().get(p1.getId());
        } catch (ManagerException e) {
            fail("Error loading object", e);
            return;
        }

        Assert.assertEquals("Objects not equals", p1.getName(), p2.getName());
        Assert.assertEquals("Objects not equals", p1.getRefId(), p2.getRefId());
    }

}
