#include "Test.h"
#include <dirent.h>
#include <cstring>
#include "../tokenizer/Tokenizer.h"

int Test::done = 0;
int Test::tests = 0;
TestLogger Test::logger;

void Test::test()
{
    testTokenizer();
    //testCompiler();
    //testOutput();
}

void Test::testTokenizer()
{
    done = 0;
    tests = 0;
    forEachFile("test", ".tout", [](const string& input, const string& output)
    {
        tests++;
        
        vector<unique_ptr<istream>> streams;
        streams.push_back(unique_ptr<istream>(new fstream));
        ((fstream*) streams[0].get())->open(input);
        
        fstream oStream;
        oStream.open(output);
        
        if(!streams[0]->good() || !oStream.good())
        {
            return;
        }
        
        Tokenizer tokenizer;
        vector<unique_ptr<Token>> tokens;
        
        try
        {
            tokenizer.tokenize(tokens, streams);
        }
        catch(exception& ex)
        {
            return;
        }
        
        logger.reset();
        for(unsigned int i = 0; i < tokens.size(); i++)
        {
            string s = tokens[i]->toString();
            logger.print(&s);
        }
        
        if(logger.check(input, oStream))
        {
            done++;
        }
    });
    cout << done << " / " << tests << " tokenizer tests succeeded" << endl;
}

void Test::testCompiler()
{
    /*
     done = 0;
        tests = 0; 
        final Compiler c = new Compiler();
        forEachFile(new File("./test"), ".cout", (inFile, checkFile) -> 
        {
            tests++;
            try
            {
                try(FileInputStream in = new FileInputStream(inFile))
                {
                    Tokenizer tokenizer = new Tokenizer();
                    LOGGER.reset();
                    Instruction[] instr = c.compile(tokenizer.tokenize(in), 
                            new HashMap<>(), new HashMap<>(), new HashMap<>(), 
                            new HashMap<>());
                    for(Instruction i : instr)
                    {
                        LOGGER.print(i.toString(), null, null, null, null, -1);
                    }
                    if(LOGGER.check(checkFile))
                    {
                        done++;
                    }
                }
            }
            catch(Exception ex)
            {
                System.out.println("_________________________________________");
                System.out.println(inFile + " failed:");
                System.out.println(ex.getMessage());
                ex.printStackTrace();
            }
        });
        System.out.println(String.format("%d / %d compiler tests succeeded", done, tests));
     
     */
}

void Test::testOutput()
{
    /*
     
     done = 0;
        tests = 0;  
        forEachFile(new File("./test"), ".out", (inFile, checkFile) -> 
        {
            tests++;
                
            LOGGER.reset();
            
            Script sc = new Script(PARSER, null, null, inFile.getName(), inFile.getPath());
            sc.run();

            if(LOGGER.check(checkFile))
            {
                done++;
            }
        });
        System.out.println(String.format("%d / %d output tests succeeded", done, tests));
     
     */
}

void Test::forEachFile(const string& path, const string& ending, void (*f) (const string&, const string&))
{
    DIR* dir;
    dir = opendir(path.c_str());
    struct dirent* entry = nullptr;
    if(dir != nullptr)
    {
        while((entry = readdir(dir)) != nullptr)
        {
            if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
            {
                continue;
            }
            if(entry->d_type == DT_DIR) // Folder
            {
                forEachFile(path + "/" + entry->d_name, ending, f);
            }
            else if(entry->d_type == DT_REG) // File
            {
                if(strchr(entry->d_name, '.') == nullptr)
                {
                    string pathInputFile = path + "/" + entry->d_name;
                    string pathOutputFile = pathInputFile + ending;
                    f(pathInputFile, pathOutputFile);
                }
            }
        }
        closedir(dir);
    }
}