//---------------------------------------------------------------------------
#include <vcl.h>
#include <string.h>
#include <iostream.h>
#include <complex.h>
#include <stdio.h>
#include <fstream.h>
#include <math.h>

#include "LastScreen.h"
#include "NextScreen.h"
#include "FileManager.h"
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TReviewScreen *ReviewScreen;

double Current[10000];
double CurrentRaw[10000];    //input data array
double Volt[10000];       //input data array
int DataCount;           //input data counter
double O2Current;
String FileName, FileDate, FileHHMMSS, FileAMPM, FileTime, FileScanRate, FileAux2;
String OutputFileName;
String HHMM;
bool Peak1Found = false;
bool Peak2Found = false;
float Fpeak = 0;
float Ipeak = 0;
float VoltBase = 0;
float VoltPeak = 0;

//---------------------------------------------------------------------------
__fastcall TReviewScreen::TReviewScreen(TComponent* Owner)
        : TForm(Owner)
{
        

}
//---------------------------------------------------------------------------
void __fastcall TReviewScreen::StartOverClick(TObject *Sender)
{
    ReviewScreen->Close();
    AnalysisInput->Close();
    FileScreen->WindowState = wsNormal;
}
//---------------------------------------------------------------------------
void __fastcall TReviewScreen::RunClick(TObject *Sender)

{
//      start program thread for file analysis
        ReviewScreen->WindowState = wsNormal;
        EndProgram->Enabled = true;
        RedDog = new TRedDog;

}
//---------------------------------------------------------------------------
//  RedDog is the TThread with the file analysis routines
//---------------------------------------------------------------------------
__fastcall TRedDog::TRedDog(void) : TThread(true)
{
    FreeOnTerminate = true;
    Priority = tpHigher;
    Resume();
}
//-----------------------------------------------------------------------------
void __fastcall TRedDog::Execute(void)
{//Start RedDog Thread . . . . . . . . .
        char Istring[20], Fstring[20], O2string[20], AVGstring[20], SDstring[20], SEstring[20];
        String RepTime;
        TimeStamp(); //get time and store in HHMM
        int FileCount = FileScreen->ListBox1->Items->Count;
        int RepLoop;
        double RepMean, RepSD, RepSE, RepData[20];
        int Replicates = AnalysisInput->Edit1->Text.ToInt();
        int RepDrop = AnalysisInput->Edit14->Text.ToInt();
        int N = Replicates-RepDrop;
        OutputFileName = FileScreen->DirectoryListBox1->Directory + "\\" +
                "ScanVoltSummary.txt";
        ofstream BlueCat(OutputFileName.c_str());
        OutputFileName = FileScreen->DirectoryListBox1->Directory + "\\" +
                "ScanVoltPlot.txt";
        ofstream GreenCat(OutputFileName.c_str());


BlueCat << "Scan Volt Summary Analysis (V 1.01)               " << HHMM.c_str() << endl;
BlueCat << endl;
/*BlueCat << "This program was designed by B. Glazer and A. Marsh to open sequential" << endl;
BlueCat << "   voltammetry scans and identify the signal peaks or features necessary" << endl;
BlueCat << "   for extracting concentration information about a redox species." << endl;
BlueCat << "` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `" << endl;
*/
BlueCat << endl;
BlueCat << "Data output for:     " << FileScreen->DirectoryListBox1->Directory.c_str() << endl;
BlueCat << "Input variables for analysis:" << endl;
BlueCat << "   Moving average window (+/-): " << AnalysisInput->Edit13->Text.c_str() << endl;
BlueCat << "   Number of replicates:   " <<  AnalysisInput->Edit1->Text.c_str() << endl;
BlueCat << "   Ignore first x replicate(s): x =" << AnalysisInput->Edit14->Text.c_str() << endl;
if (AnalysisInput->CheckBox7->Checked)
{  BlueCat << "   Oxygen -  Vi: " << AnalysisInput->Edit2->Text.c_str()
           << "   Vf: " <<  AnalysisInput->Edit3->Text.c_str() << endl;
}

BlueCat << endl;
BlueCat << "==========================================================================================" << endl;
BlueCat << "File Name      Date       Time      AUX2    Vi      Vf      O2(na)  AVG   SD   SE   status" << endl;
BlueCat << "------------------------------------------------------------------------------------------" << endl;

// Here's where the cycle starts . . . . . . . .  .
        RepLoop = 1;
        for (int xFileIn =0; xFileIn < FileCount; xFileIn++)
        {
           if (RepLoop > Replicates)
           {    RepLoop =1; }

           // set all array data to zero
           for (int i=0; i<9999; i++)
           {    Current[i]=Current[i]-Current[i];
                Volt[i]=Volt[i]-Volt[i];
                CurrentRaw[i]=CurrentRaw[i]-CurrentRaw[i];
           }

           // Job 1: Open next file and input data into variable arrays
           FileInput(xFileIn);
           if (FileName != "Not scan data file")
           {
                // Job 2: Update output file
                BlueCat << FileName.c_str() << "   "
                        << FileDate.c_str() << "   "
                        << FileTime.c_str() << "   "
                        << FileScanRate.c_str() << "   "
                        << FileAux2.c_str() << "   ";

                if (2*RepLoop > (Replicates-RepDrop)) { RepTime = FileTime; }

                // Job 3: Data manipulation and calculation
                if (AnalysisInput->CheckBox7->Checked == true)
                {  float Vi =  StrToFloat(AnsiString(AnalysisInput->Edit2->Text));
                   float Vf =  StrToFloat(AnsiString(AnalysisInput->Edit3->Text));
                   O2Current = DataProcess(Vi, Vf);
                }

                if (RepLoop > RepDrop)   //setup of array of replicate measurements
                {
                   RepData[RepLoop-RepDrop-1] = O2Current;
                }

                if (RepLoop == Replicates)
                {       RepMean = 0; RepSD = 0; RepSE = 0;
                        for (int x=0; x<N ; x++)
                        {   RepMean += RepData[x]; }
                        RepMean = RepMean/N;
                        for (int x=0; x<N ; x++)
                        {   RepSD += Sqr(RepData[x]-RepMean); }
                        RepSD = sqrt(RepSD/(N-1));
                        RepSE = RepSD/sqrt(N);
                        sprintf(AVGstring, "%5.3f", SigDigits(RepMean));
                        sprintf(SDstring, "%5.3f", SigDigits(RepSD));
                        sprintf(SEstring, "%5.3f", SigDigits(RepSE));
                }

                // Job 4: Update output file
                sprintf(Istring,  "%5.3f", SigDigits(VoltBase));
                sprintf(Fstring,  "   %5.3f", SigDigits(VoltPeak));
                sprintf(O2string, "   %5.3f", SigDigits(O2Current));
                BlueCat << Istring << Fstring << O2string << "   ";
                if (RepLoop == Replicates)
                {       BlueCat << AVGstring <<" "<< SDstring << " "<< SEstring << " ";
                        GreenCat << RepTime.c_str() << "\t" <<FileScanRate.c_str()  <<"\t"<< AVGstring << "\t" << SDstring << "\t" << SEstring << endl;
                        if (Peak1Found && Peak2Found)
                        {   BlueCat << "OK " << endl; }
                        else
                        {   if (!Peak1Found) { BlueCat << "-Vf"; }
                            if (!Peak2Found) { BlueCat << "-Vi"; }
                            BlueCat << endl;
                        }

                }
                else
                {       BlueCat << "                  ";
                        if (Peak1Found && Peak2Found)
                        {   BlueCat << "OK " << endl; }
                        else
                        {   if (!Peak1Found) { BlueCat << "-Vf"; }
                            if (!Peak2Found) { BlueCat << "-Vi"; }
                            BlueCat << endl;
                        }
                }

                ReviewScreen->Memo1->Lines->Add(FileName + "   " +
                            AnsiString(SigDigits(O2Current)));

                // Job 5: Format and output results to file


                // Go Back and get the next data set
           }//end if !FileName = "Not scan data file"
           else {  ReviewScreen->Memo1->Lines->Add(FileName); }
           RepLoop++;
        }//end of for xFileIn loop

        // Job 6:  Omit requested scans & average replicates


        BlueCat.close();
        ReviewScreen->Memo1->Lines->Add(" ");
        ReviewScreen->Memo1->Lines->Add("Job Complete");

}//end of RedDog TThread.................
//------------------------------------------------------------------
void TRedDog::FileInput(int FileNum)
{       bool found = false;
        char flag[10];
        char RawInput[20];
        double CurrentIn, VoltIn;
        String FirstWord;
        int L;
        FileName = "Not scan data file";

// Define the current input filename
        String sFile = FileScreen->DirectoryListBox1->Directory + "\\" +
                FileScreen->ListBox1->Items->Strings[FileNum];

// Open the current input file for data stream
        ifstream InputFile(sFile.c_str());

    // Check for valid DataFile -------------------------------
    InputFile >> RawInput;
    FirstWord.SetLength(20);
    L = sprintf(FirstWord.c_str(), RawInput);
    FirstWord.SetLength(L);
    if (FirstWord == "AIS")
    {   InputFile.ignore(100,'\n');
    // Find Name ----------------------------------------------
        for (int iLines = 0; iLines < 3; iLines++)
        {       InputFile.ignore(100,'\n');   }
        found = false;
        while (!found)
        {       InputFile >> flag[0];
                if (flag[0] == ':')
                { found = true;  }
        }
        InputFile >> RawInput;
        FileName.SetLength(20);
    	L = sprintf(FileName.c_str(), RawInput);
        FileName.SetLength(L);
    // Find Date ----------------------------------------------
        for (int iLines = 0; iLines < 0; iLines++)
        {       InputFile.ignore(100,'\n');   }
        found = false;
        while (!found)
        {       InputFile >> flag[0];
                if (flag[0] == ':')
                { found = true;  }
        }
        InputFile >> RawInput;
        FileDate.SetLength(20);
    	L = sprintf(FileDate.c_str(), RawInput);
        FileDate.SetLength(L);
    // Find Time ---------------------------------------------
        for (int iLines = 0; iLines < 0; iLines++)
        {       InputFile.ignore(100,'\n');   }
        found = false;
        while (!found)
        {       InputFile >> flag[0];
                if (flag[0] == ':')
                { found = true;  }
        }
        InputFile >> RawInput;
        FileHHMMSS.SetLength(20);
    	L = sprintf(FileHHMMSS.c_str(), RawInput);
        FileHHMMSS.SetLength(L);
        InputFile >> RawInput;
        FileAMPM.SetLength(20);
    	L = sprintf(FileAMPM.c_str(), RawInput);
        FileAMPM.SetLength(L);
        FileTime = FileHHMMSS + " " + FileAMPM;
    // Find ScanRate ----------------------------------
        for (int iLines = 0; iLines < 21; iLines++)
        {       InputFile.ignore(100,'\n');   }
        found = false;
        while (!found)
        {       InputFile >> flag[0];
                if (flag[0] == ':')
                { found = true;  }
        }
        InputFile >> RawInput;
        FileScanRate.SetLength(20);
    	L = sprintf(FileScanRate.c_str(), RawInput);
        FileScanRate.SetLength(L);
    // Find AUX2 ----------------------------------
        for (int iLines = 0; iLines < 27; iLines++)
        {       InputFile.ignore(100,'\n');   }
        found = false;
        while (!found)
        {       InputFile >> flag[0];
                if (flag[0] == ':')
                { found = true;  }
        }
        InputFile >> RawInput;
        FileAux2.SetLength(20);
    	L = sprintf(FileAux2.c_str(), RawInput);
        FileAux2.SetLength(L);
   // Data Input --------------------------------------
        //for (int iLines = 0; iLines < 4; iLines++)
        //{       InputFile.ignore(100,'\n');   }
        {
             //Skip to the header of the table of data
             string line = "";
             while (string::npos == line.find("Applied Potential, V:")) getline(InputFile, line);
        }
        DataCount = 0;
        while (!InputFile.eof())
 	{    InputFile >> VoltIn >> CurrentIn;
             Volt[DataCount] = VoltIn*-1; //use positive values
             CurrentRaw[DataCount] = SigDigits(CurrentIn*1000000000);//convert to nanoamps
             DataCount += 1;
        }
        DataCount -= 1;
        Current[9999] = 666;

   // Data smoothing --------------------------------
        double CurrentSum;
        int smoothing_points = AnalysisInput->Edit13->Text.ToInt();
//        if (AnalysisInput->ComboBox1->Items->Strings == 'moving average')
        int v;
        for (int i=0; i<smoothing_points; i++)
        {     CurrentSum=0;
              v = (2*i) + 1 ;
              for (int j=0; j < v; j++)
              {     CurrentSum += CurrentRaw[j]; }
              Current[i] = CurrentSum/(v);
        }

        for (int i=smoothing_points; i < DataCount-smoothing_points; i++)
        {     CurrentSum = 0;
              for (int j=0; j <= ((2*smoothing_points)+1); j++)
              {     CurrentSum += CurrentRaw[(i-smoothing_points)+j]; }
              Current[i] = CurrentSum/((2*smoothing_points)+1);
        }
    } // IF FirstWord == AIS to check for valid datafile
//Data input is complete and the CPU will return to the EXECUTE function
}
//------------------------------------------------------------------
float TRedDog::DataProcess(float Vi, float Vf)
{       float istart = Vi - 0.15;
        float istop  = Vi + 0.15;
        float fstart = Vf - 0.15;
        float fstop  = Vf + 0.15;
        float diff1=0;
        float diff2=0;
        int StartIndex, StopIndex, i, I_index;
    //    int smoothing_points = AnalysisInput->Edit13->Text.ToInt();
        int smoothing_points = 10;
        I_index = 9999; //value flag for error
        Fpeak = 0;
        Ipeak = 1000;
        VoltPeak = 0;
        VoltBase = 0;
        Peak1Found = false;
        Peak2Found = false;

// Look for peak max (Vf)
        i = 0;
        while (Volt[i] < fstart)
        {  i++; }
        StartIndex = i;
        while (Volt[i] < fstop)
        {   if (Current[i] > Current[i+1])
            {    Peak1Found = true;
                 if (Current[i] > Fpeak)
                 {   Fpeak = Current[i]; VoltPeak = Volt[i];}
            }
            i++;
        }// end while
/*
   No Peak found ? . . .  Locate the Current[i] value at the flatest
   part of the curve near Vf. Find the [i] position where the sum of
   squares of the differences between ith observation is minimized across
   the 'smoothing' window. Returns mid-point of the window as Current[i].
*/
        if (!Peak1Found)
        {   i = StartIndex;
            while (Volt[i] < fstop)
            {    diff1 = 0;
                 diff2 = 1000000000;
                 for (int j=0; j <= ((2*smoothing_points)+1); j++)
                 {     diff1 += (Sqr(Current[(i-smoothing_points)+j]-
                                 Current[(i-smoothing_points)+j+1]));
                 }// end for j
                 if (diff1 < diff2)
                 {   diff2 = diff1; //store lowest sum of squares
                     I_index = i;   //store i position of low sos.
                     // could return the starting ith obs as: i-smoothing_points
                 }// end if
                 i++;
            }// end while
            Fpeak = Current[I_index]; //on error, Fpeak will equal 666
            VoltPeak = Volt[I_index];
        } // end if !Peak1Found

// Look for peak min (Vi)
        I_index = 9999;  // error flag value
        i = 0;
        if (Volt[i] < istart)
        {    while (Volt[i] < istart)
             {  i++;}
        }
        StartIndex = i;
        while (Volt[i] < istop)
        {   if (Current[i] > Current[i+1])
            {    Peak2Found = true;
                 if (Current[i+1] < Ipeak)
                 {   Ipeak = Current[i+1]; VoltBase = Volt[i+1];}
            }
            i++;
        }// end while
/* The comparison below is designed to find an inflection point by looking
for the greatest difference in SOS between two areas of the data curve:
at the ith position, the comparison is between the i+smoothing_points and the
i-smoothing_points values.
*/
     if (!Peak2Found)
     {  if (StartIndex > smoothing_points) { i = StartIndex; }
        else { i = smoothing_points; }
        diff1 = 0;
        diff2 = 0;
        while (Volt[i] < istop)
        {
             double GoingUp = 0;
             double GoingDown = 0;
             for (int j=1; j <= smoothing_points; j++)
             {     GoingDown += Sqr(Current[i-j] - Current[i]);
                   GoingUp   += Sqr(Current[i+j] - Current[i]);
             }// end for j
             diff1 = Sqr(GoingUp - GoingDown);
             if (diff1 > diff2)
             {   diff2 = diff1;
                 I_index = i;
             }// end if
             i++;
         }// end while
         Ipeak = Current[I_index]; // on error Ipeak will equal 666
         VoltBase = Volt[I_index];
     }//end if !Peak2Found

     return Fpeak - Ipeak;

}
//------------------------------------------------------------------
double TRedDog::Sqr(double x)
{
        x = x*x;
        return x;
}
//---------------------------------------------------------------------------
void TRedDog::TimeStamp()
{
        SYSTEMTIME time;
        GetLocalTime (&time);
        HHMM.SetLength(64);
        int L = GetTimeFormat (LOCALE_USER_DEFAULT, 0, &time, NULL, HHMM.c_str(),HHMM.Length());
        HHMM.SetLength(L);

        return;

}
//---------------------------------------------------------------------------
double TRedDog::SigDigits(double NanoAmps)
{       double SignificantDigits;
        NanoAmps = NanoAmps*10000;
        SignificantDigits = ceil(NanoAmps);
        SignificantDigits = SignificantDigits/10000;
        return SignificantDigits;
}
//----------------------------------------------------------------------------
void __fastcall TReviewScreen::EndProgramClick(TObject *Sender)
{       RedDog->Terminate();
        ReviewScreen->Close();
        AnalysisInput->Close();
        FileScreen->Close();
}
//---------------------------------------------------------------------------
void __fastcall TReviewScreen::FormShow(TObject *Sender)
{
        AnalysisInput->WindowState = wsMinimized;        
}
//---------------------------------------------------------------------------

