//#include "color.h"
#include "fxcg\display.h"
#include "fxcg\keyboard.h"
#include "keyboard_syscalls.h"
#include "rtc.h"
#include "string.h"
#include "fxcg\file.h"
#include "textinput.h"
#include "stdlib.h"
#include "stdio.h"
#include "alloca.h"
#include "math.h"

#define max( a, b ) ( ((a) > (b)) ? (a) : (b) )
#define min( a, b ) ( ((a) < (b)) ? (a) : (b) )

unsigned int random(void);
unsigned int srandom(int seed);

static unsigned int lastrandom=0x12345678;
unsigned int random(void) {
   return srandom(0);
}

unsigned int srandom(int seed){
    if (seed) lastrandom=seed;
    lastrandom = ( 0x41C64E6D*lastrandom ) + 0x3039;
    return ( lastrandom >> 16 );
}

void CopySprite(const void* datar, int x, int y, int width, int height) {
   color_t*data = (color_t*) datar;
   color_t* VRAM = (color_t*)GetVRAMAddress();
   VRAM += LCD_WIDTH_PX*y + x;
   for(int j=y; j<y+height; j++) {
      for(int i=x; i<x+width; i++) {
        if(i>0 && i<384 && j>0 && j<216){
         *(VRAM++) = *(data++);
        } else { VRAM++; data++; }
     }
     VRAM += LCD_WIDTH_PX-width;
   }
}

int RGBColor(int r, int g, int b)
{
  return ((r / 8) << 11) | ((g / 4) << 5) | (b / 8);
}

void fill_scr(color_t color) {
        unsigned int temp_color = (unsigned int)(color<<16) | color;
   for(int i = 0; i < LCD_WIDTH_PX*LCD_HEIGHT_PX/2; i++) {
      *((int*)0xA8000000+i) = temp_color;
   }
}

double hue2rgb(double p, double q, double t){
    if(t < 0) t += 1;
    if(t > 1) t -= 1;
    if(t < 1/6) return p + (q - p) * 6 * t;
    if(t < 1/2) return q;
    if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
    return p;
}

int HSLtoRGB(int h1, int s1, int l1)
{
    float r, g, b, h, s, l; //this function works with floats between 0 and 1
    float temp1, temp2, tempr, tempg, tempb;
    h = h1 / 256.0;
    s = s1 / 256.0;
    l = l1 / 256.0;
    if(s == 0) r = g = b = l;
    //If saturation > 0, more complex calculations are needed
    else
    {
        //Set the temporary values
        if(l < 0.5) temp2 = l * (1 + s);
        else temp2 = (l + s) - (l * s);
        temp1 = 2 * l - temp2;
        tempr = h + 1.0 / 3.0;
        if(tempr > 1) tempr--;
        tempg = h;
        tempb = h - 1.0 / 3.0;
        if(tempb < 0) tempb++;

        //Red
        if(tempr < 1.0 / 6.0) r = temp1 + (temp2 - temp1) * 6.0 * tempr;
        else if(tempr < 0.5) r = temp2;
        else if(tempr < 2.0 / 3.0) r = temp1 + (temp2 - temp1) * ((2.0 / 3.0) - tempr) * 6.0;
        else r = temp1;

        //Green
        if(tempg < 1.0 / 6.0) g = temp1 + (temp2 - temp1) * 6.0 * tempg;
        else if(tempg < 0.5) g = temp2;
        else if(tempg < 2.0 / 3.0) g = temp1 + (temp2 - temp1) * ((2.0 / 3.0) - tempg) * 6.0;
        else g = temp1;

        //Blue
        if(tempb < 1.0 / 6.0) b = temp1 + (temp2 - temp1) * 6.0 * tempb;
        else if(tempb < 0.5) b = temp2;
        else if(tempb < 2.0 / 3.0) b = temp1 + (temp2 - temp1) * ((2.0 / 3.0) - tempb) * 6.0;
        else b = temp1;
    }

    return RGBColor((int)(r * 255.0), (int)(g * 255.0), (int)(b * 255.0));;
}

void plot(int x0, int y0, int color){
   char* VRAM = (char*)0xA8000000;
   VRAM += 2*(y0*LCD_WIDTH_PX + x0);
   *(VRAM++) = (color&0x0000FF00)>>8;
   *(VRAM++) = (color&0x000000FF);
   return;
}

int PRGM_GetKey(){
  unsigned char buffer[12];
  PRGM_GetKey_OS( buffer );
  return ( buffer[1] & 0x0F ) * 10 + ( ( buffer[2] & 0xF0 ) >> 4 );
}

int w = 145, h = 216;

color_t color;

//define the width and height of the screen and the buffers
const int screenWidth = 145;
const int screenHeight = 216;

color_t fire[145*216];  //this buffer will contain the fire
color_t palette[256]; //this will contain the color palette

int blah;

int main()
{
  Bdisp_EnableColor(1);
  //declarations
  color_t color; //used during palette generation

  //make sure the fire buffer is zero in the beginning
  for(int x = 0; x < w; x++)
  for(int y = 0; y < h; y++)
  fire[y*w+x] = 0;

  //generate the palette
  for(int x = 0; x < 256; x++)
  {
    //HSLtoRGB is used to generate colors:
    //Hue goes from 0 to 85: red to yellow
    //Saturation is always the maximum: 255
    //Lightness is 0..255 for x=0..128, and 255 for x=128..255
    color = HSLtoRGB(x / 3, 255, min(255, x * 2));
    //set the palette to the calculated RGB value
    palette[x] = color;
  }

  //start the loop (one frame per loop)
  while(1)
  {
    int key = PRGM_GetKey();
    if(key == KEY_PRGM_MENU) {  GetKey(&key); }
    fill_scr(0x0000);
    //randomize the bottom row of the fire buffer
    for(int x = 0; x < w; x++) fire[(h - 1)*w+x] = abs(32768 + random()) % 256;
    //do the fire calculations for every pixel, from top to bottom
    for(int y = 0; y < h - 1; y++)
    for(int x = 0; x < w; x++)
    {
      fire[y*w+x] =
        ((fire[((y + 1) % h)*w+((x - 1 + w) % w)]
        + fire[((y + 1) % h)*w+((x) % w)]
        + fire[((y + 1) % h)*w+((x + 1) % w)]
        + fire[((y + 2) % h)*w+((x) % w)])
        * 32) / 129;
    }

    //set the drawing buffer to the fire buffer, using the palette colors
    for(int x = 1; x < w; x++)
    for(int y = 0; y < h; y++)
    {
      plot(x+99, y, palette[fire[y*w+x]]);
    }

    Bdisp_PutDisp_DD();
    if(key == KEY_PRGM_F6)
        GetKey(&blah);
  }
}