package de.planetswebdesign.fsm.hopcroftminimizer;

import de.planetswebdesign.fsm.DefaultImpl.DefaultGuard;
import de.planetswebdesign.fsm.DefaultImpl.DefaultInputEvent;
import de.planetswebdesign.fsm.State;
import de.planetswebdesign.fsm.acceptor.AcceptorFSM;
import java.util.ArrayList;
import java.util.Collection;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 *
 * @author Sebastian Prehn
 */
public class MinimizerTest {

    public MinimizerTest() {
    }

    @BeforeClass
    public static void setUpClass() throws Exception {
    }

    @AfterClass
    public static void tearDownClass() throws Exception {
    }

    @Before
    public void setUp() {
    }

    @After
    public void tearDown() {
    }

    /**
     * Test of partition method, of class Minimizer.
     */
    @Test
    public void partition() {
        AcceptorFSM fsm = new AcceptorFSM();
        State s0 = fsm.createState();
        State s1 = fsm.createState();
        State s2 = fsm.createState();
        State s3 = fsm.createState();
        s0.setFinal(true);
        s2.setFinal(true);
        DefaultGuard t = fsm.createGuard();
        t.setEvent(new DefaultInputEvent());
        DefaultGuard h = fsm.createGuard();
        h.setEvent(new DefaultInputEvent());
        fsm.createTransition(s0, s0, t);
        fsm.createTransition(s0, s1, h);
        fsm.createTransition(s1, s1, t);
        fsm.createTransition(s1, s2, h);
        fsm.createTransition(s2, s2, t);
        fsm.createTransition(s2, s3, h);
        fsm.createTransition(s3, s3, t);
        fsm.createTransition(s3, s0, h);
        Collection finalStates = new ArrayList(2);
        finalStates.add(s0);
        finalStates.add(s2);
        Collection nonfinalStates = new ArrayList(2);
        nonfinalStates.add(s1);
        nonfinalStates.add(s3);
        Collection<Block> expResult = null;
        Collection<Block> result = Minimizer.partition(fsm);
        assertTrue(result.size() == 2);
        for (Block b : result) {
            assertTrue(b.size() == 2);
            assertTrue(b.containsAll(finalStates) || b.containsAll(nonfinalStates));
        }
    }

    @Test
    public void partition2() {



        AcceptorFSM fsm = new AcceptorFSM();

        DefaultGuard[] guards = new DefaultGuard[3];

        guards[0] = fsm.createGuard();
        guards[0].setEvent(new DefaultInputEvent());
        guards[1] = fsm.createGuard();
        guards[1].setEvent(new DefaultInputEvent());
        guards[2] = fsm.createGuard();
        guards[2].setEvent(new DefaultInputEvent());

        Collection<State> e0 = new ArrayList<State>(1);
        Collection<State> e1 = new ArrayList<State>(3);
        Collection<State> e2 = new ArrayList<State>(9);
        Collection<State> e3 = new ArrayList<State>(27);

        int numStates = 0;

        State level0 = fsm.createState();
        numStates++;
        e0.add(level0);
        level0.setLabel("0");
        for (int i = 0; i < 3; i++) {
            State level1 = fsm.createState();
            numStates++;
            e1.add(level1);
            level1.setLabel(level0.getLabel() + i);
            fsm.createTransition(level0, level1, guards[i]);
            for (int ii = 0; ii < 3; ii++) {
                State level2 = fsm.createState();
                numStates++;
                e2.add(level2);
                level2.setLabel(level1.getLabel() + ii);
                fsm.createTransition(level1, level2, guards[ii]);
                for (int iii = 0; iii < 3; iii++) {
                    State level3 = fsm.createState();
                    numStates++;
                    e3.add(level3);
                    level3.setLabel(level2.getLabel() + iii);
                    level3.setFinal(true);
                    fsm.createTransition(level2, level3, guards[iii]);
                }
            }
        }

        Collection<Block> blocks = Minimizer.partition(fsm);

        for (Block block : blocks) {
            numStates -= block.size();
        }
        assertTrue(numStates == 0);

        boolean found = false;
        for (Block block : blocks) {
            if (block.size() == e0.size() && block.containsAll(e0)) {
                found = true;
            }
        }
        assertTrue(found);

        found = false;
        for (Block block : blocks) {

            if (block.size() == e1.size() && block.containsAll(e1)) {
                found = true;
            }
        }
        assertTrue(found);

        found = false;
        for (Block block : blocks) {
            
            if (block.size() == e2.size() && block.containsAll(e2)) {
                found = true;
            }
        }
        assertTrue(found);

        found = false;
        for (Block block : blocks) {
            System.out.println(block); // print result of computation
            if (block.size() == e3.size() && block.containsAll(e3)) {
                found = true;
            }
        }
        assertTrue(found);


    }
}
