/*
    Trying to set up 8 pt text on the same scale as drawing however a line of text plus leading
    is taking up about 20 units.  so either I need to bodge the point size, bodge the scaling,
    or change from 600x1000 to 300x500 screen while keeping the units the same - nah, that
    doesn't make sense.  Should make it so a 16pt font looks like the current text below... 
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>

#include "asteroids_font.h"
// #include "hershey_font.h"     // If you include this it is used by default
// #include "tailgunner_font.h"  // TG font not yet ported.

#define SCREEN_W 600
#define SCREEN_H 1000
#define SCREEN_FONT_SCALE 8

#ifdef USE_VECTERM
#include <stdbool.h>
#include <pthread.h>
#include "../vecterm/vecterm_communication.h"

static framegen_data *init_framegen_data(void) {
    static framegen_data frame;
    frame.options.use_ay_regs           = false;
    frame.options.use_led               = false;
    frame.options.use_led_dimmed        = false;
    frame.options.use_points            = false;

    frame.options.screen_swap_x_y       = false;
    frame.options.screen_flip_x         = false;
    frame.options.screen_flip_y         = false;
    frame.options.aspect_ratio_adjust   = false;
    switch (vecterm_orientation()) {
        case 3:
            frame.options.screen_swap_x_y       = true;
            frame.options.screen_flip_x         = true;
            frame.options.aspect_ratio_adjust   = true;
            break;
        case 2:
            frame.options.screen_flip_x         = true;
            frame.options.screen_flip_y         = true;
            break;
        case 1:
            break;
        default:
            frame.options.screen_swap_x_y       = true;
            frame.options.screen_flip_y         = true;
            frame.options.aspect_ratio_adjust   = true;
            break;
    }


    frame.options.aspect_ratio          = 5.0/4.0;
    //frame.options.aspect_ratio          = 4.0/5.0; // this hack is compensated for by a counter-hack where SCREEN_H is changed from 800 to 1023 :-/
    
    frame.options.use_opt_1             = true;
    frame.options.use_opt_2             = true;
    frame.options.use_opt_point_offset  = false;
    frame.options.use_opt_point_char_detect  = false;
    frame.options.continue_distance     = 1;
    frame.options.point_size            = 8;
    
    // frame.measurement_flags             = VECTERM_MEASUREMENT_FLAGS_BUTTONS  | VECTERM_MEASUREMENT_FLAGS_DIGITAL_X | VECTERM_MEASUREMENT_FLAGS_DIGITAL_Y;
    // frame.measurement_flags             = VECTERM_MEASUREMENT_FLAGS_BUTTONS  | VECTERM_MEASUREMENT_FLAGS_ANALOG_X | VECTERM_MEASUREMENT_FLAGS_ANALOG_Y;
    frame.measurement_flags             = 0;
    
    static float tmp_mem[5*16*1024];
    frame.max_line_count = 16*1024;
    frame.ptr = tmp_mem;
    frame.line_count = 0;
    
    return (&frame);
}

framegen_data *frame;
#endif

void draw_line(int FromX, int FromY, int ToX, int ToY, int Colour15)
{
#ifdef USE_VECTERM
  if (frame->line_count < frame->max_line_count) {
    float *fptr = frame->ptr + 5*frame->line_count++;
    fptr[0] = (float)(FromX)/(float)SCREEN_W;
    fptr[1] = (float)(FromY)/(float)SCREEN_H;
    fptr[2] = (float)(ToX)/(float)SCREEN_W;
    fptr[3] = (float)(ToY)/(float)SCREEN_H;
    fptr[4] = (float)(Colour15&15)/15.0;
  }
#endif
}

static int cur_x=0, cur_y=0, cur_bright=7;

void moveto(int x, int y) {
  cur_x = x; cur_y = y;
}

void lineto(int x, int y) {
  draw_line(cur_x, cur_y, x, y, cur_bright);
  cur_x = x; cur_y = y;
}

int draw_character(char c, int x, int y, int size)
{
#ifdef CONFIG_FONT_HERSHEY
	const hershey_char_t * const f = &hershey_simplex[c - ' '];
	int next_moveto = 1;

	for(int i = 0 ; i < f->count ; i++)
	{
		int dx = f->points[2*i+0];
		int dy = f->points[2*i+1];
		if (dx == -1)
		{
			next_moveto = 1;
			continue;
		}

		dx = (dx * size) * 3 / 4;
		dy = (dy * size) * 3 / 4;

		if (next_moveto)
			moveto(x + dx/SCREEN_FONT_SCALE, y + dy/SCREEN_FONT_SCALE);
		else
			lineto(x + dx/SCREEN_FONT_SCALE, y + dy/SCREEN_FONT_SCALE);

		next_moveto = 0;
	}

	return ((f->width * size) * 3 / 4)/SCREEN_FONT_SCALE;
#else
	// Asteroids font only has upper case
	if ('a' <= c && c <= 'z')
		c -= 'a' - 'A';

	const uint8_t * const pts = asteroids_font[c - ' '].points;
	int next_moveto = 1;

	for(int i = 0 ; i < 8 ; i++)
	{
		uint8_t delta = pts[i];
		if (delta == FONT_LAST)
			break;
		if (delta == FONT_UP)
		{
			next_moveto = 1;
			continue;
		}

		unsigned dx = ((delta >> 4) & 0xF) * size;
		unsigned dy = ((delta >> 0) & 0xF) * size;

		if (next_moveto)
			moveto(x + dx/SCREEN_FONT_SCALE, y + dy/SCREEN_FONT_SCALE);
		else
			lineto(x + dx/SCREEN_FONT_SCALE, y + dy/SCREEN_FONT_SCALE);

		next_moveto = 0;
	}

	return (12 * size)/SCREEN_FONT_SCALE;
#endif
}


void
draw_string(const char *s, int x, int y, int size)
{
  while (*s) {
    char c = *s++;
    x += draw_character(c, x, y, size);
  }
}

char *ProgName = "error";

void init(void) {
#ifdef USE_VECTERM
  if (!vecterm_open_connection(0)) {
    fprintf(stderr, "%s: opening vecterm connection failed\n", ProgName);
    exit(EXIT_FAILURE);
  }
  frame = init_framegen_data();
  frame->options.screen_flip_y = false;
#endif
}


void do_frame(void) {
  // do stuff here
  draw_string("HELLO", SCREEN_W/2 - 45, SCREEN_H/2 + 35, frame->options.point_size);
  draw_string("VECTREX", SCREEN_W/2 - 45, SCREEN_H/2 + 35 - 20, frame->options.point_size);

  //  draw_string("CONGRATULATIONS", 100, SCREEN_H - 150, frame->options.point_size);
  //  draw_string("", 100, SCREEN_H - 170, frame->options.point_size);
  //  draw_string("YOUR SCORE IS IN THE TOP TEN", 100, SCREEN_H - 190, frame->options.point_size);
  //  draw_string("", 100, SCREEN_H - 210, frame->options.point_size);
  draw_string("PLEASE ENTER YOUR NAME BELOW", 100, SCREEN_H - 230, frame->options.point_size);
  draw_string("", 100, SCREEN_H - 250, frame->options.point_size);
  draw_string("1234 FRED", 200, SCREEN_H - 270, frame->options.point_size);
  draw_string(" 700 GRAHAM_", 200, SCREEN_H - 290, frame->options.point_size);
  draw_string("  23 JIM", 200, SCREEN_H - 310, frame->options.point_size);

  draw_line((SCREEN_W/2)-50,(SCREEN_H/2)-50, (SCREEN_W/2)-50,(SCREEN_H/2)+50, 7);
  draw_line((SCREEN_W/2)+50,(SCREEN_H/2)+50, (SCREEN_W/2)+50,(SCREEN_H/2)-50, 7);
  draw_line((SCREEN_W/2)+50,(SCREEN_H/2)-50, (SCREEN_W/2)-50,(SCREEN_H/2)-50, 7);
  draw_line((SCREEN_W/2)-50,(SCREEN_H/2)+50, (SCREEN_W/2)+50,(SCREEN_H/2)+50, 7);
#ifdef USE_VECTERM
  vecterm_wait_for_elapsed_frame();
  vecterm_new_frame(frame);
  frame->line_count = 0;
#endif
}

int main(int argc, char **argv)
{
  char *s;
  ProgName = argv[0];
  s = strrchr(ProgName, '/');
  if (s == NULL) s = strrchr(ProgName, '\\');
  if (s == NULL) s = strrchr(ProgName, ':');
  if (s == NULL) s = strrchr(ProgName, ']');
  if (s == NULL) s = ProgName; else s = s+1;
  ProgName = malloc(strlen(s)+1); strcpy(ProgName, s);
  s = strchr(ProgName, '.'); if (s != NULL) *s = '\0';

  init();

#ifdef GAME_PLAYS_TOO_FAST
  // This is the kind of frameskip needed when the game would by default
  // play too fast - eg it came from 40Hz hardware but needs to be displayed at 50Hz
  //
  // The other kind of frameskip - where our hardware is not keeping up with the
  // game's output depends on whether it is the game playing code which cannot
  // execute in 1/50 sec or less, or whether the problem is that it takes the
  // display longer than 1/50 sec to draw all the vectors.  In the former case
  // we can redraw the previous frame while waiting for the code to catch up,
  // but in the latter case there just may not be anything we can do except live
  // with the flicker.
  
  {int frame_no = 0;
    // We repeat every 4th frame
    // to convert 40Hz game to 50Hz display
    for (;;) {
      frame_no += 1;
      if (frame_no < 5) do_frame(); // 5th frame is a repeat of 4th frame
#ifdef USE_VECTERM
      vecterm_wait_for_elapsed_frame();
#endif
      if (frame_no == 5) frame_no = 0;
    }
  }
#else
  for (;;) {
    do_frame();
#ifdef USE_VECTERM
    vecterm_wait_for_elapsed_frame();
#endif
  }
#endif

}
