// scriptel-easyscript-test.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "scriptel-easyscript.h"
#include "scriptel-easyscript-private.h"

char *assert_reason;

scriptel_return_status test_compressed() {
	scriptel_return_status status;
	scriptel_signature signature;
	char *buffer = "~STSIGN D ST1501-STN 00.00.00 +L9nCHqnO@klSB30\"N,.nK)yz\")wdO_gz({a6OXyd+@ `";

	scriptel_signature_protocol *test_protocol = (scriptel_signature_protocol *)malloc(sizeof(scriptel_signature_protocol));
	memcpy(test_protocol, &STN_SIGNATURE_PROTOCOL, sizeof(scriptel_signature_protocol));
	test_protocol->height = 3000;
	test_protocol->width = 3000;

	status = scriptel_keyboard_parse_signature(test_protocol, &signature, buffer, strlen(buffer));

	assert(SCRIPTEL_RETR_SUCCESS == status);
	assert(3 == signature.length);

	assert(265 == signature.strokes[0].coordinates[0].x);
	assert(2130 == signature.strokes[0].coordinates[0].y);
	assert(260 == signature.strokes[0].coordinates[1].x);
	assert(2203 == signature.strokes[0].coordinates[1].y);

	assert(2909 == signature.strokes[1].coordinates[0].x);
	assert(804 == signature.strokes[1].coordinates[0].y);
	assert(2925 == signature.strokes[1].coordinates[1].x);
	assert(836 == signature.strokes[1].coordinates[1].y);

	assert(2915 == signature.strokes[2].coordinates[0].x);
	assert(1079 == signature.strokes[2].coordinates[0].y);
	assert(2928 == signature.strokes[2].coordinates[1].x);
	assert(1051 == signature.strokes[2].coordinates[1].y);
	assert(2935 == signature.strokes[2].coordinates[2].x);
	assert(1035 == signature.strokes[2].coordinates[2].y);

	scriptel_free_signature(&signature);
	free(test_protocol);

	return SCRIPTEL_RETR_SUCCESS;
}

scriptel_return_status test_uncompressed() {
	scriptel_return_status status;
	scriptel_signature signature;
	char *buffer = "~STSIGN A ST1526-STN 03.07.86 QNq[O@u;MR5b MRqjMVsfOZ3p `";

	scriptel_signature_protocol *test_protocol = (scriptel_signature_protocol *)malloc(sizeof(scriptel_signature_protocol));
	memcpy(test_protocol, &STN_SIGNATURE_PROTOCOL, sizeof(scriptel_signature_protocol));
	test_protocol->height = 505;
	test_protocol->width = 505;

	status = scriptel_keyboard_parse_signature(test_protocol, &signature, buffer, strlen(buffer));

	assert(SCRIPTEL_RETR_SUCCESS == status);
	assert(2 == signature.length);

	assert(strcmp("A", signature.protocol_version) == 0);
	assert(strcmp("ST1526-STN", signature.model) == 0);
	assert(strcmp("03.07.86", signature.version) == 0);

	assert(190.0 == signature.strokes[0].coordinates[0].x);
	assert(203.0 == signature.strokes[0].coordinates[0].y);
	assert(174.0 == signature.strokes[0].coordinates[1].x);
	assert(251.0 == signature.strokes[0].coordinates[1].y);

	assert(146.0 == signature.strokes[1].coordinates[0].x);
	assert(188.0 == signature.strokes[1].coordinates[0].y);
	assert(148.0 == signature.strokes[1].coordinates[1].x);
	assert(209.0 == signature.strokes[1].coordinates[1].y);
	assert(173.0 == signature.strokes[1].coordinates[2].x);
	assert(329.0 == signature.strokes[1].coordinates[2].y);


	scriptel_free_signature(&signature);
	free(test_protocol);

	return SCRIPTEL_RETR_SUCCESS;
}

scriptel_return_status test_compressed_high_stress() {
	scriptel_return_status status;
	scriptel_signature signature;
	char *buffer = "~STSIGN D ST1501-STN 00.00.00 \"{o[+:mv+T]z!^s.M*svCHs-%_3vAN'h%)avQHqrABab+_a-EFadE_e6ABq.<Lo.Y_a6O{]z+TaxIRc-\"JsjWR1pA|yzCJ3xI|q[M_en}LsjWV `";

	scriptel_coordinate stroke1[17] = { { CBT_COORDINATE, 191, 59 },   { CBT_COORDINATE, 191, 59 },   { CBT_COORDINATE, 252, 119 },
										{ CBT_COORDINATE, 312, 119 },  { CBT_COORDINATE, 371, 119 },  { CBT_COORDINATE, 433, 120 },
										{ CBT_COORDINATE, 496, 121 },  { CBT_COORDINATE, 1520, 120 }, { CBT_COORDINATE, 1520, 115 },
										{ CBT_COORDINATE, 1520, 120 }, { CBT_COORDINATE, 1520, 125 }, { CBT_COORDINATE, 1520, 130 },
										{ CBT_COORDINATE, 1520, 125 }, { CBT_COORDINATE, 1518, 120 }, { CBT_COORDINATE, 1516, 115 },
										{ CBT_COORDINATE, 1518, 110 }, { CBT_COORDINATE, 1516, 115 } };
	scriptel_coordinate stroke2[2] = { { CBT_COORDINATE, 0, 0 }, { CBT_COORDINATE, 2999, 2999 } };
	scriptel_coordinate stroke3[2] = { { CBT_COORDINATE, 0, 2999 }, { CBT_COORDINATE, 2999, 0 } };
	scriptel_coordinate stroke4[5] = { { CBT_COORDINATE, 0, 0 }, { CBT_COORDINATE, 2999, 0 }, { CBT_COORDINATE, 2999, 2999 }, { CBT_COORDINATE, 0, 2999 }, { CBT_COORDINATE, 0, 0 } };
	scriptel_stroke reference_strokes[4] = { 
		{ sizeof(stroke1) / sizeof(scriptel_coordinate), stroke1 },
		{ sizeof(stroke2) / sizeof(scriptel_coordinate), stroke2 },
		{ sizeof(stroke3) / sizeof(scriptel_coordinate), stroke3 },
		{ sizeof(stroke4) / sizeof(scriptel_coordinate), stroke4 }
	};

	scriptel_signature_protocol *test_protocol = (scriptel_signature_protocol *)malloc(sizeof(scriptel_signature_protocol));
	memcpy(test_protocol, &STN_SIGNATURE_PROTOCOL, sizeof(scriptel_signature_protocol));
	test_protocol->height = 3000;
	test_protocol->width = 3000;

	status = scriptel_keyboard_parse_signature(test_protocol, &signature, buffer, strlen(buffer));

	assert(SCRIPTEL_RETR_SUCCESS == status);
	assert(4 == signature.length);

	int num_ref_strokes = sizeof(reference_strokes) / sizeof(scriptel_stroke);
	int stroke;
	for (stroke = 0; stroke < num_ref_strokes; stroke++) {
		int coord;
		for (coord = 0; coord < reference_strokes[stroke].length; coord++) {
			assert(reference_strokes[stroke].coordinates[coord].type == signature.strokes[stroke].coordinates[coord].type);
			assert(reference_strokes[stroke].coordinates[coord].x == signature.strokes[stroke].coordinates[coord].x);
			assert(reference_strokes[stroke].coordinates[coord].y == signature.strokes[stroke].coordinates[coord].y);
		}
	}

	scriptel_free_signature(&signature);
	free(test_protocol);

	return SCRIPTEL_RETR_SUCCESS;
}

static int event_count;
void uncompressed_streaming_event_listener(streaming_event_data *sd) {
	switch (event_count++) {
		case 0:
			assert(CBT_METADATA == sd->type);
			assert(strcmp("C", sd->meta_data.protocol_version) == 0);
			assert(strcmp("ST1526-STN", sd->meta_data.model) == 0);
			assert(strcmp("03.07.86", sd->meta_data.version) == 0);
			break;
		case 1:
			assert(CBT_COORDINATE == sd->type);
			assert(190.0 == sd->coordinate.x);
			assert(203.0 == sd->coordinate.y);
			break;
		case 2:
			assert(CBT_COORDINATE == sd->type);
			assert(174.0 == sd->coordinate.x);
			assert(251.0 == sd->coordinate.y);
			break;
		case 3:
			assert(CBT_COORDINATE == sd->type);
			assert(146.0 == sd->coordinate.x);
			assert(345.0 == sd->coordinate.y);
			break;
		case 4:
			assert(CBT_NEWSTROKE == sd->type);
			break;
		case 5:
			assert(CBT_COORDINATE == sd->type);
			assert(146.0 == sd->coordinate.x);
			assert(188.0 == sd->coordinate.y);
			break;
		case 6:
			assert(CBT_COORDINATE == sd->type);
			assert(148.0 == sd->coordinate.x);
			assert(209.0 == sd->coordinate.y);
			break;
		case 7:
			assert(CBT_COORDINATE == sd->type);
			assert(173.0 == sd->coordinate.x);
			assert(329.0 == sd->coordinate.y);
			break;
		case 8:
			assert(CBT_END_OF_SIGNATURE == sd->type);
			break;
	}
}

scriptel_return_status test_uncompressed_streaming() {
	
	scriptel_add_event_listener(uncompressed_streaming_event_listener);

	scriptel_signature_protocol *test_protocol = (scriptel_signature_protocol *)malloc(sizeof(scriptel_signature_protocol));
	memcpy(test_protocol, &STN_SIGNATURE_PROTOCOL, sizeof(scriptel_signature_protocol));
	test_protocol->height = 505;
	test_protocol->width = 505;

	event_count = 0;
	char *c = "~STSIGN C-~=[Y ST1526-STN 03.07.86 QNq[O@u;MR5b MRqjMVsfOZ3p `";
	while (*c) {
		assert(SCRIPTEL_RETR_SUCCESS == scriptel_keyboard_parse_char(test_protocol, *c++));
	}
	assert(event_count == 9);

	scriptel_remove_event_listener(uncompressed_streaming_event_listener);

	free(test_protocol);

	return SCRIPTEL_RETR_SUCCESS;
}

void compressed_streaming_event_listener(streaming_event_data *sd) {
	switch (event_count++) {
	case 0:
		assert(CBT_METADATA == sd->type);
		assert(strcmp("D", sd->meta_data.protocol_version) == 0);
		assert(strcmp("ST1501-STN", sd->meta_data.model) == 0);
		assert(strcmp("12.23.56", sd->meta_data.version) == 0);
		break;
	case 1:
		assert(CBT_COORDINATE == sd->type);
		assert(265.0 == sd->coordinate.x);
		assert(2130.0 == sd->coordinate.y);
		break;
	case 2:
		assert(CBT_COORDINATE == sd->type);
		assert(260.0 == sd->coordinate.x);
		assert(2203.0 == sd->coordinate.y);
		break;
	case 3:
		assert(CBT_NEWSTROKE == sd->type);
		break;
	case 4:
		assert(CBT_COORDINATE == sd->type);
		assert(2909.0 == sd->coordinate.x);
		assert(804.0 == sd->coordinate.y);
		break;
	case 5:
		assert(CBT_COORDINATE == sd->type);
		assert(2925.0 == sd->coordinate.x);
		assert(836.0 == sd->coordinate.y);
		break;
	case 6:
		assert(CBT_NEWSTROKE == sd->type);
		break;
	case 7:
		assert(CBT_COORDINATE == sd->type);
		assert(2915.0 == sd->coordinate.x);
		assert(1079.0 == sd->coordinate.y);
		break;
	case 8:
		assert(CBT_COORDINATE == sd->type);
		assert(2928.0 == sd->coordinate.x);
		assert(1051.0 == sd->coordinate.y);
		break;
	case 9:
		assert(CBT_COORDINATE == sd->type);
		assert(2935.0 == sd->coordinate.x);
		assert(1035.0 == sd->coordinate.y);
		break;
	case 10:
		assert(CBT_CANCEL == sd->type);
		break;
	}
}

scriptel_return_status test_compressed_streaming() {
	scriptel_signature_protocol *test_protocol = (scriptel_signature_protocol *)malloc(sizeof(scriptel_signature_protocol));
	memcpy(test_protocol, &STN_SIGNATURE_PROTOCOL, sizeof(scriptel_signature_protocol));
	test_protocol->height = 3000;
	test_protocol->width = 3000;

	scriptel_add_event_listener(compressed_streaming_event_listener);
	event_count = 0;

	char *c = "~STSIGN D ST1501-STN 12.23.56 +L9nCHqnO@klSB30\"N,.nK)yz\")wdO_gz({a6OXyd+@ /";
	while (*c) {
		assert(SCRIPTEL_RETR_SUCCESS == scriptel_keyboard_parse_char(test_protocol, *c++));
	}
	assert(event_count == 11);

	scriptel_remove_event_listener(compressed_streaming_event_listener);

	free(test_protocol);

	return SCRIPTEL_RETR_SUCCESS;
}

scriptel_return_status test_card() {
	char *buffer = "!STCARD A %B4275448195401452^DOE/JOHN^19081011234500111000000?;4275448195401453=190810110000111?\r";
	scriptel_cardswipe swipe;

	scriptel_keyboard_parse_cardswipe(&STN_CARDSWIPE_PROTOCOL, &swipe, buffer, strlen(buffer) + 1);

	assert(CBT_CARD_DATA == swipe.type);
	assert(strcmp("A", swipe.protocol_version) == 0);
	assert(VISA == swipe.financial_card->card_issuer);
	assert(strcmp("JOHN", swipe.financial_card->track_one->first_name) == 0);
	assert(strcmp("DOE", swipe.financial_card->track_one->last_name) == 0);
	assert(strcmp("4275448195401452", swipe.financial_card->track_one->account_number) == 0);
	assert(strcmp("4275448195401453", swipe.financial_card->track_two->account_number) == 0);
	assert(1567310399 == swipe.financial_card->track_one->expiration);

	scriptel_free_cardswipe(&swipe);
	return SCRIPTEL_RETR_SUCCESS;
}

void card_streaming_event_listener(streaming_event_data *sd) {
	switch (event_count++) {
	case 0:
		assert(CBT_CARD_DATA == sd->type);
		assert(strcmp("A", sd->card_swipe.protocol_version) == 0);
		assert(VISA == sd->card_swipe.financial_card->card_issuer);
		assert(strcmp("JOHN", sd->card_swipe.financial_card->track_one->first_name) == 0);
		assert(strcmp("DOE", sd->card_swipe.financial_card->track_one->last_name) == 0);
		assert(strcmp("4275448195401452", sd->card_swipe.financial_card->track_one->account_number) == 0);
		assert(strcmp("4275448195401453", sd->card_swipe.financial_card->track_two->account_number) == 0);
		assert(1567310399 == sd->card_swipe.financial_card->track_one->expiration);
		break;
	}
}

scriptel_return_status test_card_streaming() {
	char *c = "!STCARD A %B4275448195401452^DOE/JOHN^19081011234500111000000?;4275448195401453=190810110000111?\r";

	scriptel_add_event_listener(card_streaming_event_listener);
	event_count = 0;
	while (*c) {
		assert(SCRIPTEL_RETR_SUCCESS == scriptel_keyboard_parse_char(&STN_SIGNATURE_PROTOCOL, *c++));
	}

	assert(event_count == 1);

	scriptel_remove_event_listener(card_streaming_event_listener);

	return SCRIPTEL_RETR_SUCCESS;
}

void card_intervening_signature_listener(streaming_event_data *sd) {
	switch (event_count++) {
	case 0:
		assert(CBT_METADATA == sd->type);
		assert(strcmp("C", sd->meta_data.protocol_version) == 0);
		assert(strcmp("ST1526-STN", sd->meta_data.model) == 0);
		assert(strcmp("03.07.86", sd->meta_data.version) == 0);
		break;
	case 1:
		assert(CBT_COORDINATE == sd->type);
		assert(190.0 == sd->coordinate.x);
		assert(203.0 == sd->coordinate.y);
		break;
	case 2:
		assert(CBT_CARD_DATA == sd->type);
		assert(strcmp("A", sd->card_swipe.protocol_version) == 0);
		assert(VISA == sd->card_swipe.financial_card->card_issuer);
		assert(strcmp("JOHN", sd->card_swipe.financial_card->track_one->first_name) == 0);
		assert(strcmp("DOE", sd->card_swipe.financial_card->track_one->last_name) == 0);
		assert(strcmp("4275448195401452", sd->card_swipe.financial_card->track_one->account_number) == 0);
		assert(strcmp("4275448195401453", sd->card_swipe.financial_card->track_two->account_number) == 0);
		assert(1567310399 == sd->card_swipe.financial_card->track_one->expiration);
		break;
	case 3:
		assert(CBT_COORDINATE == sd->type);
		assert(174.0 == sd->coordinate.x);
		assert(251.0 == sd->coordinate.y);
		break;
	case 4:
		assert(CBT_COORDINATE == sd->type);
		assert(146.0 == sd->coordinate.x);
		assert(345.0 == sd->coordinate.y);
		break;
	case 5:
		assert(CBT_NEWSTROKE == sd->type);
		break;
	case 6:
		assert(CBT_COORDINATE == sd->type);
		assert(146.0 == sd->coordinate.x);
		assert(188.0 == sd->coordinate.y);
		break;
	case 7:
		assert(CBT_COORDINATE == sd->type);
		assert(148.0 == sd->coordinate.x);
		assert(209.0 == sd->coordinate.y);
		break;
	case 8:
		assert(CBT_COORDINATE == sd->type);
		assert(173.0 == sd->coordinate.x);
		assert(329.0 == sd->coordinate.y);
		break;
	case 9:
		assert(CBT_END_OF_SIGNATURE == sd->type);
		break;
	}
}

scriptel_return_status test_card_intervening_signature() {

	scriptel_signature_protocol *test_protocol = (scriptel_signature_protocol *)malloc(sizeof(scriptel_signature_protocol));
	memcpy(test_protocol, &STN_SIGNATURE_PROTOCOL, sizeof(scriptel_signature_protocol));
	test_protocol->height = 505;
	test_protocol->width = 505;

	char *c = "~STSIGN C-~=[Y ST1526-STN 03.07.86 QNq[O@!STCARD A %B4275448195401452^DOE/JOHN^19081011234500111000000?;4275448195401453=190810110000111?\ru;MR5b MRqjMVsfOZ3p `";

	scriptel_add_event_listener(card_intervening_signature_listener);
	event_count = 0;
	while (*c) {
		assert(SCRIPTEL_RETR_SUCCESS == scriptel_keyboard_parse_char(test_protocol, *c++));
	}

	assert(event_count == 10);

	scriptel_remove_event_listener(card_intervening_signature_listener);

	return SCRIPTEL_RETR_SUCCESS;
}

int main() {
	if (test_uncompressed_streaming() != SCRIPTEL_RETR_SUCCESS) return 1;
	if (test_compressed_streaming() != SCRIPTEL_RETR_SUCCESS) return 1;
	if (test_compressed() != SCRIPTEL_RETR_SUCCESS) return 1;
	if (test_compressed_high_stress() != SCRIPTEL_RETR_SUCCESS) return 1;
	if (test_uncompressed() != SCRIPTEL_RETR_SUCCESS) return 1;
	if (test_card() != SCRIPTEL_RETR_SUCCESS) return 1;
	if (test_card_streaming() != SCRIPTEL_RETR_SUCCESS) return 1;
	if (test_card_intervening_signature() != SCRIPTEL_RETR_SUCCESS) return 1;

	printf("All tests passed\n");
	return 0;
}

