#include "lest.hpp"
#include <math.h>
#include "testutils.h"
using namespace std;

#include "catima/catima.h"   
#include "catima/storage.h"   

using catima::approx;
const lest::test specification[] =
{
    
    CASE("datapoints equal operator"){
      catima::Projectile p{12,6,6,1000};
      catima::Material water({
                {1,1,2},
                {16,8,1}
                });
                
      catima::Material graphite({
                {12,6,1}
                });
      catima::Config c2;
      c2.z_effective = catima::z_eff_type::winger;
      catima::DataPoint a(p,water);
      catima::DataPoint b(p,water);
      catima::DataPoint c(p,graphite);
      catima::DataPoint d;
      catima::DataPoint e(p,water,c2);
      d = c;
      EXPECT(a == b);
      EXPECT(!(a==c));
      EXPECT(d == c);
      EXPECT(!(d==b));
      EXPECT(!(e==a));
      d = a;
      EXPECT(!(d==c));
      EXPECT(d==b);
      
    },
    
    CASE("storage add"){
      catima::Projectile p{12,6,6,1000};
      catima::Material water({
                {1,1,2},
                {16,8,1}
                });
                
      catima::Material graphite({
                {12,6,1}
                });
      
      catima::Config c1;
      c1.z_effective = catima::z_eff_type::global;
      
      catima::_storage.Reset();
      EXPECT(catima::_storage.get_index()==0);
      
      catima::_storage.Add(p,water);
      auto dp = catima::_storage.Get(0);
      EXPECT(catima::_storage.get_index()==1);
      EXPECT(dp.p.A==12);
      EXPECT(dp.m.ncomponents()==2);
      catima::_storage.Add(p,water);
      auto dp2 = catima::_storage.Get(1);
      EXPECT(catima::_storage.get_index()==1);
      EXPECT(dp2.p.A==0);
      EXPECT(dp2.m.ncomponents()==0);
      
      catima::_storage.Add(p,graphite);
      auto dp3 = catima::_storage.Get(1);
      EXPECT(catima::_storage.get_index()==2);
      EXPECT(dp3.p.A==12);
      EXPECT(dp3.m.ncomponents()==1);
      
      catima::_storage.Add(p,graphite);
      EXPECT(catima::_storage.get_index()==2);
      
      catima::_storage.Add(p,graphite, c1);
      EXPECT(catima::_storage.get_index()==3);
      
      catima::_storage.Add(p,graphite);
      EXPECT(catima::_storage.get_index()==3);
      c1.z_effective = catima::z_eff_type::atima14;
      catima::_storage.Add(p,graphite ,c1);
      EXPECT(catima::_storage.get_index()==4);
      
    },
    CASE("test maximum storage"){ // this test assumes max storage = 50
      catima::Projectile p{12,6,6,1000};
      catima::Material water({
                {1,1,2},
                {16,8,1}
                });
                
      catima::Material graphite({
                {12,6,1}
                });
      catima::_storage.Reset();      
      EXPECT(catima::_storage.get_index()==0);
      for(int i=1;i<51;i++){
          catima::Projectile p1{2*i,i,i,1000};
          catima::_storage.Add(p1,graphite);
          EXPECT(catima::_storage.get_index()==i);
          EXPECT(catima::_storage.GetN()==50);
      }
      EXPECT(catima::_storage.get_index()==50);
      for(int i=1;i<49;i++){
          catima::Projectile p1{2*i,i,i,1000};
          catima::_storage.Add(p1,water);
          EXPECT(catima::_storage.get_index()==i);
          EXPECT(catima::_storage.GetN()==50);
      }

  
    },
    CASE("energy table"){
      double step = (catima::logEmax - catima::logEmin)/(catima::max_datapoints-1);
      EXPECT(catima::energy_table.step==step);
      EXPECT(catima::energy_table.values[0]==exp(M_LN10*(catima::logEmin)));
      EXPECT(catima::energy_table.values[1]==exp(M_LN10*(catima::logEmin+step)));
      EXPECT(catima::energy_table.values[catima::max_datapoints-1]==approx(exp(M_LN10*(catima::logEmax))).epsilon(1e-6));
    }
};

int main( int argc, char * argv[] )
{
    return lest::run( specification, argc, argv );
}