
 
  


#include "SimuCmds.hpp"

#include <signal.h>
#include <stdarg.h>
#include <unistd.h>
#include <math.h>

#include <cstdlib>
#include <cstdio>
#include <cstring>

#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <list>
#include <vector>
#include <stdexcept>

#include "gnuplot_i.hpp"

using namespace std;




int ImageType; 


extern int n_max;

extern double ***ex, ***ey, ***ez;  
extern double ***hx, ***hy, ***hz;
extern int nx, ny, nz;
unsigned int x_slice_low;
unsigned int x_slice_high;
unsigned int y_slice_low;
unsigned int y_slice_high;
unsigned int z_slice_low;
unsigned int z_slice_high;
bool plot_e_field;
bool plot_h_field;
unsigned int GenerateXFieldSliceAtIntrationNum;

          

bool ExecuteSimulation(void);
void PlotResults(string [], double [], double [], double [], double [], double);

volatile SIMU_CMD SimuCmd;
int ProgressCount;

extern void Init_ToyFDTDbezhig(void);
extern void DoInteration(void);

// **** FEM version of original FDTD algorythm ****************************************************************************************************

extern void Init_ToyFDTDbezhig_FEM(void);
extern void DoInteration_FEM(void);

	//Test only (Can only be used if DEMO_MATRIX_INVERSE is defined in ToyFDTDbezhig.cc)
extern void demo_matrix_inverse(void);
extern void mat_demo(void);
// ********************************************************************************************************************************************************


string TagNamesToPlot[20];
double ScaleFactors[20];
double MinPlotTimes[20];
double MaxPlotTimes[20];
double PlotTimeSteps[20];
double PlotTimeOffset;

void CtrlCHandler(int signal)
{
  string Command;

  cout << "\tEnter the one of the following commands and return:\n\n\t\t\"break\" - break simulation or plot.\n\t\t\"exit\"- exit simulation or plot.\n";

  
  while(TRUE){
 
    cout << "->";
    cin >> Command;
    if(Command == "break"){
      SimuCmd = SIMU_CMD_BreakLoop;
      break;
    }
    else if(Command == "exit"){
      SimuCmd = SIMU_CMD_Exit;
      break;
    }
  }
}



int main(int argc, char *argv[])
{
  string TagName;
  double ScaleFactor;
  double MinPlotTime;
  double MaxPlotTime;
  double PlotTimeStep;
  int i;

  // **** FEM version of original FDTD algorythm ***************************

  	  //Define only to evaluate validity of this code...
 //#define DEMO_MATRIX_INVERSE
  #ifdef DEMO_MATRIX_INVERSE
    demo_matrix_inverse();
    return 0;

  #endif
    //Define only to evaluate validity of this code..
//#define DEMO_MATRIX_MULTIPLY
#ifdef DEMO_MATRIX_MULTIPLY
    	//Produces an Identity matrix result in a 4x3 matrix.
    mat_demo();
    return 0;

#endif

  // *******************************************************************************











  signal(SIGINT, CtrlCHandler);


  
  //All "App_<xxxx>.hpp" use these functions.
  //!!!!!!!! THIS "COMPARE" MAKES NO SENCE,... NEVER TRUE,... FIX LATER !!!!!!!!!)
  if(ExecuteSimulation() == SIMU_CMD_Exit){
    return 0;
  }

  while(TRUE){
    if(SimuCmd == SIMU_CMD_Exit)
      break;
    
    cout << "\tEnter Plot Time Offset followed by\n\tPlot Name<return>\n\tScale factor<return>\n\tMin Time<return>\n\tMax Time<return>\n\t...\n\tUse symbol \"*\" to plot ALL or to terminate names.\n\tUse symbol \"$h\" to plot time stepping parameter \"h\".\n\n";
 
    for(i = 0; i < 20; i++){
      TagNamesToPlot[i] = "";
      ScaleFactors[i] = 1.0;
      PlotTimeSteps[i] = 0;
      PlotTimeOffset = 0;
    }
    //Note: Specifing a plot time offset is not just for visual support. The default precision for the temporary file
    //      generated for "gnuplot_i.cc" provides only 7 digits of precision for each column of data (including time).
    //      As the simulation time grows larger, we begin to truncate the values in the "time" column such that a "zoom"
    //      at the higher time values produces a less accurate picture compared to the "zoom" at the lower time points.
    //      Adding an offset allows us to zoom in near the zero point, making viewing at large time points more accurate.
    cout << "Plot Offset:";
    while(!(cin >> PlotTimeOffset) || (PlotTimeOffset < 0)){
      cout << "Error, bad plot time offset";
      cin.clear();
      cin.ignore();
      cout << "Plot Offset:";
    }
    i = 0;
    while(TRUE){
      cout << "->";
      cin >> TagName;
      if(TagName == "*"){
	break;
      }
      else{
	cout << "Scale Factor:";
	while(!(cin >> ScaleFactor)){
	  cout << "Error, bad scale factor";
	  cin.clear();
	  cin.ignore();
	  cout << "Scale Factor:";
	}
	cout << "Minimum Plot Time:";
	while(!(cin >> MinPlotTime)){
	  cout << "Error, bad minimum plot time";
	  cin.clear();
	  cin.ignore();
	  cout << "Minimum Plot Time:";
	}
	cout << "Maximum Plot Time:";
	while(!(cin >> MaxPlotTime)){
	  cout << "Error, bad maximum plot time";
	  cin.clear();
	  cin.ignore();
	  cout << "Maximum Plot Time:";
	}
	cout << "Plot Time Step:";
	while(!(cin >> PlotTimeStep) || (PlotTimeStep < 0)){
	  cout << "Error, bad plot time step";
	  cin.clear();
	  cin.ignore();
	  cout << "Plot Time Step:";
	}
      }



      TagNamesToPlot[i] = TagName;
      ScaleFactors[i] = ScaleFactor;
      MinPlotTimes[i] = MinPlotTime;
      MaxPlotTimes[i] = MaxPlotTime;
      PlotTimeSteps[i] = PlotTimeStep;
  
      i++;
      if(i == 19)
	break;
      
    }
    SimuCmd = SIMU_CMD_NoCommand;
    PlotResults(TagNamesToPlot, ScaleFactors, MinPlotTimes, MaxPlotTimes, PlotTimeSteps, PlotTimeOffset);
  }

}

void CheckPlotState(void)
{
  while(1){
    if((SimuCmd == SIMU_CMD_BreakLoop) || (SimuCmd == SIMU_CMD_Exit)){
      break;
    }
    pause();
   }
}

bool QuickCheckPlotState(void)
{
  return((SimuCmd == SIMU_CMD_BreakLoop) || (SimuCmd == SIMU_CMD_Exit));
 }


bool CheckSimuState(double CurTime, double SimuTime)
{
  int  CurProgressCount;
  if((SimuCmd == SIMU_CMD_BreakLoop) || (SimuCmd == SIMU_CMD_Exit)){
    cout << "\n\nSimulation stopped...\n\n\n";
    cout << "\t   Current Time - " << CurTime << "\n";
    cout << "\tSimulation Time - " << SimuTime << "\n\n\n";
    return FALSE;
  }
  else{
    CurProgressCount = (int) (100.0 * CurTime / SimuTime);
    if(CurProgressCount > ProgressCount){
      while(CurProgressCount > ProgressCount){
	printf("%3d percent executed...\n", CurProgressCount);
	ProgressCount++;
      }
      
    }
    return TRUE;
  }
}

bool ExecuteSimulation(void)
{
  Gnuplot SimuPlot;

  SimuPlot.reset_plot();

   //Un-comment to use FEM simulation.
//#define SIMULATE_USING_FEM

#ifdef SIMULATE_USING_FEM
  Init_ToyFDTDbezhig_FEM();
#else
  Init_ToyFDTDbezhig();
#endif

  while(1){

#ifdef SIMULATE_USING_FEM
	  DoInteration_FEM();
#else
    DoInteration();
#endif

#ifdef SIMULATE_USING_FEM
     x_slice_low = 1;
     x_slice_high = n_max - 1;
     y_slice_low = 1;
     y_slice_high = n_max - 1;
     z_slice_low = 1;
     z_slice_high = n_max - 1;
     plot_e_field = TRUE;
     plot_h_field = TRUE;


#else
    x_slice_low = 1; 
    x_slice_high = nx - 1;
    y_slice_low = 1;
    y_slice_high = ny - 1;
    z_slice_low = 1;
    z_slice_high = nz - 1;
    plot_e_field = TRUE;
    plot_h_field = TRUE;

#endif


// ***** Analysis of "curl" on center section of simulatin run*********************************
//
//Conditions: #define SIMULATE_Y_CONDUCTING_ELEMENT_TEST_CONTINUOUS
//                    (we should be at the DC portion of J" at this point.)
//
//
//
//

   GenerateXFieldSliceAtIntrationNum =25;

    // In Octave issue the following after this interation is executed.
    //
    //
    //octave:8> load Octave_U_V_data_file 
    //octave:9> [X Y] = meshgrid(1:32, 1:32);
    //octave:10> [curlz, cav] = curl(X, Y, U, V);
    //octave:11> mesh(X, Y, curlz)
    //octave:12> mesh(X, Y, cav)
    //octave:13> 


   // Comments: We see the distinctive "z" direction to the impressed "J" current.
   //           However, there is still indication wave propagating in the X/Y direction.
   //           We have to be careful of reflections on either side of the dipole. (I do not think
   //           this is the issue here. 
   //
   //        (Be careful of changing code in his program. Most of the parameters that generated this simulation 
   //         are hard coded!!!)
   //
   //
   //    Saved plots:
   //                   ./CURL_PLOTS/curlz.png,...cav.png,  simulation_run.png
   
 
 // **********************************************************************

#ifdef SIMULATE_USING_FEM


   SimuPlot.plot_vectors(n_max, n_max, n_max, (const double ***) ex, (const double ***) ey, (const double ***) ez,
			  (const double ***) hx, (const double ***) hy, (const double ***) hz,
			  (const unsigned int) x_slice_low, (const unsigned int ) x_slice_high,
			  (const unsigned int) y_slice_low, (const unsigned int ) y_slice_high,
			  (const unsigned int) z_slice_low, (const unsigned int ) z_slice_high,
		     (const bool) plot_e_field, (const bool) plot_h_field,
		     (const unsigned int) GenerateXFieldSliceAtIntrationNum );

#else

       SimuPlot.plot_vectors(nx, ny, nz, (const double ***) ex, (const double ***) ey, (const double ***) ez, 
    			  (const double ***) hx, (const double ***) hy, (const double ***) hz,
    			  (const unsigned int) x_slice_low, (const unsigned int ) x_slice_high, 
    			  (const unsigned int) y_slice_low, (const unsigned int ) y_slice_high,      
    			  (const unsigned int) z_slice_low, (const unsigned int ) z_slice_high, 
			     (const bool) plot_e_field, (const bool) plot_h_field,
			     (const unsigned int) GenerateXFieldSliceAtIntrationNum );

#endif

      }



}


void PlotResults(string [], double [], double [], double [], double [], double)
{
  Gnuplot SimuPlot;

  SimuPlot.reset_plot();


}
