#include "geometry.hpp"

double inf = numeric_limits<double>::infinity();

Geometry::Geometry(){
  lX=0;
  nX=0;
  dX=0;
  hsoil=nullptr;
  dhsoil=nullptr;
  hbot=nullptr;
  dhbot=nullptr;
  nZ=nullptr;
  dZ=nullptr;
  Z=nullptr;
}

void
Geometry::initZ(double dZ_avg,bool init){
  if(init){
    nZ=new size_t[nX];
    dZ=new double[nX];
    Z=new double*[nX];
  }
  for(size_t k=0;k<nX;++k){
    double d=hsoil[k]-hbot[k];
    size_t n=d/dZ_avg;
    double dz=d/n;
    dZ[k]=dz;
    nZ[k]=n+1;
    if(init) Z[k]=new double[n+1];
    for(size_t j=0;j<n+1;++j){
      Z[k][j]=factor*(hbot[k]+j*dz);
    }
  }
}

void
Geometry::initDefault(){
  lX=10;
  nX=100;
  nX_max=nmax_Qt;
  dX=lX/(nX-1);
  hsoil=new double[nmax_Qt];
  dhsoil=new double[nmax_Qt];
  hbot=new double[nmax_Qt];
  dhbot=new double[nmax_Qt];
  nZ=new size_t[nmax_Qt];
  dZ=new double[nmax_Qt];
  Z=new double*[nmax_Qt];
  for(size_t i=0;i<nmax_Qt;++i){
    Z[i]=new double[nmax_Qt];
  }
  for(size_t i=0;i<nX;++i){
    hsoil[i]=0.8;
    hbot[i]=0.2;
    dhsoil[i]=0;
    dhbot[i]=0;
  }
  depth=5;
  nZ_max=100;
  factor=5/0.6;
  initZ(depth/nZ_max,false);
}

void
Geometry::update(double _lX,size_t _nX,double _depth,size_t _nZ_max,Spline& Ssoil,Spline& Sbot){
  lX=_lX;
  depth=_depth;
  nX=_nX;
  nZ_max=_nZ_max;
  dX=lX/(nX-1);
  double hs_max=-inf,hb_min=inf;
  double v;
  for(size_t k=0;k<nX;++k){
    double x=k*dX/lX;
    v=hsoil[k]=Ssoil(x);
    hs_max=max(v,hs_max);
    dhsoil[k]=Ssoil.derivate(x);
    v=hbot[k]=Sbot(x);
    hb_min=min(v,hb_min);
    dhbot[k]=Sbot.derivate(x);
  }
  double dZ_avg=(hs_max-hb_min)/_nZ_max;
  factor=depth/(hs_max-hb_min);
  initZ(dZ_avg,false);
}

Geometry::~Geometry(){
  if(hsoil!=nullptr){
    delete[] hsoil;
    delete[] dhsoil;
    delete[] hbot;
    delete[] dhbot;
    delete[] dZ;
    delete[] nZ;
    for(size_t i=0;i<nX_max;++i){
      delete[] Z[i];
    }
    delete[] Z;

  }


}
