/** @file frontend_csfml.c
  CSFML frontend for Licar.
*/

#include <SFML/Audio.h>
#include <SFML/Graphics.h>
#include <SFML/System.h>
#include <SFML/Audio/Types.h>
#include <stdint.h>
#include <stdio.h>

#define LCR_SETTING_LOG_LEVEL 2
#define DATA_FILE_NAME "data"

//#define LCR_LOADING_COMMAND SDL_PumpEvents();

// #define LCR_FPS_GET_MS SDL_GetTicks() // uncomment for FPS measuring

#include "game.h"

#define WINDOW_SIZE (LCR_SETTING_RESOLUTION_X * LCR_SETTING_RESOLUTION_Y)

sfUint32 windowPixels[WINDOW_SIZE * 2];
uint8_t fullscreen = 1;
FILE *musicFile = 0;
FILE *dataFile = 0;
sfClock *clock;
sfRenderWindow* window;
sfSoundStream *sound;

#define AUDIO_BUFFER_SIZE 256

int16_t audioBuffer[AUDIO_BUFFER_SIZE];
uint8_t musicBuffer[AUDIO_BUFFER_SIZE];

char LCR_getNextDataFileChar(void)
{
  if (!dataFile)
    return 0;

  int c = fgetc(dataFile);

  if (c == EOF)
  {
    rewind(dataFile);
    return 0;
  }

  return c;
}

void LCR_appendDataStr(const char *str)
{
  fclose(dataFile);
  
  dataFile = fopen(DATA_FILE_NAME,"a");
  
  if (dataFile)
  {
    fprintf(dataFile,"%s",str);
    fclose(dataFile);
    dataFile = fopen(DATA_FILE_NAME,"r");
  }
}

uint8_t LCR_keyPressed(uint8_t key)
{
  #define k(x) sfKeyboard_isKeyPressed(sfKey ## x)

  switch (key)
  {
    case LCR_KEY_UP:    return k(W) || k(Up) || k(Num8);              break;
    case LCR_KEY_RIGHT: return k(E) || k(Right) || k(Num6);           break;
    case LCR_KEY_DOWN:  return k(S) || k(Down) || k(Num5) || k(Num2); break;
    case LCR_KEY_LEFT:  return k(Q) || k(Left) || k(Num4);            break;
    case LCR_KEY_A:     return k(K) || k(Return);                     break;
    case LCR_KEY_B:     return k(L) || k(Escape);                     break;
    default: break;
  }

  return 0;
}

void LCR_sleep(uint16_t timeMs)
{
  sfTime t;
  t.microseconds = timeMs * 1000;
  sfSleep(t);
}

void LCR_drawPixel(unsigned long index, uint16_t color)
{
  windowPixels[index] = 0xff000000 | ((color & 0x07e0) << 5) |
    (((color << 19) | (color >> 8)) & 0x00f800f8) ;
}

void LCR_log(const char *str)
{
  printf("LOG: %s\n",str);
}

void printHelp(void)
{
  printf(
    "Licar, 3D racing game, v. " LCR_VERSION ", CSFML frontend, args:\n"
    "  -h   print help and quit\n"
    "  -wN  window (N = 1) or fullscreen (N = 0)\n"
    LCR_ARG_HELP_STR);
}

sfBool soundFill(sfSoundStreamChunk *data, void *userdata)
{
  if (musicFile && LCR_gameMusicOn())
  {
    if (!fread(musicBuffer,1,AUDIO_BUFFER_SIZE,musicFile))
      rewind(musicFile);

    for (int i = 0; i < AUDIO_BUFFER_SIZE; ++i)
      audioBuffer[i] = musicBuffer[i];
  }
  else
    for (int i = 0; i < AUDIO_BUFFER_SIZE; ++i)
      audioBuffer[i] = 127;

  for (int i = 0; i < AUDIO_BUFFER_SIZE; ++i)
    audioBuffer[i] =
      (audioBuffer[i] + LCR_gameGetNextAudioSample() - 255) * 64;

  data->samples = audioBuffer;
  data->sampleCount = AUDIO_BUFFER_SIZE;

  return sfTrue;
}

void soundSeek(sfTime t, void *userData)
{
}

int main(int argc, char *argv[])
{
  for (int i = 0; i < argc; ++i)
    if (argv[i][0] == '-')
      switch (argv[i][1])
      {
        case 'h': printHelp(); return 0; break;
        case 'w': fullscreen = argv[i][2] == '0'; break;
        default: break;
      }

  dataFile = fopen(DATA_FILE_NAME,"r");

  if (!dataFile)
    LCR_log("couldn't open data file");

  musicFile = fopen("assets/music","rb");

  if (!musicFile)
    fputs("could not open music file",stderr);

  LCR_log("initializing game");
  LCR_gameInit(argc,(const char **) argv);

  LCR_log("initializing SFML");
  sfVideoMode mode = {LCR_SETTING_RESOLUTION_X,LCR_SETTING_RESOLUTION_Y,32};
  sfEvent event;
  clock = sfClock_create();
  sfClock_restart(clock);

  LCR_log("initializing audio");

  for (int i = 0; i < AUDIO_BUFFER_SIZE; ++i)
    audioBuffer[i] = 0;

  sound = sfSoundStream_create(soundFill,soundSeek,1,8000,0);

  sfTexture* windowTexture =
    sfTexture_create(LCR_SETTING_RESOLUTION_X,LCR_SETTING_RESOLUTION_Y);

  sfTexture_setSmooth(windowTexture,sfTrue);

  sfSprite* windowSprite = sfSprite_create();

  window = sfRenderWindow_create(mode,"Licar", 
    fullscreen ? sfFullscreen : (sfResize | sfClose ),NULL);

  sfSprite_setTexture(windowSprite,windowTexture,sfTrue);
  sfWindow_setVerticalSyncEnabled((sfWindow *) window,sfFalse);

  sfSoundStream_play(sound);

  puts("starting");

  while (sfRenderWindow_isOpen(window))
  {
    while (sfRenderWindow_pollEvent(window,&event))
      if (event.type == sfEvtClosed)
        sfRenderWindow_close(window);

    if (!LCR_gameStep(sfClock_getElapsedTime(clock).microseconds / 1000))
      break;

    sfTexture_updateFromPixels(windowTexture,(const sfUint8 *) windowPixels,
      LCR_SETTING_RESOLUTION_X,LCR_SETTING_RESOLUTION_Y,0,0);
    sfRenderWindow_clear(window,sfBlack);
    sfRenderWindow_drawSprite(window,windowSprite,NULL);
    sfRenderWindow_display(window);
  }

  LCR_log("ending");

  if (musicFile)
    fclose(musicFile);

  if (dataFile)
    fclose(dataFile);

  sfSoundStream_stop(sound);
  sfSoundStream_destroy(sound);
  sfSprite_destroy(windowSprite);
  sfTexture_destroy(windowTexture);
  sfRenderWindow_destroy(window);
  sfClock_destroy(clock);

  LCR_gameEnd();

  return 0;
}
