// Name:     Micheal H. McCabe
// Date:     April 20, 2009
// Program:  Calculator V10 / Modular Version
// Filename: calc_functions.cpp

#include "calc.h"

/*----------------------------------------------------------------------------*/
/*      This is the "simple add" function that adds N1 and N2                 */
/*----------------------------------------------------------------------------*/

int add(NewDataView& Data)
{
	Data.Last_Result = Data.N1 + Data.N2;
	return 0;
}

/*----------------------------------------------------------------------------*/
/*      This is the "simple sub" function that subtracts N2 from N1           */
/*----------------------------------------------------------------------------*/

int sub(NewDataView& Data)
{
	Data.Last_Result = Data.N1 - Data.N2;
	return 0;
}

/*----------------------------------------------------------------------------*/
/*     This is the "simple mult" function that multiplies N1 by N2            */
/*----------------------------------------------------------------------------*/

int mult(NewDataView& Data)
{
	Data.Last_Result = Data.N1 * Data.N2;
	return 0;
}

/*----------------------------------------------------------------------------*/
/*     This is the "simple div" function that divides N1 by N2                */
/*----------------------------------------------------------------------------*/

int div(NewDataView& Data)
{
	if (Data.N2==0)
		{cout << "Error! Division by zero is annoying. \n"; return -1;}
	Data.Last_Result = Data.N1 / Data.N2;
	return 0;
}

/*----------------------------------------------------------------------------*/
/*     This is the "exponent" function that raises N1 to the N2  power        */
/*----------------------------------------------------------------------------*/

int exponent(NewDataView& Data)
{
	Data.Last_Result = pow(Data.N1,Data.N2);
	return 0;
}

/*----------------------------------------------------------------------------*/
/*     This is the "simple mod" function that divides N1 by N2                */
/*----------------------------------------------------------------------------*/

int mod(NewDataView& Data)
{
	if (Data.N2==0)
		{cout << "Error! Division by zero is annoying. \n"; return -1;}
	Data.Last_Result = (int)Data.N1 % (int)Data.N2;
	return 0;
}

/*----------------------------------------------------------------------------*/
/*      This is the "sum" function that adds element j through element k      */
/*----------------------------------------------------------------------------*/

int sum(NewDataView& Data)
{
	int i;
	if (Data.Used==0) 
		{cout << "Error! No Data in the silly array. \n"; return -1;}
	Data.Last_Result=0;
	for (i=0; i<=Data.Used-1; i++)
		Data.Last_Result = Data.Last_Result + Data.Array[i];
	return 0;
}

/*----------------------------------------------------------------------------*/
/*   This is the "product" function that multiplies element j thru element l  */
/*----------------------------------------------------------------------------*/

int product(NewDataView& Data)
{
	int i;
	if (Data.Used==0) 
		{cout << "Error! No Data in the silly array. \n"; return -1;}
	Data.Last_Result=1;
	for (i=0; i<=Data.Used-1; i++)
		Data.Last_Result = Data.Last_Result * Data.Array[i];
	return 0;
}

/*----------------------------------------------------------------------------*/
/*   This is the "mean" function that finds the arithmetic mean of array      */
/*----------------------------------------------------------------------------*/

int mean(NewDataView& Data)
{
	int i;
	if (Data.Used==0) 
		{cout << "Error! No Data in the silly array. \n"; return -1;}
	Data.Last_Result=0;
	for (i=0; i<=Data.Used-1; i++)
		Data.Last_Result = Data.Last_Result + Data.Array[i];
	Data.Last_Result = Data.Last_Result / (Data.Used);
	return 0;
}

/*----------------------------------------------------------------------------*/
/*   This is the "deviant" function that finds the standard deviation         */
/*----------------------------------------------------------------------------*/

int deviant(NewDataView& Data)
{
	if (Data.Used==0) 
		{cout << "Error! No Data.  Pervert. \n"; return -1;}
	float list_mean;
        float td=0;
        int i=0;
        // My understanding of statistics is a little rusty, so bear with me!
        // First we gotta find the mean...
        mean(Data);
	list_mean = Data.Last_Result;
        // Now we gotta find the difference from the mean for each element,
        // square the difference, and total the squared differences.
        for (i=0; i<=Data.Used-1; i++)
           td=td+pow(fabs(Data.Array[i]-list_mean),2);
        // divide that by the number of elements in the list and take the square
        // root -- then we're done!
        Data.Last_Result=sqrt(td/(Data.Used-1));
        return 0;
}

/*----------------------------------------------------------------------------*/
/*	This is the factorial function that calculates N! via iteration       */
/*----------------------------------------------------------------------------*/
                                
double long factorial(int x)      // This function implements the n-factorial
                                  // operation using an iterative algorithm.
{
       double long temp = (double long) abs(x); // Allocate storage for our 
                                                // argument and stuff it
                                                // with the absolute value of
                                                // the integer we were given as
                                                // input.
                                                
       double long fact = 1;      // This is our accumulator where the result
                                  // will be developed over the course of the
                                  // while loop that follows.
       
       while (temp>1)             // While temp is >1, keep on truckin'.
             {
             fact = fact * temp;  // Self explanatory multiplication.
             temp --;             // Decrement the loop counter.
             }                    // This is really a GOTO, hidden from Dijkstra
                                  // for its own protection.
       if (x<0)                   // If X was negative, we need to change the
             fact = -fact;        // sign of our result back to negative.
       return fact;               // Home again, Home Again, Jiggity Jig!
}

/*----------------------------------------------------------------------------*/
/*	This function reads data into the list from a file                    */
/*----------------------------------------------------------------------------*/

int ReadInputFile(NewDataView& Data)
{
    ifstream InFileDesc;
    string Filename="";
    char response;
    int start;
    float value;
    bool Read_ok = true;
    int count=-1;
	

	cout << Data.Used << " Records in array. \n";
	
	if (Data.Used != 0)
		{
		cout << "Append (A) or Replace (R)? ";
		cin >> response;
		if (response=='A') start=Data.Used;
		else 
			{
			start=0;
			Data.Used=0;
			}
		}


    while (Filename == "")
          {
          cout << "Enter File Name to read: ";
          cin >> Filename;
          if (Filename == "Cancel")
             {
             Read_ok = false;
             break;
             }
             }
    if (Read_ok)
       {
       InFileDesc.open(Filename.c_str());
       if (InFileDesc)
          {
          // File Open
          while (!InFileDesc.eof())
                {
                InFileDesc >> value;
                if (InFileDesc.fail())
                   {
                   // Non-Numeric Encountered
                   InFileDesc.clear();
                   InFileDesc.ignore(100,'\n');
                   }
                else
                    // We have a numeric
                    {
                    count++;
                    if ((Data.Used+count) < MAX_USER_LIST)
                       {
                       Data.Array[Data.Used+count] = value;
                       InFileDesc.ignore(100,'\n');
                       }
                    else
                        {
                        cout << "Array is Full \n";
                        count--;
                        break;
                        }
                        }
                        }
                        }
       InFileDesc.close();
       }
Data.Used=Data.Used+count+1;
cout << "Read in " << (count+1) << " values from " << Filename << endl;
cin.ignore(80,'\n');
return 0;
}

/*----------------------------------------------------------------------------*/
/*	This function writes the user data list into a file                   */
/*----------------------------------------------------------------------------*/

int WriteOutputFile(NewDataView& Data)
	{
	string Filename;
	bool Read_ok;
	int i;
	int return_value;
	ofstream outputfile;
	while (Filename == "")
		{
		cout << "Enter File Name to write: ";
		cin >> Filename;
		cout << endl;
		if (Filename == "Cancel")
			{
			Read_ok = false;
			break;
			}
		}
	outputfile.open(Filename.c_str());
	if (outputfile.is_open())
          	{
          	cout << "Writing " << Data.Used << " records to disk." << endl;
          	for (i=0; i<=Data.Used-1; i++)
              		{
              		outputfile << Data.Array[i] << endl;
              		}
              	outputfile.close();
		return_value=1;
         	}
       else
		{
		cout << "WTF?  Output file could not be opened! \n";
		return_value=-1;
		}           
	cin.ignore(80,'\n');
	return return_value;
	}

/*----------------------------------------------------------------------------*/
/*	This is a simple routine to list all program data                     */
/*----------------------------------------------------------------------------*/

void list_data(NewDataView& Data)
{
	int i;
	cout << setw(10) << fixed << setprecision(4); 
	cout << "Number of Records in Data List:  " << Data.Used << endl;
	cout << "Value Stored in N1:              " << Data.N1 << endl;
	cout << "Value Stored in N2:              " << Data.N2 << endl;
	cout << "Last Result:                     " << Data.Last_Result << endl;
	for (i=0; i<=Data.Used-1; i++)
		{
		cout << i << " : " << Data.Array[i] << endl;
		}
	return;
}


/*----------------------------------------------------------------------------*/
/*	This is the get_numeric routine provided by Dr. Schuyler              */
/*----------------------------------------------------------------------------*/

bool get_numeric(string prompt, string stop, float& output)
{
     bool get_it = true;           // This flag controls the while loop
                                   // executed below.
     
     bool got_one = false;         // Another flag - if set true on return
                                   // indicates a successful numeric value
                                   // stored at the address of output.
                                     
     string temp="";               // A place to store the input string.
     
     float value=0;                // Intermediate result -- stores a numeric
                                   // entry until passed out to the address
                                   // of output.
     
     while (get_it)                // Do this loop while get_it remains true.
           {
           if (prompt !="")        // If the prompt string is not null,
              cout << prompt;      // send the prompt to standard output.
              
           cin >> temp;            // Grab something from standard input.
           
           if (temp==stop)         // If the input is equal to the 'stop' value,
              get_it = false;      // set the control flag to false (in order
                                   // to end the loop after this iteration.)
                
           else {
                istringstream in_stream(temp);  // More black magic from Bell...
                in_stream >> value;             // See following block for an
                                                // interpretation of how I think
                                                // it works!
                                                
                // We're simulating a file operation here, effectively writing
                // out the string we just obtained to a "string stream" and then
                // immediately bringing that data back in as a numeric value.
                
                if (!in_stream)                  // Did it not work?
                   {
                   cout << "Bad entry: (enter " << stop << " to cancel) \n";
                   continue;
                   }
                else                            // Okay, it did work.
                   {
                   output = value;              // Store our value in output.
                   get_it = false;              // Reset the control flag.
                   got_one = true;              // Set out success flag.
                   break;                       // Get out of the current block.
                   }                            
                }                               
           }
     cin.ignore(80,'\n');   
     return got_one;                            // Return from the procedure.
}


/*----------------------------------------------------------------------------*/
/*	This routine prompts the user for N1 and N2 values and accepts them   */
/*----------------------------------------------------------------------------*/

void getN1N2(NewDataView& Data)
{
	float value;
	string prompt = "Please enter a value for N1: ";
	get_numeric(prompt, "Q", value);
	Data.N1=value;
	prompt = "Please enter a value for N2: ";
	get_numeric(prompt, "Q", value);
	Data.N2=value;
	return;
}

/*----------------------------------------------------------------------------*/
/*	This function clears the data list and resets the count to zero       */
/*----------------------------------------------------------------------------*/

void clearl(NewDataView& Data)
{
	int i;
	for (i=0; i<=Data.Used; i++)
		Data.Array[i]=0;
	Data.Used=0;
	return;
}

/*----------------------------------------------------------------------------*/
/*	This function clears only the N1, N2, and Last_Result Values          */
/*----------------------------------------------------------------------------*/

void clearn(NewDataView& Data)
{
	Data.N1 = 0;
	Data.N2 = 0;
	Data.Last_Result=0;
	return;
}

/*----------------------------------------------------------------------------*/
/*	This function displays the help screen                                */
/*----------------------------------------------------------------------------*/

void helpscreen()
{
cout <<  HELP_e;
cout <<  HELP_i;
cout <<  HELP_fi;
cout <<  HELP_fo;
cout <<  HELP_plus;
cout <<  HELP_minus;
cout <<  HELP_star;
cout <<  HELP_slash;
cout <<  HELP_caret;
cout <<  HELP_exclaim;
cout <<  HELP_c;
cout <<  HELP_cL;
cout <<  HELP_h;
cout <<  HELP_l;
cout <<  HELP_q;
cout <<  HELP_o;
cout <<  HELP_a;
cout <<  HELP_d;
cout <<  HELP_m;
cout <<  HELP_s;
cout <<  HELP_sd;
cout <<  HELP_p;
cout <<  HELP_M1;
cout <<  HELP_M2;
cout <<  HELP_N1;
cout <<  HELP_N2;
cout <<  HELP_i;
return;
}

/*----------------------------------------------------------------------------*/
/*	This function displays the result of the last calculation             */
/*----------------------------------------------------------------------------*/

void output_last(NewDataView& Data)
{
	cout << "The result of the last calculation was: " << Data.Last_Result << endl;
	return;
}

/*----------------------------------------------------------------------------*/
/*	This function adds items to the list interactively                    */
/*----------------------------------------------------------------------------*/

void GetArray(NewDataView& Data)
{
	int start=0;
	char response;
	bool continue_entry=true;
	float value;
	bool j;
	cout << Data.Used << " Records in array. \n";
	
	if (Data.Used != 0)
		{
		cout << "Append (A) or Replace (R)? \n";
		cin >> response;
		if (response=='A') start=Data.Used;
		else start=0;
		}

	while (continue_entry)
		{
		cout << start << "(" << Data.Array[start] << ")";
		j=get_numeric(" --->","quit",value);
		if (j)
			{
			Data.Array[start]=value;
			start++;
			}
		else
			{
			continue_entry=false;
			}
		}
	Data.Used=start;
	return;
}

/*----------------------------------------------------------------------------*/
/*	This function displays the files in the current linux directory       */
/*      Please note this is platform dependant and will not work on DOS       */
/*----------------------------------------------------------------------------*/
     
     int directory()
     	{
       	cout << "\nFiles in the current Linux Directory: \n \n:";
       	DIR *dp;
      	struct dirent *ep;
       	dp = opendir ("./");
      	if (dp != NULL)
       		{
           	while ((ep = readdir (dp)))
			{
             		puts (ep->d_name);
			}
           	(void) closedir (dp);
         	}
       	else
         	perror ("Couldn't open the directory");
	cout << endl;
       	return 0;
    	}

/*----------------------------------------------------------------------------*/
/* 	Function GetNumArg -- gets a numeric argument from command line       */
/*----------------------------------------------------------------------------*/

	int GetNumArg (string command_line)
		{
		string temp;
		int value;
		temp=command_line.substr(1,command_line.length()-1);
		istringstream in_stream(temp);  
                in_stream >> value;             
                if (!in_stream)
                   {
                   cout << "Bad Parameter! \a \n";
                   }
		return value;
		}

/*----------------------------------------------------------------------------*/
/*	This function deletes an element of the data list                     */
/*----------------------------------------------------------------------------*/

	int deletelist(int p, NewDataView& Data)
		{
		int c;
		if (p>=0 and (p<=Data.Used-1))
			{
			for (c=p; c<=(Data.Used-1); c++)
				Data.Array[c]=Data.Array[c+1];
			Data.Used=Data.Used-1;
			}
		else
			{
			cout << "Out of bounds error! \n";
			}
		return 0;
		}

/*----------------------------------------------------------------------------*/
/*	This function copies the result into an element of the data list      */
/*----------------------------------------------------------------------------*/

	int moveresult(int p, NewDataView& Data)
		{
		Data.Array[p]=Data.Last_Result;
		if (p>=Data.Used-1) Data.Used=p+1;
		return 0;
		}
/*----------------------------------------------------------------------------*/
/*	This is a group of functions to handle the M1/M2 N1/N2 commands       */
/*----------------------------------------------------------------------------*/
	void storen1(NewDataView& Data)
		{
		float temp;
		get_numeric("Index No? ","quit",temp);
		Data.Array[(int)temp]=Data.N1;
		if (temp>=Data.Used-1) Data.Used=temp+1;
		return;
		}
	void storen2(NewDataView& Data)
		{
		float temp;
		get_numeric("Index No? ","quit",temp);
		Data.Array[(int)temp]=Data.N2;
		if (temp>=Data.Used-1) Data.Used=temp+1;
		return;
		}
	void loadn1(NewDataView& Data)
		{
		float temp;
		get_numeric("Index No? ","quit",temp);
		Data.N1=Data.Array[(int)temp];
		return;
		}
	void loadn2(NewDataView& Data)
		{
		float temp;
		get_numeric("Index No? ","quit",temp);
		Data.N2=Data.Array[(int)temp];
		return;
		}
/*----------------------------------------------------------------------------*/



	

