//----------------------------------------------------------------------------//
//    module FVarTypes.cpp                                                    //
//                                                                            //
//    Dialog (form to be shown with ShowModal()) to show and edit the         //
//    variable types. Symbolic variables can be toggled between nominal       //
//    and nominal (symbolic) type. Additional information like extrema,       //
//    # symbols etc. is displayed for each variable.                          //
//                                                                            //
//    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 "FVartypes.h"
#pragma package(smart_init)
#pragma resource "*.dfm"

#include <htmlhelp>     // due to   HTML help

#define PREC   2        // precision used to display data minima etc.


TFVarTypes *FVarTypes;

//----------------------------------------------------------------------------------------------------------------------
// fill string grid with variable informatiob like extrema, # symbols and current variable type. Each variable is
// displayed in an own row.
void __fastcall TFVarTypes::FormShow(TObject *Sender)
{
// ToDo: check if data is given, else show IPI error and close

   // a) set string grid properties
   StringGrid->RowCount = data->nVar()+1;    // set as many rows as variables (+1 because of the header row)
   StringGrid->ColCount = 7;
   StringGrid->Hint = "You may toggle the type of each highlighted variable by just clicking on it.";


   // b) set column names and focused control
   StringGrid->Cells[0][0] = "Column";
   StringGrid->Cells[1][0] = "Minimum";
   StringGrid->Cells[2][0] = "Maximum";
   StringGrid->Cells[3][0] = "Mean";
   StringGrid->Cells[4][0] = "Deviation";
   StringGrid->Cells[5][0] = "# Symbols";
   StringGrid->Cells[6][0] = "Type";


   // c) set extrema, deviation etc.
   char text[256];
   for(int j=0;j<data->nVar();j++)
   {
      // column Id and - for first (output) add "(Output)"
      if(j==0)
         StringGrid->Cells[0][j+1] = AnsiString(TData::OriginalColumnInFile(j, data->OutputColumn())) + " (Output)";
      else
         StringGrid->Cells[0][j+1] = TData::OriginalColumnInFile(j, data->OutputColumn());


      StringGrid->Cells[1][j+1] = ValueToText1(data->Min()[j],  0, PREC);           // minimum
      StringGrid->Cells[2][j+1] = ValueToText1(data->Max()[j],  0, PREC);           // maximum
      StringGrid->Cells[3][j+1] = ValueToText1(data->Mean()[j], 0, PREC);           // mean
      StringGrid->Cells[4][j+1] = ValueToText1(data->Dev()[j],  0, PREC);           // deviation
      StringGrid->Cells[5][j+1] = ValueToText1(data->nIntegerMaxMin(j), 0, PREC);   // # symbols
   }

   // d) write variable types and initialize check box
   VarTypesToStringGrid();
   EvVarTypes();
}


//----------------------------------------------------------------------------------------------------------------------
// resize column width in string grid
void __fastcall TFVarTypes::FormResize(TObject *Sender)
{
   // calculate column width ignoring the first column
   const int w = (StringGrid->ClientWidth-StringGrid->ColWidths[0]-GetSystemMetrics(SM_CXVSCROLL))/(StringGrid->ColCount-1);

   for(int j=1;j<StringGrid->ColCount;j++)      // do not(!) resize the first column (variable id's)
      StringGrid->ColWidths[j] = w;
}


//----------------------------------------------------------------------------------------------------------------------
// response to button 'Ok': close window
void __fastcall TFVarTypes::BtOkClick(TObject *Sender)
{
   Close();
}


//----------------------------------------------------------------------------------------------------------------------
// if there are integer variables and they are not all symbolic: enable and uncheck check box
bool TFVarTypes::EvVarTypes()
{
   // check variable's which could be symbolic are all symbolic (nominal)
   bool f_Symbolic=false, f_AllSymbolic=true, f_AllContinous=true;
   for(int j=0;j<data->nVar();j++)
      if(prj->CouldBeSymbolic(j))      // variable type could be symbolic (nominal)
      {
         f_Symbolic = true;            // there are possible symbolic variables
         if(!data->IsSymbolic(j))      // check
            f_AllSymbolic = false;     // not all possibly symbolic are symbolic
         else
            f_AllContinous = false;      // at least one variable is symbolic
      }


   // check/uncheck check box (group box 'Speed Settings')
   CbNominal->Checked = f_AllSymbolic && f_Symbolic;
   CbContinous->Checked = f_AllContinous;

   if(f_Symbolic)
   {
      CbNominal  ->Enabled = !f_AllSymbolic;
      CbContinous->Enabled = !f_AllContinous;
   }
   else
   {
      CbNominal->Enabled = false;
      CbContinous->Enabled = false;
   }

   return f_Symbolic;
}


//----------------------------------------------------------------------------------------------------------------------
// write all variable types to string grid
void TFVarTypes::VarTypesToStringGrid()
{
   for(int j=0;j<data->nVar();j++)        // for each variable
      switch(data->GetVarType(j))                                          // get variable type ...
      {
         case TData::cont : StringGrid->Cells[6][j+1]="continous"; break;         // .. and write corresponding text
         case TData::symb : StringGrid->Cells[6][j+1]="symbolic";  break;
      }
}


//----------------------------------------------------------------------------------------------------------------------
// evaluate mouse clicks in the string grid: toggle symbolic variable type between nominal and ordinal type. Display
// warning if variable is continous
void __fastcall TFVarTypes::StringGridClick(TObject *Sender)
{
   // a) only evaluate clicks in the 6th column which contains the variable types
   if(StringGrid->Col!=6)
      return;

   // b) if 6th column: try to toggle variable type
   if(prj->CouldBeSymbolic(StringGrid->Row-1))                       // if variable could be symbolic (nominal)
   {
      // b1) if it is an input variable ...
      if(StringGrid->Row!=1)
         if(!main->AllowChangeOfInputType())         // ... ask user if a model is present cause this would be deleted
         {
            CorrectSelection();
            return;
         }

      // b2) toggle variable type
      if(data->GetVarType(StringGrid->Row-1)==TData::symb)
      {
         data->SetVarType(StringGrid->Row-1, TData::cont);                  // set to be continous
         StringGrid->Cells[6][StringGrid->Row]="continous";
      }
      else
      {
         data->SetVarType(StringGrid->Row-1, TData::symb);                  // set to be symbolic (nominal)
         StringGrid->Cells[6][StringGrid->Row]="symbolic";
      }


      // b3) display warning if output variable type has been changed
      if(StringGrid->Row==1)
        Application->MessageBox("You've toggled the type of the output variable! This type is ignored.\nUse the regression check\
 box instead!", "Warning", MB_OK | MB_ICONWARNING);


      // b4) check/unckeck boxes
      EvVarTypes();     // if all symbolic variables are either nominal or ordinal: check corresponding check box

      main->SetSavedFlag(false); // unset saved flag cause something was changed
   }


   // c) 'correct selection'
   CorrectSelection();
}


//----------------------------------------------------------------------------------------------------------------------
// correct selection in list box
void TFVarTypes::CorrectSelection()
{
// (hack!) necessary cause focus is always defered to close button ??
   TGridRect rect;
   rect.Left = rect.Right = rect.Top = rect.Bottom = 1;
   StringGrid->Selection=rect;
}


//----------------------------------------------------------------------------------------------------------------------
// if box is checked: set all symbolic variables to be nominal
void __fastcall TFVarTypes::CbNominalClick(TObject *Sender)
{
   if(CbNominal->Checked)                    // if check box is set
   {
      // determine if any input variable would be changed
      bool f_Check = false;
      for(int j=1;j<data->nVar();j++)
         if(prj->CouldBeSymbolic(j) && !data->IsSymbolic(j))   // if variable could be symbolic and currently is not ...
            f_Check = true;                                    // ... set flag that an input variable would be changed


      // if model is present: ask user if inputs would be changed
      if(f_Check)
         if(!main->AllowChangeOfInputType())
         {
            CbNominal->Checked=false;           // reset again
            return;
         }


      // change
      for(int j=0;j<data->nVar();j++)           // for each variable
         if(prj->CouldBeSymbolic(j))            // set it to be symbolic if it could
            data->SetVarType(j, TData::symb);

      CbNominal->Enabled = false;               // disable myself
      CbContinous->Enabled = true;              // and enable
      CbContinous->Checked = false;             // and uncheck the 'other'


      // display changes: write variable types to list box again
      VarTypesToStringGrid();
   }

   ActiveControl = BtOk;    // set focus to button 'Ok'
}


//----------------------------------------------------------------------------------------------------------------------
// if box is checked: set all symbolic variables to be continous
void __fastcall TFVarTypes::CbContinousClick(TObject *Sender)
{
   if(CbContinous->Checked)                    // if check box is set
   {
      // determine if any input(!) variable would be changed
      bool f_Check = false;
      for(int j=1;j<data->nVar();j++)
         if(data->IsSymbolic(j))               // if variable is symbolic
            f_Check = true;                    // ... set flag that an input variable would be changed


      // if model is present: ask user if inputs would be changed
      if(f_Check)
         if(!main->AllowChangeOfInputType())
         {
            CbContinous->Checked=false;        // reset again
            return;
         }


      // change
      for(int j=0;j<data->nVar();j++)           // for each variable
         data->SetVarType(j, TData::cont);      // set it to be continous

      CbContinous->Enabled = false;             // disable myself
      CbNominal->Enabled = true;                // and enable
      CbNominal->Checked = false;               // and uncheck the 'other'


      // display changes: write variable types to list box again
      VarTypesToStringGrid();
   }

   ActiveControl = BtOk;    // set focus to button 'Ok'
}


//----------------------------------------------------------------------------------------------------------------------
// ensure that only integer input variable types can be selected
void __fastcall TFVarTypes::StringGridSelectCell(TObject *Sender, int ACol, int ARow, bool &CanSelect)
{
   CanSelect = (ACol==6 /*&& ARow!=1*/ && prj->CouldBeSymbolic(ARow-1));
}


//----------------------------------------------------------------------------------------------------------------------
// Respond to OnDrawCell event: draw cell text using some special background colors to visualize variable types
void __fastcall TFVarTypes::StringGridDrawCell(TObject* Sender, int ACol, int ARow, TRect& Rect, TGridDrawState State)
{
   // if it's a fixed row (headers)
   if(State.Contains(gdFixed))
   {
      StringGrid->Canvas->Brush->Color = clBtnFace;
      StringGrid->Canvas->Font->Color = clWindowText;
      StringGrid->Canvas->FillRect(Rect);
      Frame3D(StringGrid->Canvas, Rect, clBtnHighlight, clBtnShadow, 1);
   }

   // color column 6 if it could be a symbolic variable (if it would be an input)
   else if(ACol==6 /*&& ARow!=1*/ && prj->CouldBeSymbolic(ARow-1))              // note: minus 1 because first row is 1
   {
      if(data->GetVarType(ARow-1)==TData::cont)
         StringGrid->Canvas->Brush->Color = clActiveCaption;
      else
         StringGrid->Canvas->Brush->Color = clInactiveCaption;

      StringGrid->Canvas->Font->Color = clCaptionText;
      StringGrid->Canvas->FillRect(Rect);
   }

   // if normal
   else
   {
      StringGrid->Canvas->Brush->Color = StringGrid->Color;
      StringGrid->Canvas->Font->Color = StringGrid->Font->Color;
      StringGrid->Canvas->FillRect(Rect);
   }

   AnsiString text = " " + StringGrid->Cells[ACol][ARow];
   StringGrid->Canvas->TextRect(Rect, Rect.Left, Rect.Top, text);
}


//----------------------------------------------------------------------------------------------------------------------
// close all help windows
void __fastcall TFVarTypes::FormClose(TObject*, TCloseAction&){ /* HtmlHelp(0, 0, HH_CLOSE_ALL, 0); */}