#include "playTest.h"

#include <iostream>
#include <cstdlib>
#include <ctime>

#include "automaton/determinize/Determinize.h"
#include "automaton/generate/RandomAutomatonFactory.h"
#include "automaton/simplify/Minimize.h"
#include "automaton/simplify/Normalize.h"
#include "automaton/simplify/Trim.h"
#include "automaton/simplify/EpsilonRemover.h"

#define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y))

#define TEST_ITERATIONS 100
#define TEST_AUTOMATON_STATES_MAX 18
#define TEST_AUTOMATON_DENSITY_MAX 2.5
#define TEST_AUTOMATON_ALPHABET_MAX 4

CPPUNIT_TEST_SUITE_REGISTRATION( playTest );

void playTest::setUp()
{
    srand(time(NULL));
}

void playTest::tearDown(){}

automaton::NFA playTest::randomNFA(void) const
{
    return automaton::generate::RandomAutomatonFactory::generateNFA(
            rand() % TEST_AUTOMATON_STATES_MAX + 1,
            rand() % TEST_AUTOMATON_ALPHABET_MAX + 1,
            static_cast<double> (rand()) / (static_cast<double> (RAND_MAX/TEST_AUTOMATON_DENSITY_MAX))
            );
}

automaton::DFA playTest::mDFA(const automaton::NFA& automaton) const
{
    automaton::NFA nfa = automaton::simplify::EpsilonRemover::remove(automaton);
    nfa = automaton::simplify::Trim::trim(nfa);
    automaton::DFA dfa = automaton::determinize::Determinize::determinize(nfa);
    dfa = automaton::simplify::Trim::trim(dfa);
    dfa = automaton::simplify::Minimize::minimize(dfa);
    dfa = automaton::simplify::Normalize::normalize(dfa);
    return dfa;
}

/**
 * Test case 1:
 *  - covers: FA -> LRG, FA -> RRG, RRG <-> LRG, RRG -> FA, LRG -> FA
 *  a. FA -> RRG -> LRG -> FA
 *  b. FA -> LRG -> RRG -> FA
 */
void playTest::testPlay1()
{
    for(int i = 0; i < TEST_ITERATIONS; i++)
        this->case1a();
    for(int i = 0; i < TEST_ITERATIONS; i++)
        this->case1b();
}

void playTest::case1a(void) const
{
    /*
    fa2rg::FAtoRRGConverter fa2rrg;
    rg2rg::RightToLeftRegularGrammar rrg2lrg;
    rg2fa::LRGtoFAConverter lrg2fa;

    automaton::NFA a1 = this->randomNFA();
    automaton::NFA a2 = lrg2fa.convert(rrg2lrg.convert(fa2rrg.convert(a1)));

    CPPUNIT_ASSERT(this->mDFA(a1) == this->mDFA(a2));
    */
}

void playTest::case1b(void) const
{
    /*
    fa2rg::FAtoLRGConverter fa2lrg;
    rg2rg::LeftToRightRegularGrammar lrg2rrg;
    rg2fa::RRGtoFAConverter rrg2fa;

    automaton::NFA a1 = this->randomNFA();
    automaton::NFA a2 = rrg2fa.convert(lrg2rrg.convert(fa2lrg.convert(a1)));

    CPPUNIT_ASSERT(this->mDFA(a1) == this->mDFA(a2));
    */
}