#include <iostream>
#include <fstream>
using namespace std;



int const BYTES = 900;
int const NUMBER_OFFSET = 48;

int memory[BYTES]={0};

int program_counter = 0;
int accumulator = 0;
int stack_pointer = 900;
int instruction_register = 0;


int GetOpcode(int x)
{
	return x/1000;
}

int GetOperand(int x)
{
	return x%1000;
}

/*void PutInProgram(int memory[])
{
	int end=1;

	cout<<"input program.  end with 0"<<endl;

	for (int byte=0; end >0;byte++)
	{
		cout<<"Content of "<<byte<<"? ";
		cin>>memory[byte];
		cout<<endl;
		
		if (memory[byte]==0)
		{
			end=0;
		}
		else;
	}

}*/

int ConvertNumber(char a, char b, char c)
{
	int ReturnInt=0;
	int ai = (int) a;
	ai -= NUMBER_OFFSET;
	int bi = (int) b;
	bi -= NUMBER_OFFSET;
	int ci = (int) c;
	ci -= NUMBER_OFFSET;

	ReturnInt = ai*100;
	ReturnInt += bi*10;
	ReturnInt += ci;

	return ReturnInt;
}

void ReadFile(char FileToRead[])
{
	
	int address = 0, content = 0;
	bool Quit = false;
	ifstream fin;

	char f;
	char s;
	char t;
	char trash;

	fin.open (FileToRead, ios::in);

	if(!fin.fail())
	{

		fin.get(f);
		fin.get(s);
		fin.get(t);
		fin.get(trash);
		
		fin.get(trash);
		address = ConvertNumber(f, s, t);
		fin>>content;
		while (!fin.eof()&& Quit != true)
		{
			
			memory[address]=content;
			//have to get newline, cr
			
			fin.get(trash);

			fin.get(f);
			
			if(f == '*')
			{
				Quit = true;
			}
			else
			{
				fin.get(s);
				fin.get(t);
				fin.get(trash);
				fin.get(trash);
				address = ConvertNumber(f, s, t);
				fin>>content;
			}

		}
	}
	else
	{
		cout<<"Could not open file."<<endl;
	}
	fin.close();


}
void main(int argc, char* argv[])
{
	bool CPUIsRunning=true;
	char ascii;
	char string[BYTES];
	char FileToRead[50];
	int opcode;
	int operand;
	

	if(argv[1] == NULL)
	{
		cout<<"File to read from:  ";
		cin>>FileToRead;
	}
	else
	{
		strcpy(FileToRead, argv[1]);
	}

	ReadFile(FileToRead);
	
	while (CPUIsRunning)
	{
		opcode = GetOpcode(memory[program_counter]);
		operand = GetOperand(memory[program_counter]);

		switch (opcode) 
		{
			case 0:	//stop
				CPUIsRunning = false;       
					break;
			case 1:	//ld x
				accumulator = memory[operand];
				break;
			case 2:		//ldi x;
				accumulator = memory[memory[operand]];
				break;
			case 3:	//lda x
				accumulator = operand;
					
				break;
			case 4:	//st x
				memory[operand] = accumulator;
					
				break;
			case 5:	//stix
				memory[memory[operand]] = accumulator;
					
				break;
			case 6:	//add x			
				accumulator += memory[operand];					
				break;

			case 7:	//sub x			
				accumulator -= memory[operand];					

				break;
			case 8:	//mul x
				accumulator = accumulator*memory[operand];
					
				break;
			case 9:	//div x				
				accumulator = accumulator/(memory[operand]);					

				break;
			case 10:	//in
				cin >> ascii;
				accumulator = ascii;

				break;
			case 11:	//out
				ascii = accumulator;
				cout<<ascii;
				
				break;
			case 12://b x
				//the -1 is offset by the increment at the bottom
				program_counter = operand-1;
					
				break;
			case 13://bp x
				if (accumulator>0)
					program_counter = operand-1;
				
				break;
			case 14://bn x
				if (accumulator<0)
					program_counter = operand- 1;
				break;
			case 15://bz x
				if (accumulator==0)
					program_counter = operand -1 ;
				break;
			case 16://?jsb x
				stack_pointer -=1;
				memory[stack_pointer] = program_counter;
				program_counter = operand;
					
				switch (operand)	//need to put in real data
				{
				case 900:	
					//ascii = accumulator;
					//cout<<ascii;
					cout<<accumulator;
					program_counter = memory[stack_pointer];
					stack_pointer += 1;
					break;
				case 925:	
					for (int n=0;memory[accumulator+n] !=0;n++)
					{
						ascii = memory[accumulator+n];
						cout<<ascii;
					}
					program_counter = memory[stack_pointer];
					stack_pointer += 1;
					break;
				case 950:	
					cin >> accumulator;
					program_counter = memory[stack_pointer];
					stack_pointer += 1;
								
					break;
				case 975:
					cin.getline(string, BYTES);
					cin.getline (string,BYTES);				//need to add it to memory
					
					for(n=0; string[n] !='\0';n++)
					{
						memory[accumulator+n]=(int)string[n];
					}
					memory[accumulator+n] = 0;
					program_counter = memory[stack_pointer];
					stack_pointer += 1;
					break;
				default:
					//if it's not a special jsb, we need to counter act the ++
					program_counter--;
					break;
				}
				
				break;
			case 17:// rsb x
				program_counter = memory[stack_pointer];
				stack_pointer += 1;
					
				break;
			case 18://push
				stack_pointer -= 1;
				memory[stack_pointer] = accumulator;

				break;
			case 19://pop
				accumulator = memory[stack_pointer];
				stack_pointer +=1;

				break;
				//maybe all graphics codes could just be SET x and the x would reference
				//the variables on the graphics chip. Set x, set y, set red, set blue, set green
				//first have to ld, then set.
			case 20: //set in graphics chip
				//set x
				break;
			default:	
				cout<<"Fatal Error:  Bad Opcode line "<<program_counter<<endl;
				CPUIsRunning = false;
				break;
		}
		program_counter++;

	}
}
