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

        Final Project                                 MMU 1996

        ######################################################
        #                                                    #
        #               A Modular Neural Network             #   
        #                                                    #  
        #                 The User Interface                 #   
        #                                                    #
        ######################################################
 
        Albrecht Schmidt                              17.09.96
 
        FILE: CUserIF.C                            Version 1.0
 
   ************************************************************* */

#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "CUserIF.h"

#define PRINT     3
#define PRINT_NOT 0
#define RND_START 17

// constructor
CUserIF::CUserIF()
{
	changed = FALSE;
	installed = FALSE;
};

// displays a menu and let the user chose
TAction CUserIF::Menu()
{
   char choise;
   char inStr[MAX_STR_LEN];
   do
   {
     cout << "\n\n";
     cout << "\n\nWelcome to the";
     cout << "\n         M O D U L A R  N E U R A L  N E T W O R K ";
     cout << "\n                                   	 User Interface!";
     cout << "\n\n-----------------------------------------------------------";
     cout <<   "\n   <N>ew network. User will be asked for parameters.";
     cout <<   "\n   <L>oad a network form a description-file.";
     cout <<   "\n   <S>tore the actuell network in a description-file.";

     cout << "\n\n   <T>rain the whole network on a data-file.";
     cout <<   "\n   <I>nput network training on a data-file.";
     cout <<   "\n   <D>ecision network training on a data-file.";

     cout << "\n\n   <P>erformance test of the network (on a data-file)";
     cout <<   "\n   <C>alculate outputs for given input file.";
     cout <<   "\n   <R>eset the weights of the actuell network.";

     cout << "\n\n   <H>elp gives help on data-file structure";
     cout << "\n\n   <Q>uit!";
     cout <<   "\n-----------------------------------------------------------";
     cout << "\n\n>>>";
     gets(inStr);
     choise = inStr[0];
     switch (choise)
     {
	case 'n': case 'N': return new_net;
			    break;
	case 'l': case 'L': return load;
			    break;
	case 's': case 'S': return store;
			    break;
	case 't': case 'T': return train;
			    break;
        case 'i': case 'I': return train_inp;
			    break;
        case 'd': case 'D': return train_dec;
			    break;
	case 'p': case 'P': return test;
			    break;

	case 'r': case 'R': return reset;
			    break;
	case 'c': case 'C': return work;
			    break;
	case 'h': case 'H': return help;
			    break;

	case 'q': case 'Q': return quit;
			    break;
	default:
		cout << "\n\n >>>>>> Not a valid choise !";
     }
   }
   while(TRUE); // This is not an infinite loop! Exit by return!
}

void CUserIF::LoadNet()
{
  char yes_no[MAX_STR_LEN] = "y";
  char desc_file[MAX_STR_LEN];
  char dir_name[MAX_STR_LEN];
  char log_file[MAX_STR_LEN];
  cout <<"\n\nLoad a Modular Neural Network from file:";
  if (changed == TRUE)
  {
    cout << "\n\nWARNING: The existing network has changes since last saving!";
    cout <<   "\n         If a new net is loaded this changes will be lost!";
    cout << "\n\n         Create new network anyway (y/n) ? [n]";
    cout <<   "\n         >>>";
    cin >>  yes_no;
  }
  if (yes_no[0] == 'y')
  {
    // read the filenames
    cout << "\n Name of the network description file: ";
    cin >> desc_file;
    cout << "\n Name of the dir: ";
    cin >> dir_name;
    cout << "\n Name of the log-output file         : ";
    cin >> log_file;

    // remove old network - if exists
    if (installed == TRUE)
    {
      m_net->CMul2L::~CMul2L();
    };

    // build a newnetwork from file
    m_net = new CMul2L(desc_file, dir_name, log_file);

    // set the flags
    changed = FALSE;
    installed = TRUE;
  }
}


void CUserIF::ResetNet()
{
  char yes_no[MAX_STR_LEN] = "y";
  char inStr[MAX_STR_LEN];
  double min,max;

  cout <<"\n\nReset the Neural Network:";

  // check if a network is installed
  if (installed == FALSE)
  {
    cout << "\n\nThere is no network loaded !!!";
    cout <<   "\nLoad or create an New Network first!!!";
    cout <<   "\nand try again!";
    return;
  }

  // check if the network was changed since last change
  if (changed == TRUE)
  {
    cout << "\n\nWARNING: The existing network has changes since last saving!";
    cout <<   "\n         If the weights are reseted this changes will bi lost!";
    cout << "\n\n         Reset the network anyway (y/n) ? [n]";
    cout <<   "\n         >>>";
    gets(yes_no);
  }

  if (yes_no[0] == 'y')
  {
    cout << "\nGive range for the initial weights:";
    cout << "\nMinimum [-1] ? ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%lf", &min) < 1) min = -1;
    cout <<"\nMaximum [1]   ? ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%lf", &max) < 1) max = 1;

    // reset the weights in the given range
    m_net->ResetWeights(min, max);
    // set the changed flag
    changed = TRUE;
 }
}


void CUserIF::StoreNet()
{
  char desc_file[MAX_STR_LEN];
  char dir_name[MAX_STR_LEN];
  cout <<"\n\nStore a Neural Network in a description file:";

  if (installed == FALSE)
  {
    cout << "\n\nThere is no network loaded !!!";
    cout <<   "\nLoad or create an New Network first !!!";
    cout <<   "\nand try again!";
    return;
  }

  // read the filename and directory
  cout << "\nNetwork description file:          ";
  cin >>  desc_file;
  cout << "\nNetwork directory: (to be created) ";
  cin >>  dir_name;


  // store the network to disk
  m_net->StoreNet(desc_file, dir_name);

  // set the flags
  changed = FALSE;
  installed = TRUE;
}

void CUserIF::TestNet()
{
  char data_file[MAX_STR_LEN];
  char inStr[MAX_STR_LEN];

  double diff;
  int displ;
  cout <<"\n\nTest the Modular Neural Network with a data-file:";

  if (installed == FALSE)
  {
    cout << "\n\nThere is no network loaded !!!";
    cout <<   "\nLoad or create an New Network first !!!";
    cout <<   "\nand try again!";
    return;
  }

  // read the parameters
  cout << "\nName of the data-file: ";
  cin >> data_file;
  cout << "\nConfidence (difference bewteen winner and runner-up) [0.01]? ";
  gets( inStr);
  // convert string in number, if string is no valid take default
  if (sscanf(inStr, "%lf", &diff) < 1) diff = 0.01;
  cout << "\nPrint the Desired and calculated output? (y/n) [n]";
  gets( inStr);
  // check string, if no yes than no!
  if (inStr[0] == 'y') displ = PRINT; else displ = PRINT_NOT;

  // call the test function
  m_net->Test(data_file, diff, displ);
}


void CUserIF::WorkNet()
{
  char in_file[MAX_STR_LEN],
       out_file[MAX_STR_LEN];
  char inStr[MAX_STR_LEN];
  int dft, displ;

  cout <<"\n\nCalculate the outputs for a file:";

  if (installed == FALSE)
  {
    cout << "\n\nThere is no network loaded !!!";
    cout <<   "\nLoad or create an New Network first!!!";
    cout <<   "\nand try again!";
    return;
  }

  cout << "\nName of the input file: ";
  cin >> in_file;
  cout << "\nName of the output file: ";
  cin >> out_file;

  cout << "\nType of the data file (long/short)?  [s]";
  gets( inStr);
  // check string, if no yes than no!
  if (inStr[0] == 'l') dft = 0; else dft = 1;

  cout << "\nPrint the Desired and calclated output? (y/n) [n]";
  gets( inStr);
  // check string, if no yes than no!
  if (inStr[0] == 'y') displ = PRINT; else displ = PRINT_NOT;

  // call the calculation function
  m_net->Work(in_file, out_file, dft, displ);
}


void CUserIF::NewNet()
{
  char inStr[MAX_STR_LEN];
  char logname[MAX_STR_LEN];
  char yes_no[MAX_STR_LEN] = "y";
  TNetDef  *netL1 = new TNetDef;
  TNetDef *net_m = new TNetDef;
  int i, cl, in, rnd_start, tempInt;
  TOutRep inter_repres;
  double tempDouble;

  cout <<"\n\nSetup a new Neural Network:";
  if (changed == TRUE)
  {
    cout << "\n\nWARNING: The existing network has changes since last saving!";
    cout <<   "\n         If a new net is created this changes will bi lost!";
    cout << "\n\n         Create new network anyway (y/n) ? [n]";
    cout <<   "\n         >>>";
    gets(yes_no);
  }
  if (yes_no[0] == 'y')
  {
    cout << "\n--- Modular Network Parameter: --- ";
    cout << "\n Number of inputs     : "; cin >> in;
    cout << "\n Number of classes    : "; cin >> cl;
    cout << "\n Intermediate represenation? (long, short) [short] : ";
    gets(inStr);
    if (inStr[0] == 'l')
	inter_repres = big;
    else
	inter_repres = small;
    cout << "\n Code for the mapping (0=lin, >1 = RND) [RND]: ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%i", &rnd_start) < 1) rnd_start = RND_START;

    cout << "\n Name of the logfile? [multi.log] ";
    gets(logname);
    if (strcmp(logname, "") == 0) strcpy(logname, "multi.log");

    cout << "\n\n\n First Net Layer:";
    cout << "\n Number of inputs per net    : ";
    cin >> netL1->no_inputs;
    cout << "\n Number of layers per net (2..5) [2]  : ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%i", &tempInt) < 1) tempInt = 2;
    netL1->no_layers = tempInt;
    if(netL1->no_layers>5 || netL1->no_layers < 2)
    {
      cout << "\n\nWARNING: Valid Number of Layers: 2 to 5.";
      cout <<   "\n         Set to default value (2)!";
      netL1->no_layers = 2;
    }

    cout << "\n Lambda value (0.1 .. 3)    [1]  : ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%lf", &tempDouble) < 1) tempDouble = 1;
    netL1->lambda = tempDouble;

    netL1->fct = uni_pol;
    for(i=0;i<5;i++) netL1->neuronL[i]=0; //Reset Neuron Number;
    for(i=0;i<netL1->no_layers-1;i++)
    {
      cout << "\n Neurons in 1st netlayer in layer " << i << " [4] : ";
      gets( inStr);
      // convert string in number, if string is no valid take default
      if (sscanf(inStr, "%i", &tempInt) < 1) tempInt = 4;
      netL1->neuronL[i] = tempInt;
    }

    cout << "\n\n\n Main Net Layer:";
    cout << "\n Number of layers in main net   [2] : ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%i", &tempInt) < 1) tempInt = 2;

    net_m->no_layers = tempInt;
    if(net_m->no_layers>5 || net_m->no_layers < 2)
    {
      cout << "\n\nWARNING: Valid Number of Layers: 2 to 5.";
      cout <<   "\n         Set to default value (2)!";
      net_m->no_layers = 2;
    }
    cout << "\n Lambda value (0.1 .. 3)     [1]  : ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%lf", &tempDouble) < 1) tempDouble = 1;
    net_m->lambda = tempDouble;

    net_m->fct = uni_pol;
    for(i=0;i<5;i++) net_m->neuronL[i]=0; //Reset Neuron Number;
    for(i=0;i<net_m->no_layers-1;i++)
    {
      cout << "\n Neurons in main net in layer "  << i << " [4] : ";
      gets( inStr);
      // convert string in number, if string is no valid take default
      if (sscanf(inStr, "%i", &tempInt) < 1) tempInt = 4;
      net_m->neuronL[i] = tempInt;
    }

    // if a network is installed delete it
    if (installed == TRUE)
    {
      m_net->CMul2L::~CMul2L();
    };

    // set up the network
    m_net = new CMul2L(in, cl, netL1, net_m,
		       logname, rnd_start, inter_repres);

    // free the memory for the input structures
    delete net_m;
    delete netL1;

    // set the flags
    changed = TRUE;
    installed = TRUE;
  }
}

void CUserIF::TrainNet()
{
  char yes_no[MAX_STR_LEN] = "y";
  char err_file1[MAX_STR_LEN],
       err_filem[MAX_STR_LEN],
       data_file[MAX_STR_LEN],
       inStr[MAX_STR_LEN];
  double eta, max_err1, max_errm, alpha;
  int steps1, stepsm;

  cout <<"\n\nTrain the Neural Network on a data-file:";

  if (installed == FALSE)
  {
    cout << "\n\nThere is no network loaded !!!";
    cout <<   "\nLoad or create an New Network first !!!";
    cout <<   "\nand try again!";
    return;
  }

  if (changed == TRUE)
  {
    cout << "\n\nWARNING: The existing network has changes since last saving!";
    cout <<   "\n         If the net is trained this changes will bi lost!";
    cout << "\n\n         Overwrite the weights anyway (y/n) ? [n]";
    cout <<   "\n         >>>";
    gets(yes_no);
  }
  if (yes_no[0] == 'y')
  {
    cout << "\n--- Learning Parameter: --- ";
    cout << "\nName of the data-file? ";
    cin >> data_file;
    cout << "\nLearning constant eta [1]? ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%lf", &eta) < 1) eta = 1;

    cout << "\nFactor for old delta weights (momentum) [0]? ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%lf", &alpha) < 1) alpha = 0;

    cout << "\nAccepted error in  1st net(0.0 - 0.2) [0.01] ? ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%lf", &max_err1) < 1) max_err1 = 0.01;

    cout << "\nAccepted error in  main net(0.0 - 0.2) [0.01] ? ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%lf", &max_errm) < 1) max_errm = 0.01;

    cout << "\nNumber of steps 1st net (maximum) [1000] ? ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%i", &steps1) < 1) steps1 = 1000;

    cout << "\nNumber of steps main net (maximum) [1000] ? ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%i", &stepsm) < 1) stepsm = 1000;

    cout << "\nName of the error-file for the 1st net? [input.err]     ";
    gets( err_file1);
    if (strcmp(err_file1, "") == 0) strcpy(err_file1, "input.err");
    cout << "\nName of the error-file for the main net? [decision.err] ";
    gets( err_filem);
    if (strcmp(err_filem, "") == 0) strcpy(err_filem, "decision.err");

    // call the training function
    m_net->Train(data_file,
		 steps1, max_err1,
		 stepsm, max_errm,
		 err_file1, err_filem,
		 eta, alpha);

    // set the cahnged flag
    changed = TRUE;
  }
}

void CUserIF::TrainInputNet()
{
  char yes_no[MAX_STR_LEN] = "y";
  char err_file1[MAX_STR_LEN],
       data_file[MAX_STR_LEN],
       inStr[MAX_STR_LEN];
  double eta, max_err1, alpha;
  int steps1;
  cout <<"\n\nTrain Input Layer of the Modular Neural Network on a data-file:";

  if (installed == FALSE)
  {
    cout << "\n\nThere is no network loaded !!!";
    cout <<   "\nLoad or create an New Network first !!!";
    cout <<   "\nand try again!";
    return;
  }

  if (changed == TRUE)
  {
    cout << "\n\nWARNING: The existing network has changes since last saving!";
    cout <<   "\n         If the net is trained this changes will bi lost!";
    cout << "\n\n         Overwrite the weights anyway (y/n) ? [n]";
    cout <<   "\n         >>>";
    gets(yes_no);
  }
  if (yes_no[0] == 'y')
  {
    cout << "\n--- Learning Parameter: --- ";
    cout << "\nName of the data-file? ";
    cin >> data_file;
    cout << "\nLearning constant eta [1]? ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%lf", &eta) < 1) eta = 1;

    cout << "\nFactor for old delta weights (momentum) [0]? ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%lf", &alpha) < 1) alpha = 0;

    cout << "\nAccepted error in  1st net(0.0 - 0.2) [0.01] ? ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%lf", &max_err1) <1) max_err1 = 0.01;

    cout << "\nNumber of steps 1st net (maximum) [1000] ? ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%i", &steps1) <1) steps1 = 1000;

    cout << "\nName of the error-file for the 1st net? [input.err]     ";
    gets( err_file1);
    if (strcmp(err_file1, "") == 0) strcpy(err_file1, "input.err");

    // call the training function for the input layer
    m_net->TrainL1(data_file, steps1, max_err1, err_file1, eta, alpha);

    // set the cahnged flag
    changed = TRUE;
  }
}



void CUserIF::TrainDecisionNet()
{
  char yes_no[MAX_STR_LEN] = "y";
  char err_filem[MAX_STR_LEN],
       data_file[MAX_STR_LEN],
       inStr[MAX_STR_LEN];
  double eta, max_errm, alpha;
  int stepsm;

  cout <<"\n\nTrain the Neural Network on a data-file:";

  if (installed == FALSE)
  {
    cout << "\n\nThere is no network loaded !!!";
    cout <<   "\nLoad or create an New Network first !!!";
    cout <<   "\nand try again!";
    return;
  }

  if (changed == TRUE)
  {
    cout << "\n\nWARNING: The existing network has changes since last saving!";
    cout <<   "\n         If the net is trained this changes will bi lost!";
    cout << "\n\n         Overwrite the weights anyway (y/n) ? [n]";
    cout <<   "\n         >>>";
    gets(yes_no);
  }
  if (yes_no[0] == 'y')
  {
    cout << "\n--- Learning Parameter: --- ";
    cout << "\nName of the data-file? ";
    cin >> data_file;
    cout << "\nLearning constant eta [1]? ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%lf", &eta) < 1) eta = 1;

    cout << "\nFactor for old delta weights (momentum) [0]? ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%lf", &alpha) < 1) alpha = 0;

    cout << "\nAccepted error in  main net(0.0 - 0.2) [0.01] ? ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%lf", &max_errm) < 1) max_errm = 0.01;

    cout << "\nNumber of steps main net (maximum) [1000] ? ";
    gets( inStr);
    // convert string in number, if string is no valid take default
    if (sscanf(inStr, "%i", &stepsm) < 1) stepsm = 1000;

    cout << "\nName of the error-file for the main net? [decision.err] ";
    gets( err_filem);
    if (strcmp(err_filem, "") == 0) strcpy(err_filem, "decision.err");

    // call the training function for the decision network
    m_net->Train_m(data_file, stepsm, max_errm, err_filem, eta, alpha);

    // set the cahnged flag
    changed = TRUE;
  }
}


void CUserIF::HelpNet()
{
  char yes_no[MAX_STR_LEN];
  cout << "\n\nH E L P  on the file structures for this program!";
  cout << "\n\n* The data file: (for training and testing)";
  cout <<   "\n  For each recored one line is used. First there are the";
  cout <<   "\n  input values separetated by <SPACE>. Then a ':' follows.";
  cout <<   "\n  after this the output values are placed. The line is ended";
  cout <<   "\n  by a ';'. The last line is ended by a '.'.";
  cout <<   "\n  example:     1 -0.6 2.2 0.888 -1 : 1 0 1;";
  cout <<   "\n               ....";
  cout <<   "\n               3.2 -1 0.5 -1.1 -2.1 : 0 0 1.";
  cout << "\n\n* The work file: (for calculating the output)";
  cout <<   "\n  For each recored one line is used. First there are the";
  cout <<   "\n  input values separetated by <SPACE>. The line is ended";
  cout <<   "\n  by a ';'. The last line is ended by a '.'.";
  cout <<   "\n  example:     1 -0.6 0.2 0.888 -1 ;";
  cout <<   "\n               ....";
  cout <<   "\n               -.2 -1 0.5 -1.0 -0.1 .";
  cout <<   "\n\n\nPress >RETURN< for the menu! ";
  gets(yes_no);
}

void CUserIF::QuitNet()
{
  char yes_no[MAX_STR_LEN] = "y";
  cout <<"\n\nQuit this program:";
  if (changed == TRUE)
  {
    cout << "\n\nWARNING: The existing network has changes since last saving!";
    cout <<   "\n         All this changes will be lost!";
    cout << "\n\n         Quit anyway (y/n) ? [n]";
    cout <<   "\n         >>>";
    gets(yes_no);
  }
  if (yes_no[0] == 'y')
  {
    cout << "\n\nBYE !!!\n\n";
    // call the destructor for the net
    if (installed == TRUE)
    {
      m_net->CMul2L::~CMul2L();
    };
    exit(1);
  }
}


void CUserIF::Handle(TAction action)
{
	switch (action)
	{
	  case new_net:   NewNet();
			  break;
	  case load:      LoadNet();
			  break;
	  case store:     StoreNet();
			  break;
	  case train:     TrainNet();
			  break;
	  case train_inp: TrainInputNet();
			  break;
	  case train_dec: TrainDecisionNet();
			  break;
	  case test:      TestNet();
			  break;
          case reset:     ResetNet();
			  break;
          case work:      WorkNet();
                          break;
          case help:      HelpNet();
                          break;
	  case quit:      QuitNet();
                          break;
	}
}
