//----------------------------------------------------------------------------//
//    module ThrOpenProject.cpp                                               //
//                                                                            //
//    Thread function: Loads model, tuning results and data as specifed in    //
//    given TProjectG object. Calls back to given c-style function when       //
//    finished.                                                               //
//                                                                            //
//    copyright (c) 2003 by Lars Haendel                                      //
//    home: www.newty.de                                                      //
//                                                                            //
//    This program is free software and can be used under the terms of the    //
//    GNU licence. See header file for further information and disclaimer.    //
//                                                                            //
//----------------------------------------------------------------------------//


#include <vcl.h>
#pragma hdrstop

# include "ThrOpenProject.h"
#pragma package(smart_init)


#include "exception.h"                 // due to:  TExceptionU


//----------------------------------------------------------------------------------------------------------------------
// constructor
__fastcall ThrOpenProject::ThrOpenProject(bool CreateSuspended, void (*_FinishFunc)(), TProjectG*const& _prj,
   const char*const& _szModelFile, const char*const& _szTuningFile, const bool*const& _f_Stop/*=NULL*/)
   : TThread(CreateSuspended)
{
   FinishFunc      = _FinishFunc;      // callback function; called when finished
   prj             = _prj;             // project
   szModelFile     = _szModelFile;
   szTuningFile    = _szTuningFile;
   f_Stop          = _f_Stop;          // stop flag

   Priority        = tpNormal;         // set thread's properties
   OnTerminate     = &OnFinish;
   FreeOnTerminate = true;


   data_L = NULL;                      // initialize to NULL
   data_T = NULL;
   model = NULL;
   tuningResults = NULL;

   szFilename = NULL;                  // "delete" filename

   // note: Ini of f_IsWithOutput not necessary
}



//----------------------------------------------------------------------------------------------------------------------
// execute function gets called when thread object is created
void __fastcall ThrOpenProject::Execute()
{
   try
   {
      // a) load model if filename is given
      const TDataData* ddata = NULL;                     // ini
      szFilename = szModelFile;                          // set filename pointer
      if(szFilename[0]!='\0')
      {
         ifstream file(szFilename);                                           // open model file
         IfTrueThrowTypeU(!file, "Unable to open file '%s'!", szFilename);    // and check success

         model = new TCluster();                        // new model
         int line = 1;
         model->Load(file, line);                       // load model 
         file.close();                                   // close file

         ddata = model->GetDataData();                  // set ddata object which will be checked against data
      }

      // b) load learn data
      szFilename = prj->GetData1FileName();              // set filename pointer
      data_L = new TData();                              // new learn data object
      data_L->Load(szFilename, f_Stop, ddata);           // load data using TData::Load()


      // MayBe: check if loaded data matches with ddata object (if there is one) ??   No, would be better but it's not
      // necessary because once the model is learned it relies only on the ddata object, there would not be a problem
      // although the situation is clearly an error.
      szFilename = "project file";     // (hack!)
      prj->Synchronize(data_L);


      // calculate feature weights and standard parameter values
      szFilename = prj->GetData1FileName();                                                        // set filename
      data_L->CalculateWeights(prj->Get_N_Bins(), !prj->Regression(), prj->EqualWidthBinning());   // feature weights



      // c) load tuning results if filename is given
      szFilename = szTuningFile;                                              // set filename pointer
      if(szFilename[0]!='\0')
      {
         ifstream file(szFilename);                                           // open model file
         IfTrueThrowTypeU(!file, "Unable to open file '%s'!", szFilename);    // and check success

         tuningResults = new TTune(prj, data_L);                              // new object
         int line = 1;
         tuningResults->Load(file, line);                                     // load tuning results
         file.close();                                                        // close file
      }



      // d) load test data
      szFilename = prj->GetData2FileName();                       // set filename pointer
      if(szFilename[0]!='\0')                                     // if test data file name is given
      {
         // check if model is loaded cause otherwise no test data can be loaded
         IfTrueThrowTypeU(!ddata, "You cannot specify a test data file if no model is given!");

         data_T = new TData();                                    // new test data object
         data_T->Load(prj->GetData2FileName(), f_Stop, ddata);    // load data using TData::Load()

         // set output column and variable types and throw error if they cannot be set
         f_IsWithOutput = data_T->MakeCompatible(ddata);
      }
   }
   catch(TExceptionU excp)
   {                                            // exception handling 'type U' exception
      strcpy(szText, excp.GetErrorText());      // copy error message ...
      Synchronize(MessageBox);                  // ... and display it in a message box
      Synchronize(Clear);                       // release data and model again
   }
   catch(TExceptionAB excp)
   {                                            // exception handling 'type AB' exception
      strcpy(szText, excp.GetErrorText());      // copy error message ...
      Synchronize(MessageBox);                  // ... and display it in a message box
      Synchronize(Clear);                       // release data and model again
   }
   catch(...)
   {                                            // all other exceptions
      strcpy(szText, "C++ Exception ;-) (ThrOpenProject::Execute)");      // copy error message ...
      Synchronize(MessageBox);                  // ... and display it in a message box
      Synchronize(Clear);                       // release data and model again
   }
}


//----------------------------------------------------------------------------------------------------------------------
// return status text
const char* ThrOpenProject::Status()
{
   if(data_T)
      return data_T->StatusText();
   else
      if(data_L)
         return data_L->StatusText();
      else
         if(model)
            return "Loading model ...";
         else
            return "Initializing";
}


//----------------------------------------------------------------------------------------------------------------------
// return current progress
float ThrOpenProject::Progress()
{
   if(data_T)
      return data_T->LoadDataProgress();
   else
      if(data_L)
         return data_L->LoadDataProgress();
      else
         return 0;
}


//----------------------------------------------------------------------------------------------------------------------
// return actually processed filename
const char* ThrOpenProject::Filename()
{
   if(szFilename)
      return szFilename;
   else
      return "";
}


//----------------------------------------------------------------------------------------------------------------------
// display error message
void __fastcall ThrOpenProject::MessageBox()
{
   char szCaption[256];
   sprintf(szCaption, "Error loading %s", szFilename);
   Application->MessageBox(szText, szCaption, MB_OK | MB_ICONERROR);
}


//----------------------------------------------------------------------------------------------------------------------
// release data and model again (in case of an error) and set pointer to NULL
void __fastcall ThrOpenProject::Clear()
{
   if(data_L)                    // release data
      data_L->Release();
   if(data_T)
      data_T->Release();
   data_L = data_T = NULL;

   if(model)                    // release model
      delete model;
   model = NULL;
}