#include <iostream>
#include <fstream>
#include <cstring>
#include <vector>

#include <dirent.h>

#include "test/Test.h"
#include "test/TestLogger.h"
#include "tokenizer/Token.h"
#include "tokenizer/Tokenizer.h"
    
static unsigned int done = 0;
static unsigned int tests = 0;
static TestLogger logger;

static void forEachFile(const std::string& path, const std::string& ending, void (*f) (const std::string&, const std::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)
                {
                    std::string pathInputFile = path + "/" + entry->d_name;
                    std::string pathOutputFile = pathInputFile + ending;
                    f(pathInputFile, pathOutputFile);
                }
            }
        }
        closedir(dir);
    }
}

static void testTokenizer(const char* path)
{
    done = 0;
    tests = 0;
    forEachFile(path, ".tout", [](const std::string& input, const std::string& output)
    {
        tests++;
        
        std::ifstream iStream;
        iStream.open(input);
        
        std::ifstream oStream;
        oStream.open(output);
        
        if(!iStream.good() || !oStream.good())
        {
            return;
        }
        
        std::vector<Token> tokens;
        try
        {
            Tokenizer::tokenize(tokens, iStream);
        }
        catch(std::exception& ex)
        {
            return;
        }
        
        logger.reset();
        for(Token& token : tokens)
        {
            std::string s = token.toString();
            logger.print(&s);
        }
        
        if(logger.check(input, oStream))
        {
            done++;
        }
    });
    std::cout << done << " / " << tests << " tokenizer tests succeeded" << std::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::start(const char* path)
{
    testTokenizer(path);
    //testCompiler();
    //testOutput();
}