//
//  CSOric.m
//  Clock Signal
//
//  Created by Thomas Harte on 11/10/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#import "CSOric.h"

#include "Oric.hpp"
#include "StaticAnalyser.hpp"

#import "CSMachine+Subclassing.h"
#import "NSData+StdVector.h"
#import "NSBundle+DataResource.h"

@implementation CSOric {
	std::unique_ptr<Oric::Machine> _oric;
}

- (instancetype)init {
	Oric::Machine *machine = Oric::Machine::Oric();

	self = [super initWithMachine:machine];
	if(self) {
		_oric.reset(machine);

		NSData *basic10 = [self rom:@"basic10"];
		NSData *basic11 = [self rom:@"basic11"];
		NSData *colour = [self rom:@"colour"];
		NSData *microdisc = [self rom:@"microdisc"];

		if(basic10)		_oric->set_rom(Oric::BASIC10, basic10.stdVector8);
		if(basic11)		_oric->set_rom(Oric::BASIC11, basic11.stdVector8);
		if(colour)		_oric->set_rom(Oric::Colour, colour.stdVector8);
		if(microdisc)	_oric->set_rom(Oric::Microdisc, microdisc.stdVector8);
	}
	return self;
}

- (NSData *)rom:(NSString *)name {
	return [[NSBundle mainBundle] dataForResource:name withExtension:@"rom" subdirectory:@"ROMImages/Oric"];
}

#pragma mark - CSKeyboardMachine

- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed {
	@synchronized(self) {
		switch(key) {
			case VK_ANSI_0:		_oric->set_key_state(Oric::Key::Key0, isPressed);	break;
			case VK_ANSI_1:		_oric->set_key_state(Oric::Key::Key1, isPressed);	break;
			case VK_ANSI_2:		_oric->set_key_state(Oric::Key::Key2, isPressed);	break;
			case VK_ANSI_3:		_oric->set_key_state(Oric::Key::Key3, isPressed);	break;
			case VK_ANSI_4:		_oric->set_key_state(Oric::Key::Key4, isPressed);	break;
			case VK_ANSI_5:		_oric->set_key_state(Oric::Key::Key5, isPressed);	break;
			case VK_ANSI_6:		_oric->set_key_state(Oric::Key::Key6, isPressed);	break;
			case VK_ANSI_7:		_oric->set_key_state(Oric::Key::Key7, isPressed);	break;
			case VK_ANSI_8:		_oric->set_key_state(Oric::Key::Key8, isPressed);	break;
			case VK_ANSI_9:		_oric->set_key_state(Oric::Key::Key9, isPressed);	break;

			case VK_ANSI_Q:		_oric->set_key_state(Oric::Key::KeyQ, isPressed);	break;
			case VK_ANSI_W:		_oric->set_key_state(Oric::Key::KeyW, isPressed);	break;
			case VK_ANSI_E:		_oric->set_key_state(Oric::Key::KeyE, isPressed);	break;
			case VK_ANSI_R:		_oric->set_key_state(Oric::Key::KeyR, isPressed);	break;
			case VK_ANSI_T:		_oric->set_key_state(Oric::Key::KeyT, isPressed);	break;
			case VK_ANSI_Y:		_oric->set_key_state(Oric::Key::KeyY, isPressed);	break;
			case VK_ANSI_U:		_oric->set_key_state(Oric::Key::KeyU, isPressed);	break;
			case VK_ANSI_I:		_oric->set_key_state(Oric::Key::KeyI, isPressed);	break;
			case VK_ANSI_O:		_oric->set_key_state(Oric::Key::KeyO, isPressed);	break;
			case VK_ANSI_P:		_oric->set_key_state(Oric::Key::KeyP, isPressed);	break;
			case VK_ANSI_A:		_oric->set_key_state(Oric::Key::KeyA, isPressed);	break;
			case VK_ANSI_S:		_oric->set_key_state(Oric::Key::KeyS, isPressed);	break;
			case VK_ANSI_D:		_oric->set_key_state(Oric::Key::KeyD, isPressed);	break;
			case VK_ANSI_F:		_oric->set_key_state(Oric::Key::KeyF, isPressed);	break;
			case VK_ANSI_G:		_oric->set_key_state(Oric::Key::KeyG, isPressed);	break;
			case VK_ANSI_H:		_oric->set_key_state(Oric::Key::KeyH, isPressed);	break;
			case VK_ANSI_J:		_oric->set_key_state(Oric::Key::KeyJ, isPressed);	break;
			case VK_ANSI_K:		_oric->set_key_state(Oric::Key::KeyK, isPressed);	break;
			case VK_ANSI_L:		_oric->set_key_state(Oric::Key::KeyL, isPressed);	break;
			case VK_ANSI_Z:		_oric->set_key_state(Oric::Key::KeyZ, isPressed);	break;
			case VK_ANSI_X:		_oric->set_key_state(Oric::Key::KeyX, isPressed);	break;
			case VK_ANSI_C:		_oric->set_key_state(Oric::Key::KeyC, isPressed);	break;
			case VK_ANSI_V:		_oric->set_key_state(Oric::Key::KeyV, isPressed);	break;
			case VK_ANSI_B:		_oric->set_key_state(Oric::Key::KeyB, isPressed);	break;
			case VK_ANSI_N:		_oric->set_key_state(Oric::Key::KeyN, isPressed);	break;
			case VK_ANSI_M:		_oric->set_key_state(Oric::Key::KeyM, isPressed);	break;

			case VK_Space:			_oric->set_key_state(Oric::Key::KeySpace, isPressed);		break;
			case VK_Return:			_oric->set_key_state(Oric::Key::KeyReturn, isPressed);		break;
			case VK_ANSI_Minus:		_oric->set_key_state(Oric::Key::KeyMinus, isPressed);		break;
			case VK_ANSI_Equal:		_oric->set_key_state(Oric::Key::KeyEquals, isPressed);		break;
			case VK_ANSI_Backslash:
									_oric->set_key_state(Oric::Key::KeyBackSlash, isPressed);		break;
			case VK_ANSI_Slash:		_oric->set_key_state(Oric::Key::KeyForwardSlash, isPressed);	break;

			case VK_ANSI_LeftBracket:
									_oric->set_key_state(Oric::Key::KeyOpenSquare, isPressed);	break;
			case VK_ANSI_RightBracket:
									_oric->set_key_state(Oric::Key::KeyCloseSquare, isPressed);	break;
			case VK_ANSI_Quote:		_oric->set_key_state(Oric::Key::KeyQuote, isPressed);		break;

			case VK_RightArrow:		_oric->set_key_state(Oric::Key::KeyRight, isPressed);		break;
			case VK_LeftArrow:		_oric->set_key_state(Oric::Key::KeyLeft, isPressed);		break;
			case VK_DownArrow:		_oric->set_key_state(Oric::Key::KeyDown, isPressed);		break;
			case VK_UpArrow:		_oric->set_key_state(Oric::Key::KeyUp, isPressed);			break;

			case VK_Delete:			_oric->set_key_state(Oric::Key::KeyDelete, isPressed);		break;
			case VK_Escape:			_oric->set_key_state(Oric::Key::KeyEscape, isPressed);		break;

			case VK_ANSI_Comma:		_oric->set_key_state(Oric::Key::KeyComma, isPressed);		break;
			case VK_ANSI_Period:	_oric->set_key_state(Oric::Key::KeyFullStop, isPressed);	break;

			case VK_ANSI_Semicolon:	_oric->set_key_state(Oric::Key::KeySemiColon, isPressed);	break;

			case VK_Shift:
				_oric->set_key_state(Oric::Key::KeyLeftShift, isPressed);
				_oric->set_key_state(Oric::Key::KeyRightShift, isPressed);
			break;
			case VK_RightShift:		_oric->set_key_state(Oric::Key::KeyRightShift, isPressed);	break;
			case VK_Control:		_oric->set_key_state(Oric::Key::KeyControl, isPressed);		break;

			case VK_ANSI_Grave:
			case VK_F12:			_oric->set_key_state(Oric::Key::KeyNMI, isPressed);			break;

			default:
				printf("%02x\n", key);
			break;
		}
	}
}

- (void)clearAllKeys {
	@synchronized(self) {
		_oric->clear_all_keys();
	}
}

#pragma mark - Options

- (void)setUseFastLoadingHack:(BOOL)useFastLoadingHack {
	@synchronized(self) {
		_useFastLoadingHack = useFastLoadingHack;
		_oric->set_use_fast_tape_hack(useFastLoadingHack ? true : false);
	}
}

- (void)setUseCompositeOutput:(BOOL)useCompositeOutput {
	@synchronized(self) {
		_useCompositeOutput = useCompositeOutput;
		_oric->set_output_device(useCompositeOutput ? Outputs::CRT::Television : Outputs::CRT::Monitor);
	}
}

@end
