/////////////////////////////////////////////////////////////
//                                                         //
// Copyright (c) 2007-2017 by The University of Queensland //
// Centre for Geoscience Computing                         //
// http://earth.uq.edu.au/centre-geoscience-computing      //
//                                                         //
// Primary Business: Brisbane, Queensland, Australia       //
// Licensed under the Open Software License version 3.0    //
// http://www.apache.org/licenses/LICENSE-2.0              //
//                                                         //
/////////////////////////////////////////////////////////////

#include "geometry/Sphere.h"
#include "util/vector3.h"
#include "InsertGenerator2D.h"
#include "HexAggregateInsertGenerator2D.h"
#include "CircMNTable2D.h"
#include "BoxWithLines2D.h"

// --- IO includes ---
#include <iostream>

using std::cout;
using std::cout;
using std::endl;

// -- System includes --
#include <cstdlib>
#include <sys/time.h>
using std::atoi;
using std::atof;

int main(int argc, char** argv)
{
  int ret=0;

  double size=atof(argv[1]);
  int ntry=atoi(argv[2]);
  double rmin_sand=atof(argv[3]);
  double rmin_clay=atof(argv[4]);
  double rmax_clay=atof(argv[5]);
  int outputstyle=atoi(argv[6]);

  double sand_layer_thickness=0.425*size;
  double clay_layer_thickness=0.15*size;
  double center_box_dim=0.05*size;

  CircMNTable2D* T=new CircMNTable2D(Vector3(0.0,0.0,0.0),Vector3(size,size,0.0),2.5,1);
  HexAggregateInsertGenerator2D *G_sand=new HexAggregateInsertGenerator2D(rmin_sand,1.0,ntry,1000,1e-6);
  InsertGenerator2D *G_clay=new InsertGenerator2D(rmin_clay,rmax_clay,ntry,1000,1e-6);

  // seed RNG
  struct timeval tv;
  gettimeofday(&tv,NULL);
  int random_seed=tv.tv_usec;
  srand(random_seed);

  CircMNTable2D::SetOutputStyle(outputstyle);

  // clay layer
  double clay_layer_min=sand_layer_thickness;
  double clay_layer_max=clay_layer_min+clay_layer_thickness;
  double clay_box_min=  clay_layer_min-rmax_clay;
  double clay_box_max=  clay_layer_max+rmax_clay;

  BoxWithLines2D ClayBox(Vector3(clay_layer_min,0.0,0.0),Vector3(clay_layer_max,size,0.0));

  ClayBox.addLine(Line2D(Vector3(clay_layer_min,0.0,0.0),Vector3(clay_layer_max,0.0,0.0))); // left 
  ClayBox.addLine(Line2D(Vector3(clay_layer_max,size,0.0),Vector3(clay_layer_min,size,0.0))); // right
  ClayBox.addLine(Line2D(Vector3(clay_layer_max,size,0.0),Vector3(clay_layer_max,0.0,0.0))); // top
  ClayBox.addLine(Line2D(Vector3(clay_layer_min,size,0.0),Vector3(clay_layer_max,size,0.0))); // right

  G_clay->generatePacking(&ClayBox,T,0,2);

  // little center box
  double cbox_layer_minx=sand_layer_thickness-center_box_dim;
  double cbox_layer_maxx=sand_layer_thickness+clay_layer_thickness+center_box_dim;
  double cbox_layer_miny=0.5*size-center_box_dim;
  double cbox_layer_maxy=0.5*size+center_box_dim;

  BoxWithLines2D CenterBox(Vector3(cbox_layer_minx,cbox_layer_miny,0.0),
			   Vector3(cbox_layer_maxx,cbox_layer_maxy,0.0));

  CenterBox.addLine(Line2D(Vector3(cbox_layer_minx,cbox_layer_miny,0.0),
			   Vector3(cbox_layer_maxx,cbox_layer_miny,0.0))); // left 
  CenterBox.addLine(Line2D(Vector3(cbox_layer_maxx,cbox_layer_maxy,0.0),
			   Vector3(cbox_layer_minx,cbox_layer_maxy,0.0))); // right
  CenterBox.addLine(Line2D(Vector3(cbox_layer_maxx,cbox_layer_maxy,0.0),
			   Vector3(cbox_layer_maxx,cbox_layer_miny,0.0))); // top
  CenterBox.addLine(Line2D(Vector3(cbox_layer_minx,cbox_layer_maxy,0.0),
			   Vector3(cbox_layer_maxx,cbox_layer_maxy,0.0))); // right

  G_clay->generatePacking(&CenterBox,T,0,2);
  

  // --- sand layers
  // layer 1
  double sand_layer_min1=0;
  double sand_layer_max1=sand_layer_thickness;
  double sand_box_min1=sand_layer_min1-rmin_sand;
  double sand_box_max1=sand_layer_max1+rmin_sand;

  BoxWithLines2D SandBox1(Vector3(sand_box_min1,0.0,0.0),Vector3(sand_box_max1,size,0.0));

  SandBox1.addLine(Line2D(Vector3(sand_layer_min1,size,0.0),Vector3(sand_layer_min1,0.0,0.0))); // bottom
  SandBox1.addLine(Line2D(Vector3(sand_layer_min1,0.0,0.0),Vector3(sand_layer_max1,0.0,0.0))); // left 
  SandBox1.addLine(Line2D(Vector3(sand_layer_max1,size,0.0),Vector3(sand_layer_max1,0.0,0.0))); // top
  SandBox1.addLine(Line2D(Vector3(sand_layer_min1,size,0.0),Vector3(sand_layer_max1,size,0.0))); // right
    
  SandBox1.addLine(Line2D(Vector3(0.0,size/2.0,0.0),Vector3(size,size/2.0,0.0))); // middle

  G_sand->generatePacking(&SandBox1,T,0,1);
  
  // layer 2
  double sand_layer_min2=sand_layer_thickness+clay_layer_thickness;
  double sand_layer_max2=size;
  double sand_box_min2=sand_layer_min2-rmin_sand;
  double sand_box_max2=sand_layer_max2+rmin_sand;

  BoxWithLines2D SandBox2(Vector3(sand_box_min2,0.0,0.0),Vector3(sand_box_max2,size,0.0));

  SandBox2.addLine(Line2D(Vector3(sand_layer_min2,size,0.0),Vector3(sand_layer_min2,0.0,0.0))); // bottom
  SandBox2.addLine(Line2D(Vector3(sand_layer_min2,0.0,0.0),Vector3(sand_layer_max2,0.0,0.0))); // left 
  SandBox2.addLine(Line2D(Vector3(sand_layer_max2,size,0.0),Vector3(sand_layer_max2,0.0,0.0))); // top
  SandBox2.addLine(Line2D(Vector3(sand_layer_min2,size,0.0),Vector3(sand_layer_max2,size,0.0))); // right
    
  SandBox2.addLine(Line2D(Vector3(0.0,size/2.0,0.0),Vector3(size,size/2.0,0.0))); // middle

  G_sand->generatePacking(&SandBox2,T,0,1);
  
  T->generateBonds(0,1e-6,0,1,1);
    

  Line2D top_line(Vector3(0.0,size,0.0),Vector3(size,size,0.0));
  Line2D bottom_line(Vector3(0.0,0.0,0.0),Vector3(size,0.0,0.0));

  T->tagParticlesAlongLine(top_line,0.5,4,4,0);
  T->tagParticlesAlongLine(bottom_line,0.5,8,8,0);
  
  cout << *T << endl;

  delete T;
  delete G_sand;
  delete G_clay;
  return ret;
}
