#include "ZenLib/Conf.cpp"
#include "ZenLib/Dir.cpp"
#include "ZenLib/File.cpp"
#include "ZenLib/FileName.cpp"
#include "ZenLib/int128s.cpp"
#include "ZenLib/int128u.cpp"
#include "ZenLib/Utils.cpp"
#include "ZenLib/Ztring.cpp"
#include "ZenLib/ZtringList.cpp"
#include "ZenLib/OS_Utils.cpp"
#include <cstdlib>
using namespace ZenLib;
using namespace std;

#include <queue>
typedef std::basic_string<char>        String;
std::queue<String> ToParse;


//Stats file
//Per column: FileName;Status;ErrorCount\n
File Valgrind_Stats;
//Buffer for Valgrind_tmp
const size_t Valgrind_tmp_Buffer_Size=1024*1024;
int8u Valgrind_tmp_Buffer[Valgrind_tmp_Buffer_Size];
//mediainfo emplacement
Ztring MediaInfo;
//Killed
bool Killed;

void Valgrind(const Ztring &FileName)
{
    //Saving info before test
    Valgrind_Stats.Open("Valgrind_stats.txt", File::Access_Write_Append);
    Valgrind_Stats.Write(FileName);
    Valgrind_Stats.Close();

    //Processing
    system(("valgrind --max-stackframe=5041008 --tool=memcheck --show-reachable=yes --track-fds=yes --leak-check=full --track-origins=yes --log-file=Valgrind.tmp -v "+MediaInfo+" \""+FileName+"\"").c_str());

    //Saving info after test
    Valgrind_Stats.Open("Valgrind_stats.txt", File::Access_Write_Append);
    Valgrind_Stats.Write(";OK");

    //Retrieving stats
    File Valgrind_tmp;
    Valgrind_tmp.Open("Valgrind.tmp");
    size_t Valgrind_tmp_Buffer_Offset=0;
    while(Valgrind_tmp_Buffer_Offset<Valgrind_tmp_Buffer_Size)
    {
        size_t BytesRead=Valgrind_tmp.Read(Valgrind_tmp_Buffer+Valgrind_tmp_Buffer_Offset, Valgrind_tmp_Buffer_Size-Valgrind_tmp_Buffer_Offset);
        if (BytesRead==0)
            break; //Read is finished
        Valgrind_tmp_Buffer_Offset+=BytesRead;
    }
    Ztring Valgrind_tmp_String; Valgrind_tmp_String.From_Local((const char*)Valgrind_tmp_Buffer, Valgrind_tmp_Buffer_Offset);

    //Testing if killed
    if (Valgrind_tmp_String.find("Process terminating with default action")!=string::npos)
    {
        Valgrind_Stats.Write(";Killed");
        Killed=true;
        return;
    }

    //Filling stats
    else if (Valgrind_tmp_String.find("ERROR SUMMARY: 0 errors from 0 contexts")==string::npos)
    {
        Valgrind_Stats.Write(";Error");
        Ztring NameDots=FileName;
        NameDots.FindAndReplace("/", "x", 0, Ztring_Recursive);
        NameDots.FindAndReplace(".", "x", 0, Ztring_Recursive);
        system(("cp Valgrind.tmp Valgrind.PerFile."+NameDots).c_str());
    }    
    
    //EOL
    Valgrind_Stats.Write("\n");
    Valgrind_Stats.Close();
}

int main(int argc, char* argv[])
{
	//Testing input
    if (argc<3)
    {
        std::cout<<"Usage: ./Valgrind MediaInfo_FileName Directory/files"<<std::endl;
        return 1;
    }

    //Configuring
    Valgrind_Stats.Create("Valgrind_stats.txt", true);
    Valgrind_Stats.Write("FileName;Passed;Error\n");
    Valgrind_Stats.Close();
    MediaInfo=argv[1];
    Killed=false;

    //Processing
    for (int argv_Pos=2; argv_Pos<argc; argv_Pos++)
    {
        //Geting all filenames
        ZtringList FileNames=Dir::GetAllFileNames(Ztring().From_Local(argv[argv_Pos]));
        
        for (size_t FileNames_Pos=0; FileNames_Pos<FileNames.size(); FileNames_Pos++)
        {
            std::cout<<"***"<<std::endl;
            std::cout<<FileNames[FileNames_Pos]<<std::endl;
            Valgrind(FileNames[FileNames_Pos]);

            if (Killed)
                return 1;
        }
    }

    return 0;
}

