//---------------------------------------------------------------------------

#include <vcl.h>
#include <stdio.h>



#include "Viewer.h"
#include "Display.h"
#include "Settings.h"
#include "Structures.h"
#include "WRL.h"
#include <math.h>
#pragma hdrstop


//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TFrmMonitor *FrmMonitor;
void Callback(TProcess *p, int step, int action);

//---------------------------------------------------------------------------
__fastcall TFrmMonitor::TFrmMonitor(TComponent* Owner)
  : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void Callback(TProcess *p, int step, int action){
  char buffer[255];
  char buffer2[255];



//FrmMonitor->Log->Lines->Add();
  switch(step){
    case S_INIT:
      switch(action){
        case A_IN_START:
          FrmMonitor->Log->Lines->Add("Initializing ...");
          break;
        case A_IN_END:
          FrmMonitor->Log->Lines->Add("OK - Done.");
          break;
      }
      break;
    case S_MC:
      if(FrmMonitor->chkNoMCLog->Checked) return;
      FrmMonitor->Caption = IntToStr(FrmMonitor->p.Stats.Cubes.Count);
      switch(action){
        case A_MC_FIRST_CUBE:
          if(p->ActiveCubes == NULL){
            FrmMonitor->Log->Lines->Add("ERR - First cube not found");
          }
          else {
            sprintf(buffer, "First cube at [\t%i,\t%i,\t%i ]" ,
                       p->ActiveCubes->Cube.Index.I,
                       p->ActiveCubes->Cube.Index.J,
                       p->ActiveCubes->Cube.Index.K);
            FrmMonitor->Log->Lines->Add(buffer);
          }
//........found?



          break;
        case A_MC_EVALUATE:
          sprintf(buffer, "Evaluating cube at [\t%i,\t%i,\t%i ] Configuration [%i]" ,
                       p->ActiveCube->Cube.Index.I,
                       p->ActiveCube->Cube.Index.J,
                       p->ActiveCube->Cube.Index.K,
                       p->ActiveCube->Cube.Configuration);
          FrmMonitor->Log->Lines->Add(buffer);

          FrmMonitor->WaitForDisplay();
          break;
        case A_MC_FIND_EDGES:
          break;
        case A_MC_SUBDIVIDE:
          break;
      }
      InvalidateRect(frmDisplay->Handle, NULL, false);
      FrmMonitor->WaitForDisplay();
      break;
    case S_MT:
      if(FrmMonitor->chkNoMTLog->Checked) return;
      FrmMonitor->Caption = IntToStr(FrmMonitor->p.Stats.Triangles.Count);
//      if(FrmMonitor->p.Stats.Triangles.Count < 13600) return; //10749
//      if(!FrmMonitor->chkMTAnimate->Checked && FrmMonitor->p.Stats.Triangles.Count % 500) return;
      switch(action){
        #define A_MT_FIRST_EDGE       0
#define A_MT_TRIANGLE_CREATED 1
#define A_MT_NEW_EDGE         2
#define A_MT_PATCH_FOR_EDGE   3
#define A_MT_NEW_VERTEX       4
#define A_MT_CYCLING          5
#define A_MT_MAX_COUNT        6
        case A_MT_FIRST_EDGE:
          sprintf(buffer, "First edge found");
          FrmMonitor->Log->Lines->Add(buffer);
          break;
        case A_MT_TRIANGLE_CREATED:
          sprintf(buffer, "Triangle # %i created.", FrmMonitor->p.Stats.Triangles.Count);
          FrmMonitor->Log->Lines->Add(buffer);
          break;
        case A_MT_NEW_EDGE:
          break;
        case A_MT_PATCH_FOR_EDGE:
          break;
        case A_MT_CYCLING:
          sprintf(buffer, "No more triangles can be created.");
          FrmMonitor->Log->Lines->Add(buffer);
          break;
        case A_MT_MAX_COUNT:
          sprintf(buffer, "Max. # of triangles created.");
          FrmMonitor->Log->Lines->Add(buffer);
          break;
      }
      InvalidateRect(frmDisplay->Handle, NULL, false);

      FrmMonitor->WaitForDisplay();
      break;
  }

//  sprintf(buffer, "Step: \t %i; Action: \t %i;", step, action);
//  FrmMonitor->Log->Lines->Add(buffer);
}
//---------------------------------------------------------------------------

double Sphere(double x, double y, double z){
  return x * x + y * y + z * z - 9;
}
//---------------------------------------------------------------------------

double Torus(double x, double y, double z){
//(x^2 + y^2 + z^2 + 3^2 - 2^2)^2 - 4*2^2(x^2+y^2)
  return pow(x * x + y * y + z * z + 9 - 0.5 * 0.5, 2) - 4 * 9 * (x * x + y * y);
}
//---------------------------------------------------------------------------

double Spheres(double x, double y, double z){
  double s1 = x * x + y * y + z * z - 9;
  double s2 = (x - 3.7) * (x - 3.7) + y * y + z * z - 9;
  return (s1 >= s2 ? s1 : s2);
}


//---------------------------------------------------------------------------
double Genus3(double x, double y, double z){
  return (256.0*z*z-
        (1.0-(x*x)/36.0-(y*y)/12.25)*
        ((x-3.9)*(x-3.9)+y*y-1.44)*
        ((x+3.9)*(x+3.9)+y*y-1.44)*
        (x*x+y*y-1.44));
}

//---------------------------------------------------------------------------
double Jack(double x, double y, double z){
// f_3(x,y,z)&=&(x^2/9 + 4y^2 + 4z^2)^{-4} + (y^2/9 + 4x^2 + 4z^2)^{-4} +{} \\
//& & (z^2/9 + 4y^2 + 4x^2)^{-4} +{} \\
//& & [(4x / 3 - 4)^2 + 16y^2/9 + 16z^2/9]^{-4} +{} \\
//   & & [(4x / 3 + 4)^2 + 16y^2/9 + 16z^2/9]^{-4} +{} \\
//& & [(4y / 3 - 4)^2 + 16x^2/9 + 16z^2/9]^{-4} +{} \\
//& & [(4y / 3 + 4)^2 + 16x^2/9 + 16z^2/9]^{-4} - 1
  if((x == 0.0) && (y == 0.0) && (z == 0.0)){
    return -999999999.0;
  }

  return 1.0 - pow( x*x / 9.0 + 4.0*y*y + 4.0*z*z, -4)
          - pow( y*y / 9.0 + 4.0*x*x + 4.0*z*z, -4)
          - pow( z*z / 9.0 + 4.0*y*y + 4.0*x*x, -4)
          - pow( (4*x / 3.0 - 4.0)*(4.0*x / 3.0 - 4.0) + 16.0*y*y / 9.0 + 16.0*z*z /9.0, -4)
          - pow( (4*x / 3.0 + 4.0)*(4.0*x / 3.0 + 4.0) + 16.0*y*y / 9.0 + 16.0*z*z /9.0, -4)
          - pow( (4*y / 3.0 - 4.0)*(4.0*y / 3.0 - 4.0) + 16.0*x*x / 9.0 + 16.0*z*z /9.0, -4)
          - pow( (4*y / 3.0 + 4.0)*(4.0*y / 3.0 + 4.0) + 16.0*x*x / 9.0 + 16.0*z*z /9.0, -4)  ;
}

//---------------------------------------------------------------------------


void __fastcall TFrmMonitor::btnStartClick(TObject *Sender)
{
  char buffer[255];

  int nulove = 0;
  int max = 0;

  this->btnStart->Enabled = False;
  this->Button1->Enabled = True;
  this->Button2->Enabled = True;
  this->Button3->Enabled = True;

  Triangulate(&(this->p));

  if(this->p.quit){
    this->Close();
    return;
  }
  
  sprintf(buffer, "Time for %i cubes %f s", this->p.Stats.Cubes.Count,
            ((double)(this->p.Stats.Cubes.End - this->p.Stats.Cubes.Start)) / CLK_TCK);
  Log->Lines->Add(buffer);

  sprintf(buffer, "Time for %i triangles %f s", this->p.Stats.Triangles.Count,
            ((double)(this->p.Stats.Triangles.End - this->p.Stats.Triangles.Start)) / CLK_TCK);
  Log->Lines->Add(buffer);

  sprintf(buffer, "Time for whole algorithm %f s",
            ((double)(this->p.Stats.All.End - this->p.Stats.All.Start)) / CLK_TCK);
  Log->Lines->Add(buffer);

  sprintf(buffer, "%i", HASHSIZE);
  Log->Lines->Add(buffer);

  for(int i = 0; i < HASHSIZE; i++){
    if(this->p.FoundEdges[i] == NULL ){
      nulove++;
    } else {
      int count = 0;
      for(TCubeEdges *CE = this->p.FoundEdges[i]; CE != NULL; CE = CE->Next){
        count++;
      }
      if(count > max)
        max = count;
    }
  }

  sprintf(buffer, "Edges: 0 - %i; max - %i", nulove, max);
  Log->Lines->Add(buffer);

  nulove = 0; max = 0;
  for(int i = 0; i < HASHSIZE; i++){
    if(this->p.FoundVertices[i] == NULL ){
      nulove++;
    } else {
      int count = 0;
      for(TCubeVertices *CV = this->p.FoundVertices[i]; CV != NULL; CV = CV->Next){
        count++;
      }
      if(count > max)
        max = count;
    }
  }

  sprintf(buffer, "Vertices: 0 - %i; max - %i", nulove, max);
  Log->Lines->Add(buffer);

  nulove = 0; max = 0;
  for(int i = 0; i < HASHSIZE; i++){
    if(this->p.FoundCubes[i] == NULL ){
      nulove++;
    } else {
      int count = 0;
      for(TCubesHash *CH = this->p.FoundCubes[i]; CH != NULL; CH = CH->Next){
        count++;
      }
      if(count > max)
        max = count;
    }
  }

  sprintf(buffer, "Cubes: 0 - %i; max - %i", nulove, max);
  Log->Lines->Add(buffer);

  nulove = 0; max = 0;
  for(int i = 0; i < HASHSIZE; i++){
    if(this->p.TriangleEdges[i] == NULL ){
      nulove++;
    } else {
      int count = 0;
      for(TTriangleEdges *TE = this->p.TriangleEdges[i]; TE != NULL; TE = TE->NextInHash){
        count++;
      }
      if(count > max)
        max = count;
    }
  }

  sprintf(buffer, "Triangle edges: 0 - %i; max - %i", nulove, max);
  Log->Lines->Add(buffer);


}
//---------------------------------------------------------------------------

void __fastcall TFrmMonitor::FormCreate(TObject *Sender)
{
  
  this->close_form = 0;
  this->p.Callback = Callback;


//  this->p.Function = Torus;
//  this->p.Config.STARTING_POSITION.X = 3.0;

//  this->p.Function = Sphere;
//  this->p.Config.STARTING_POSITION.X = 3.0;

//  this->p.Function = Genus3;
//  this->p.Config.STARTING_POSITION.X = 2.7;

//    this->p.Function = Jack;
//    this->p.Config.STARTING_POSITION.X = -1.9;
}
//---------------------------------------------------------------------------


void __fastcall TFrmMonitor::Button2Click(TObject *Sender)
{

  this->Pause = 0;  
}
//---------------------------------------------------------------------------

void TFrmMonitor::WaitForDisplay(){
  this->Pause = 1;
  while(this->Pause){
    Application->ProcessMessages();
    if(FrmMonitor->chkMTAnimate->Checked) break;
  }
  if(this->close_form){
    this->Close();
    Application->ProcessMessages();
  }
}
//---------------------------------------------------------------------------



void __fastcall TFrmMonitor::Button1Click(TObject *Sender)
{
     frmDisplay->Show();
}
//---------------------------------------------------------------------------

void __fastcall TFrmMonitor::Button3Click(TObject *Sender)
{

  if(this->dlgSave->Execute())
    ExportTriangles(&(this->p), (char *) this->dlgSave->FileName.data() );
}
//---------------------------------------------------------------------------

void __fastcall TFrmMonitor::Button4Click(TObject *Sender)
{
  char buffer[255];
  double AvgVal = 0.0;
  double MinVal = 1000000.0;
  double MaxVal = 0.0;

  Log->Lines->Add("STATISTICS:");
  Log->Lines->Add("--------------------------");
  Log->Lines->Add("");
  Log->Lines->Add("Vertices:");
  Log->Lines->Add("--------------------------");
  sprintf(buffer, "Count: %i", this->p.Vertices->Index);
  Log->Lines->Add(buffer);

  for(T3DPoints *AP = this->p.Vertices; AP != NULL; AP = AP->Next){
    double Value = this->p.Function(AP->Point.X, AP->Point.Y, AP->Point.Z);

    Value = Value * Value;
    AvgVal += Value;
    if(Value < MinVal) MinVal = Value;
    if(Value > MaxVal) MaxVal = Value;
  }
  AvgVal /= (double) this->p.Vertices->Index + 1.0;
  sprintf(buffer, "Avg Value: %f", AvgVal);
  Log->Lines->Add(buffer);
  sprintf(buffer, "Min Value: %f", MinVal);
  Log->Lines->Add(buffer);
  sprintf(buffer, "Max Value: %f", MaxVal);
  Log->Lines->Add(buffer);


  AvgVal = 0.0;
  MinVal = 1000000.0;
  MaxVal = 0.0;
  Log->Lines->Add("");
  Log->Lines->Add("Normals:");
  Log->Lines->Add("--------------------------");
  T3DPoints *AP = this->p.Vertices;
  for(T3DNormals *AN = this->p.Normals; AN != NULL; AN = AN->Next){
    double Value = (((-1.0) * AN->Normal) * AP->Point) / (sqrt(AN->Normal * AN->Normal) * sqrt(AP->Point * AP->Point));

    Value = Value * Value;
    AvgVal += (Value / (double) (this->p.Vertices->Index + 1.0));
    if(Value < MinVal) MinVal = Value;
    if(Value > MaxVal) MaxVal = Value;

    AP = AP->Next;
  }

  
  sprintf(buffer, "Avg Value: %f", AvgVal);
  Log->Lines->Add(buffer);
  sprintf(buffer, "Min Value: %f", MinVal);
  Log->Lines->Add(buffer);
  sprintf(buffer, "Max Value: %f", MaxVal);
  Log->Lines->Add(buffer);

}
//---------------------------------------------------------------------------


void __fastcall TFrmMonitor::FormClose(TObject *Sender,
      TCloseAction &Action)
{
  frmDisplay->Close();
  frmSettings->Close();
  if(this->p.quit){
    Action = caFree;
  }
  else {
    this->p.quit = 1;
    this->Pause = 0;
    Action = caNone;
  }
}
//---------------------------------------------------------------------------

