 #include <iostream>
#include <string>
#include <fstream>
using namespace std;
#include "SPL.h"

const bool debug = false;

SPL::SPL()
{
  string fname;
  for (int i = 0; i < CAPACITY; i++)
		mem[i] = 0;
	greetingSTART();
  cin >> fname;
  file.open(fname.c_str(), ios::in);
  	if (!file.is_open())
	{
		errorMESSAGE(FILE_ERROR);
		exit(FILE_ERROR);
	}
  readProgram();
}

SPL::SPL(char inp[99])
{
	for (int i = 0; i < CAPACITY; i++)
		mem[i] = 0;
	file.open(inp, ios::in);
	greetingSTART();
	if (!file.is_open())
	{
		errorMESSAGE(FILE_ERROR);
		exit(FILE_ERROR);
	}
	readProgram();
}

SPL::~SPL()
{
	greetingEND();
}
void SPL::readProgram()
{
	int count = 0, total, mod;
	string line;

	while (!file.eof())
	{
		mod = 1;
		total = 0;
		getline (file, line);
		for (int i = 0; i < 4; i++)
		{
			total += (static_cast<int>(line[i] - 48) * (1000 / mod));
			mod *= 10;
		}
		if ((count + 1) == CAPACITY)
		{
			errorMESSAGE(OUT_OF_MEM);
			exit(OUT_OF_MEM);
		}
		mem[count++] = total;
	}
}

void SPL::greetingSTART()
{
	cout << "*** Welcome to myComputer\n" << endl;
}

void SPL::greetingEND()
{
	cout << "*** myComputer: Good-bye...\n" << endl;
}

void SPL::errorMESSAGE(Errors errCode)
{
	switch (errCode)
		{
				case NO_ERROR: break;
				case DIV_BY_ZERO: cout << "*** Error: Division by zero" << endl; break;
				case OUT_OF_MEM: cout << "*** Error: Out of memory" << endl; break;
				case FILE_ERROR: cout << "*** Error: Unable to open file" << endl; break;
		}
}

Errors SPL::exec()
{
	int accumulator = 0;
	int counter = 0;
	int instrReg;
	int operCode;
	int operand;

	do
	{
	  instrReg = mem[counter];
	  operCode = instrReg / 100;
	  operand = instrReg % 100;

		if (debug == true)
		{
			cout << "instrReg = " << instrReg << endl
					<< "operCode = " << operCode << endl
					<< "operand = "  << operand  << endl
					<< "counter = "  << counter  << endl << endl;
		}

	   switch (operCode)
	   {
	      case READ:
					read(operand);
					counter++; break;
	      case WRITE:
				 write(operand);
					counter++; break;
	      case LOAD:
				 accumulator = load(operand);
					counter++; break;
	      case STORE:
				 store(operand, accumulator);
					counter++; break;
	      case ADD:
					accumulator = add(accumulator, operand);
					if (debug == true)
						cout << "accumulator ==" << accumulator << endl;
					counter++; break;
	      case SUBTRACT:
						accumulator = subtract(accumulator, operand);
					counter++; break;
	      case DIVIDE:
						accumulator = divide(accumulator, operand);
					counter++; break;
	      case MULTIPLY:
					accumulator = multiply(accumulator, operand);
					counter++; break;
	      case BRANCH:
					counter = branch(operand); break;
	      case BRANCHNEG:
					counter = branchNEG(operand, counter); break;
	      case BRANCHZERO:
					counter = branchZERO(operand, counter); break;
	      case HALT: break;
	   }
	} while (operCode != HALT);

	return NO_ERROR;
}

void SPL::read(int operand)
{
	cin >> mem[operand];
	if (debug == true)
		cout << "read: operand = " << operand << endl;
	return;
}

void SPL::write(int operand)
{
	cout << "RESULT = " << mem[operand] << endl;
	if (debug == true)
		cout << "write: operand = " << operand << endl;
	return;
}

int SPL::load(int operand)
{
	if (debug == true)
	{
		cout << "load: operand = " << operand << endl;
		cout << "New accumulator = " << mem[operand] << endl;
		cout << "mem[operand] == " << mem[operand] << endl;
	}
	return mem[operand];
}


void SPL::store(int operand, int accumulator)
{
	mem[operand] = accumulator;
	if (debug == true)
		cout << "store: operand = " << operand << " accumulator = " << accumulator << endl;
	return;
}


int SPL::add(int accumulator, int operand)
{
	if (debug == true)
	{
		cout << "add: operand = " << operand << " accumulator = " << accumulator << endl;
		cout << "New accumulator = " << accumulator + mem[operand] << endl;
	}
	else
		cout << "operation: add" << endl;
	return accumulator + mem[operand];
}


int SPL::subtract(int accumulator, int operand)
{
	if (debug == true)
		cout << "subtract: operand = " << operand << " accumulator = " << accumulator << endl;
	else
		cout << "operation: subtract" << endl;
	return accumulator - mem[operand];
}

int SPL::divide(int accumulator, int operand)
{
	if (debug == true)
		cout << "divide: operand = " << operand << " accumulator = " << accumulator << endl;
	else
		cout << "operation: divide" << endl;
	if (mem[operand] != 0)
		return accumulator / mem[operand];
	else
	{
		errorMESSAGE(DIV_BY_ZERO);
		exit(DIV_BY_ZERO);
	}
}

int SPL::multiply(int accumulator, int operand)
{
	if (debug == true)
		cout << "multiply: operand = " << operand << " accumulator = " << accumulator << endl;
	else
		cout << "operation: multiple" << endl;
	return accumulator * mem[operand];
}


int SPL::branch(int operand)
{
	cout << "branch: operand = " << endl;
	return operand;
}


int SPL::branchNEG(int operand, int counter)
{
	cout << "branchNEG: operand = " << operand << " counter = " << counter << endl;
	if (mem[operand] < 0)
		return operand;
	else
		return ++counter;
}
int SPL::branchZERO(int operand, int counter)
{
	cout << "branchZERO: operand = " << operand << " counter = " << counter <<
endl;
	if (mem[operand] == 0)
		return operand;
	else
		return ++counter;
}