// Vorosweep - Copyright (C) 2010-2014 T. Mouton
//
// See the LICENSE.txt file for license information. Please report all
// bugs and problems to <thibaud.mouton@gmail.com>.

#include "vorosweep.h"
#include "database.h"
#include <fenv.h>
#include <vector>
#include "gtest/gtest.h"

using ::testing::TestWithParam;
using ::testing::Values;
using ::testing::internal::ParamGenerator;
using ::testing::ValuesIn;

using namespace vorosweep;

int md5check ( vector<string> row )
{
  char command[100];
  sprintf ( command, "md5sum testcase/%s.dat", row.at ( 0 ).c_str() );

  FILE *fp;
  char value[100];
  /* Open the command for reading. */
  fp = popen ( command, "r" );
  if ( fp == NULL )
  {
    printf ( "Failed to run command\n" );
    exit ( 1 );
  }

  char file[100];
  char sum[100];
  /* Read the output a line at a time - output it. */
//    while (fgets(value, 100-1, fp) != NULL)
  if ( fgets ( value, 100-1, fp ) != NULL )
  {
    sscanf ( value, "%s %s", sum, file );
//     printf ( "file : %s --> sum = %s\n", file, sum );
  }
  else
  {
    printf ( "Problem during checking md5sum of file !!\n" );
    exit ( 1 );
  }

  /* close */
  pclose ( fp );

  if ( strcmp ( row.at ( 0 ).c_str(), sum ) != 0 )
  {
    printf ( "file %s has changed --> skipping\n", file );
    return 0;
  }

//   printf ( "file %s is correct\n", file );
  return 1;
}

ParamGenerator<std::pair<string, string> > generate()
{
  std::vector<std::pair<string, string> > values;

  Database *db;
  db = new Database ( "testcase/database.sqlite" );

//   db->query("CREATE TABLE testcase (file varchar(32), checksum varchar(16));");
//   db->query("INSERT INTO testcase VALUES('e4ef87f3a057dde2678ae1d268ed0901', '971bb595751c04fd');");
//   db->query("INSERT INTO testcase VALUES('cc9dfe078fc50a75b3a3e3f40e7da82a', '49f400092278bb92');");
//   db->query("DELETE INTO testcase WHERE file='fbc52b09c0ec974ddbc38643dad2feec'");
  
  vector<vector<string> > result = db->query ( "SELECT file, checksum FROM testcase;" );

  for ( vector<vector<string> >::iterator it = result.begin(); it < result.end(); ++it )
  {
    vector<string> row = *it;
//    printf("Values: (file= %s, checksum= %s\n", row.at(0).c_str(), row.at(1).c_str());
    char filename[100];
    sprintf ( filename, "testcase/%s.dat", row.at ( 0 ).c_str() );

    if ( md5check ( row ) )
    {
      values.push_back ( std::pair<string, string> ( row.at ( 0 ).c_str(), row.at ( 1 ).c_str() ) );
    }
  }
  
  db->close();
  
  ParamGenerator<std::pair<string, string> > gen = ValuesIn ( values.begin(), values.end() );
  return gen;
}

class VorosweepTest : public ::testing::TestWithParam<std::pair<string, string> >
{
  protected:
    // You should make the members protected s.t. they can be
    // accessed from sub-classes.

    // Declares the variables your tests want to use.
    string md5sum;
    string checksum;
    Graph *mg;

    // virtual void SetUp() will be called before each test is run.  You
    // should define it if you need to initialize the varaibles.
    // Otherwise, this can be skipped.
    virtual void SetUp()
    {
      md5sum = GetParam().first;
      checksum = GetParam().second;
//       printf("setup --> %s %s\n", md5sum.c_str(), checksum.c_str());
    }
// virtual void TearDown() will be called after each test is run.
// You should define it if there is cleanup work to do.  Otherwise,
// you don't have to provide it.
//
    virtual void TearDown()
    {
      tprintf ( "Deleting structures ...\n" );
      delete mg;
    }

//   // A helper function for testing vorosweep.
    void VorosweepTester ( )
    {
      char filename[100];
      sprintf ( filename, "testcase/%s.dat", md5sum.c_str() );
      mg = new Graph;
      mg->read_input_file ( filename );

      feenableexcept ( FE_UNDERFLOW | FE_DIVBYZERO );

      mg->default_borders();
      mg->init();
      mg->run(); 
      mg->finalize();
      mg->export_vtk ( "vorosweep" );
      mg->export_vector_graphic ( "vorosweep", false, true, true, 20  );
    }
    
//     //   // A helper function for testing vorosweep.
//     void VorosweepTesterWithWalls ( )
//     {
//       char filename[100];
//       sprintf ( filename, "testcase/%s.dat", md5sum.c_str() );
//       mg = new Graph;
//       mg->read_input_file ( filename );
// 
//       feenableexcept ( FE_UNDERFLOW | FE_DIVBYZERO );
// 
//       mg->init();
//       mg->run();      
//       mg->export_vtk ( "vorosweep" );
// //       mg->export_vector_graphic ( "vorosweep", 0, 1, 1, 20 );
//     }
};

ParamGenerator<std::pair<string, string> > gen = generate();

INSTANTIATE_TEST_CASE_P (
  GeneralCheck,
  VorosweepTest,
  gen );


TEST_P ( VorosweepTest, runAll )
{
  VorosweepTester ( );
  EXPECT_EQ ( GetParam().second, mg->get_checksum() );
}

int main ( int argc, char **argv )
{
  ::testing::InitGoogleTest ( &argc, argv );
  return RUN_ALL_TESTS();
}
