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

        Final Project                                 MMU 1996

        ######################################################
        #                                                    #
        #               A Modular Neural Network             #   
        #                                                    #
        #         The monolithic network User interface      #   
        #                                                    #
        ######################################################

        Albrecht Schmidt                              17.09.96

        FILE: CBPUI.C                              Version 1.0

   ************************************************************* */
#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>

#include "CBPUI.h"

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

// displays a menu and let the user chose
TAction CBPUserIF::Menu()
{
   char choise;
   char inStr[MAX_STR_LEN];
   do
   {
     cout << "\n\nWelcome to the  N E U R A L  N E T W O R K  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 network on a data-file.";
     cout <<   "\n   <P>erformance test of the network (on a data-file)";
     cout <<   "\n   <R>eset the weights of the actuell network.";

     cout << "\n\n   <C>alculate outputs for given input file.";

     cout << "\n\n   <H>elp gives help on data-file and";
     cout <<   "\n          desciption-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 '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 CBPUserIF::LoadNet()
{
	char yes_no[MAX_STR_LEN] = "y";
	char desc_file[MAX_STR_LEN],
	     log_file[MAX_STR_LEN];
	cout <<"\n\nLoad a 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 bi lost!";
		cout << "\n\n         Create new network anyway (y/n) ?";
		cout <<   "\n         >>>";
		cin >> yes_no;
	}
	if (yes_no[0] == 'y')
	{
		cout << "\n Network description file: ";
		cin >> desc_file;
		cout << "\n Logfile for this session: ";
		cin >> log_file;
		if (installed == TRUE)
		{
			network->CBackPro::~CBackPro();
		};
		network = new CBackPro(desc_file, log_file);
		changed = FALSE;
		installed = TRUE;
	}
}

void CBPUserIF::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";
		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) ?";
		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
		network->ResetWeights(min, max);
		changed = TRUE;
	}
}


void CBPUserIF::StoreNet()
{
	char desc_file[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";
		cout <<   "\nand try again!";
		return;
	}

	cout << "\nNetwork description file: ";
	cin >> desc_file;
	network->StoreNet(desc_file);
	changed = FALSE;
}

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

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

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

	cout << "\nName of the data-file: ";
	cin >> data_file;
	cout << "\nAccepted difference [0.5]? ";
	gets( inStr);
  	// convert string in number, if string is no valid take default
  	if (sscanf(inStr, "%lf", &diff) < 1) diff = 0.5;

	network->Test(data_file, diff);
}

void CBPUserIF::WorkNet()
{
	char in_file[MAX_STR_LEN],
	     out_file[MAX_STR_LEN];
	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";
		cout <<   "\nand try again!";
		return;
	}

	cout << "\nName of the input file: ";
	cin >> in_file;
	cout << "\nName of the output file: ";
	cin >> out_file;
	network->Work(in_file, out_file);
}



void CBPUserIF::NewNet()
{
	char inStr[MAX_STR_LEN];
	char yes_no[MAX_STR_LEN] = "y";
	char bi_uni;
	char log_file[MAX_STR_LEN];
	int i, no_ins, no_layers;
	int no_neurons[5];
	double lambda;
	TFunction function;

	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) ?";
		cout <<   "\n         >>>";
		cin >> yes_no;
	}
	if (yes_no[0] == 'y')
	{
		cout << "\n--- Network Parameter: --- ";
		cout << "\nNumber of inputs? ";
		cin >> no_ins;
		cout << "\n Number of layers (2..5) [3]  : ";
    		gets( inStr);
    		// convert string in number, if string is no valid take default
    		if (sscanf(inStr, "%i", &no_layers) < 1) no_layers = 3;
		if(no_layers>5)
		{
			cout << "\n\nWARNING: Set the Number of Layers to 5.";
			cout <<   "\n         This is the Maximum value!";
			no_layers = 5;
		}
		for(i=0;i<5;i++) no_neurons[i]=0; //Reset Neuron Number;
		for(i=0;i<no_layers-1;i++)
		{
			cout << "\nNumber of Neuerons in the " << i+1 ;
			cout << ". Layer? [4]";
  			gets( inStr);
      			// convert string in number, 
			// if string is no valid take default
      			if (sscanf(inStr, "%i", &no_neurons[i]) < 1) 
                                                          no_neurons[i] = 4;
		}
	        cout << "\nNumber of Neuerons in the " << no_layers ;
                cout << ". Layer = Number of outputs ? ";
                gets( inStr); 
                // convert string in number
                if (sscanf(inStr, "%i", &no_neurons[no_layers-1]) < 1) 
		{
			cout << "\n\nWARNING: Set the Number of Output neurons ";
			cout <<  "to 1 -- is this correct with the data set?\n";
                	no_neurons[no_layers-1]= 1;
		}
    		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", &lambda) < 1) lambda = 1;
		do
		{
		  cout << "\nActivation function (b=bi-polar, u=uni-polar)? ";
		  cin >> bi_uni;
		}
		while (bi_uni != 'b' && bi_uni != 'u');
		if (bi_uni == 'b')
			function = bi_pol; else function = uni_pol;
		cout << "\nLogfile for this session: ";
		cin >> log_file;
		if (installed == TRUE)
		{
			network->CBackPro::~CBackPro();
		};
		network = new CBackPro  (no_ins, no_layers,lambda, function,
					 log_file, no_neurons[0],
					 no_neurons[1], no_neurons[2],
					 no_neurons[3], no_neurons[4]);
 		changed = TRUE;
		installed = TRUE;
	}
}


void CBPUserIF::TrainNet()
{
	char yes_no[MAX_STR_LEN] = "y";
	char err_file[MAX_STR_LEN],
	     inStr[MAX_STR_LEN],
	     data_file[MAX_STR_LEN];
	double eta, max_err, alpha;
	int steps;

	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";
		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) ?";
		cout <<   "\n         >>>";
		cin >> 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 (0.0 - 0.2) [0.01] ? ";
    		gets( inStr);
    		// convert string in number, if string is no valid take default
    		if (sscanf(inStr, "%lf", &max_err) < 1) max_err = 0.01;
   		cout << "\nNumber of steps (maximum) [1000] ? ";
    		gets( inStr);
    		// convert string in number, if string is no valid take default
    		if (sscanf(inStr, "%i", &steps) < 1) steps = 1000;
 
		cout << "\nName of the error-file? [bpnet.err]     ";
    		gets( err_file);
    		if (strcmp(err_file, "") == 0) strcpy(err_file, "bpnet.err");

		network->Train(eta, max_err, data_file, steps, err_file, alpha);
		changed = TRUE;
	}
}

void CBPUserIF::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 2.2 0.888 -1 ;";
  cout <<   "\n               ....";
  cout <<   "\n               3.2 -1 0.5 -1.1 -2.1 .";
  cout <<   "\n\n\nPress >RETURN< for the menu! ";
  gets(yes_no);
}

void CBPUserIF::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) ?";
		cout <<   "\n         >>>";
		cin >> yes_no;
	}
	if (yes_no[0] == 'y')
	{
		cout << "\n\nBYE !!!\n\n";
		if (installed == TRUE)
		{
			network->CBackPro::~CBackPro();
		};
		exit(1);
	}
}


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