// Program Name:  Cheap Banker
// Programmer: Mark Dehus
// Assignment Number: Project 3
// Purpose: To write a program that uses the bankers algorithm

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include "process.h"

using namespace std;

int A,B,C,D;
int req;

int run_request(Process proc[], int NUM_PROC)
{
	if (proc[req - 1].req_a <= proc[req - 1].need_a 
 		&& proc[req - 1].req_b <= proc[req - 1].need_b
 		&& proc[req - 1].req_c <= proc[req - 1].need_c
 		&& proc[req - 1].req_d <= proc[req - 1].need_d
   		&& proc[req - 1].req_a <= A
   		&& proc[req - 1].req_b <= B
     	&& proc[req - 1].req_c <= C
      	&& proc[req - 1].req_d <= D){
 		// Adjust allocation
 		proc[req - 1].a += proc[req - 1].req_a;
 		proc[req - 1].b += proc[req - 1].req_b;
 		proc[req - 1].c += proc[req - 1].req_c;
 		proc[req - 1].d += proc[req - 1].req_d;	
	} else {
		cout << "P" << req << " Request: DENIED (Too much requested)" << endl;
		return 0;
	}
	
	bool safe;
	bool done = false;
	int finished = 0;
	int over_avail = 0;
 	string safe_seq;
  	
  	// re-run bankers algorthim	
	while (!done){
		for (int i = 0; i < NUM_PROC; i++){
			if (!proc[i].finish){
				if (proc[i].need_a <= A && proc[i].need_b <= B 
    				&& proc[i].need_c <= C && proc[i].need_d <= D){
    				safe_seq += +"<" + proc[i].name + ">";
    			    A += proc[i].a;
           			B += proc[i].b;
              		C += proc[i].c;
                	D += proc[i].d;
                	finished++;
                 	proc[i].finish = true;	
				} else 
					over_avail++;
			}
		}
		
		// If all of the processes finished were in a safe state
		if (finished >= NUM_PROC){
			cout << "P" << req << " Request: ACCPETED (Seq:" << safe_seq << ")" << endl;
			done = true;
		}
		// If its done this loop more times there are # of processes
		// there is no safe state
		if (over_avail > NUM_PROC){
			cout << "P" << req << " Request: DENIED (Unsafe state)" << endl;
			done = true;
		}
	}
}

void run_bankers(Process proc[], int NUM_PROC)
{	
	bool safe;
	bool done = false;
	int finished = 0;
	int over_avail = 0;
 	string safe_seq;
  	
  	// Check if system is in a safe state	
	while (!done){
		for (int i = 0; i < NUM_PROC; i++){
			if (!proc[i].finish){
				if (proc[i].need_a <= A && proc[i].need_b <= B 
    				&& proc[i].need_c <= C && proc[i].need_d <= D){
    				safe_seq += +"<" + proc[i].name + ">";
    			    A += proc[i].a;
           			B += proc[i].b;
              		C += proc[i].c;
                	D += proc[i].d;
                	finished++;
                 	proc[i].finish = true;	
				} else 
					over_avail++;
			}
		}
		
		// If all of the processes finished were in a safe state
		if (finished >= NUM_PROC){
			cout << "System is in a safe state!" << endl;
			cout << "Safe Sequence: " << safe_seq << endl;
			done = true;
		}
		// If its done this loop more times there are # of processes
		// there is no safe state
		if (over_avail > NUM_PROC){
			cout << "Warning System NOT SAFE!" << endl;
			cout << "No Safe Sequence found!" <<  endl;
			done = true;
		}
	}
}

int main(int argc, char *argv[])
{
	char var;
	int val;
	FILE *proc_data;
	int NUM_PROC;
	
	if (argv[1] == NULL){
		cout << "Using default matrix.txt\n---------------------------------\n";
		argv[1] = "matrix.txt";
	}
	
	proc_data = fopen(argv[1], "r");	
 	if (proc_data==NULL){
		cout << "FILE DOES NOT EXIST!\n";
		system("PAUSE");
		return 0;
	}
 	
	string state;
	string param_type;
	
 	// Get file into string
	while(!feof(proc_data))
 		state += fgetc(proc_data);
	
	// Get our resource values and num of processes
	string str_val = state.substr(state.find("A") + 2, 2);
	A = atoi(str_val.c_str());
	str_val = state.substr(state.find("B") + 2, 2);
	B = atoi(str_val.c_str());
	str_val = state.substr(state.find("C") + 2, 2);
	C = atoi(str_val.c_str());
	str_val = state.substr(state.find("D") + 2, 2);
	D = atoi(str_val.c_str());
	str_val = state.substr(state.find("D") + 4, 2);
	NUM_PROC = atoi(str_val.c_str());

	// I'll use the GCC dynamic memory extension.. ok so its not
	// "standard" c++ but it will work for now
	Process proc[NUM_PROC];
	string p_param[NUM_PROC];
 		
    // Get the proc data we need out of the string and do our thing
    for (int x = 0; x < 3; x++){    
    	for (int i = 0; i < NUM_PROC; i++){
   			char ch_buff[20];
   			string ident = "P";
   			ident += itoa(i + 1, ch_buff, 10);
   			int offset = state.find(ident);    
   			
   			if (offset != string::npos){
        		p_param[i] = state.substr(offset
          			, state.find("\n", offset) - offset);        	
         		if (p_param[i].find(": Allocation") != string::npos)
         			param_type = "Allocation";
      			if (p_param[i].find(": Max")!= string::npos)
        			param_type = "Max";
      			if (p_param[i].find(": Request")!= string::npos){
        			param_type = "Request";
        			str_val = p_param[i].substr(1,2);
        			req = atoi(str_val.c_str());
     			}
      			state.erase(offset, state.find("\n", offset) - offset);

        		// set process resources depending on type
        		proc[i].set_resources(p_param[i], param_type);
        	}        	
       	}
	}
	
	// Print out each processes need and subtract its allocation from our resources
	for (int i = 0; i < NUM_PROC; i++){
		A -= proc[i].a;
		B -= proc[i].b;
		C -= proc[i].c;
		D -= proc[i].d;
		cout << proc[i].name << " Need (A,B,C,D): " << proc[i].need_a 
  			<< " " << proc[i].need_b << " " << proc[i].need_c << " " 
     		<< proc[i].need_d << endl;
	}
	
	cout << "Available Resources (A,B,C,D): " << A << " " << B << " " 
 		<< C << " " << D << " " << endl << endl;
	cout << "Now Running Bankers" << endl << "------------------------" << endl;
	run_bankers(proc, NUM_PROC);
	
	// Reset resources
 	str_val = state.substr(state.find("A") + 2, 2);
	A = atoi(str_val.c_str());
	str_val = state.substr(state.find("B") + 2, 2);
	B = atoi(str_val.c_str());
	str_val = state.substr(state.find("C") + 2, 2);
	C = atoi(str_val.c_str());
	str_val = state.substr(state.find("D") + 2, 2);
	D = atoi(str_val.c_str());
	for (int i = 0; i < NUM_PROC; i++){
		A -= proc[i].a;
		B -= proc[i].b;
		C -= proc[i].c;
		D -= proc[i].d;
	}
	
	// Set all the processes finish back to false
  	for (int i = 0; i < NUM_PROC; i++)
		proc[i].finish = false;	
	
	// Check if request can be granted
	run_request(proc, NUM_PROC);
  		
	
	system("PAUSE");	
    return 0;
}

