///////////////////////////////////////////////////////////////////////////////
// TJC ChipDisk #2 main file
// Author: Pontus (pikzel) Palmenäs    050530
///////////////////////////////////////////////////////////////////////////////

#include "chipdisk.h"

///////////////////////////////////////////////////////////////////////////////
// void init()
// Initierar allegro och ställer in det åt oss
///////////////////////////////////////////////////////////////////////////////
void init() {

  // initiera ellegro
  allegro_init();

  // fixa färgdjup
  int depth = desktop_color_depth();
  if (depth == 0) depth = 32;
  set_color_depth(depth);

  // försök att ställa in grafikläget
  if (set_gfx_mode(MODE, WIDTH, HEIGHT, 0, 0) != 0) {
    allegro_message(allegro_error);
    exit(-1);
  }

  // ställ in fönstrets titel
  set_window_title(WINDOW_TITLE);

  // periferi och timer
  install_timer();
  install_keyboard();

  // välj transparent text
  text_mode(-1);

  // fixa för frameraten
  LOCK_VARIABLE(counter);
  LOCK_VARIABLE(framerate);
  LOCK_VARIABLE(ticks);
  LOCK_VARIABLE(resting);
  LOCK_VARIABLE(rested);
  LOCK_FUNCTION(customTimer);
  LOCK_FUNCTION(hold);
  install_int(customTimer, 1000);

}


///////////////////////////////////////////////////////////////////////////////
// void deinit()
// Rensar upp efter vår användning
///////////////////////////////////////////////////////////////////////////////
void deinit() {

  // rensa tangenbordsbuffern
  clear_keybuf();

  // rensa musiken
  for (int i=0; i<N_SONGS; i++) {
    FMUSIC_FreeSong(songs[i].mod);
  }

  // stäng ljudströmmen
  FSOUND_Close();

  // töm bufferten
  destroy_bitmap(buff);
}


///////////////////////////////////////////////////////////////////////////////
// void setupMusic()
// Sätter upp musiken för användning
///////////////////////////////////////////////////////////////////////////////
void setupMusic() {

  // initiera ljudet
  if(!FSOUND_Init(32000, 64, 0)) {
    allegro_message("Can't init sound!\n");
    exit(-1);
  }

  // ladda in modulerna
  for (int i=0; i<N_SONGS; i++) {
    songs[i].mod = FMUSIC_LoadSong(files[i]);

    // kontrollera att filen lästes in ordentligt
    if (!songs[i].mod) {
      allegro_message("Modules not loaded correctly :/\n");
      exit(-1);
    }

    // ställ in volymen på alla låtar
    FMUSIC_SetMasterVolume(songs[i].mod,volume);
  }

  // fyll i text och msg för varje låt
  for (int i=0; i<N_SONGS; i++) {
    songs[i].title = titles[i];
    songs[i].msg = msgs[i];
    //songs[i].title = "titel";
    //songs[i].msg = "msg";
  }

  // spela den första låten
  FMUSIC_PlaySong(songs[0].mod);
}


///////////////////////////////////////////////////////////////////////////////
// void setupScene();
// Ställer in "scenen" som vi vill ha den
///////////////////////////////////////////////////////////////////////////////
void setupScene() {

  // skapa buffern
  buff = create_bitmap(WIDTH,HEIGHT);

  // vit bakgrund
  clear_to_color(buff, WHITE);

  // ladda bakgrunden
  backg = load_bitmap("data/gfx/bg.bmp", NULL);
  if (!backg) {
    allegro_message("File not found: bg.bmp)");
    exit(-1);
  }

  // ladda blomma
  flower = load_bitmap("data/gfx/flower.bmp", NULL);
  if (!flower) {
    allegro_message("File not found: flower.bmp)");
    exit(-1);
  }

  // ladda noter
  note1 = load_bitmap("data/gfx/note1.bmp", NULL);
  if (!note1) {
    allegro_message("File not found: note1.bmp");
    exit(-1);
  }

  note2 = load_bitmap("data/gfx/note2.bmp", NULL);
  if (!note2) {
    allegro_message("File not found: note1.bmp");
    exit(-1);
  }


  // slumpa typ, position, stolek och hastighet för varje not
  for (int i=0; i<N_NOTES; i++) {
    notes[i].type = (1+rand()%4);
    notes[i].x = (WIDTH-50-rand()%200);
    notes[i].y = (rand()%HEIGHT-100);
    notes[i].speed = (1+rand()%10);
  }

  // räkna ut mitten av bildens koordinater
  center_x = SCREEN_W/2 - flower->w/2;
  center_y = SCREEN_H/2 - flower->h/2;
}


///////////////////////////////////////////////////////////////////////////////
// void updateScene();
// Uppdaterar allt i scenen
///////////////////////////////////////////////////////////////////////////////
void updateScene() {

  // öka vinkeln för blomman
  flower_angle -= ftofix(0.3);
  if (flower_angle < 0) {
    flower_angle = ftofix(256);
  }

  // öka noternas vinkel
  note_angle -= ftofix(1);
  if (note_angle < 0) {
    note_angle = ftofix(256);
  }

  // flytta noterna
  for (int i=0; i<N_NOTES; i++) {
    notes[i].y -= (FMUSIC_GetBPM(songs[current].mod)/FMUSIC_GetSpeed(songs[current].mod))/(notes[i].speed*8)+1;
    notes[i].x += fixtoi(fixcos(note_angle));
    if (notes[i].y < -50) {
      notes[i].y = HEIGHT-100;
      notes[i].x = (WIDTH-50-rand()%200);
    }
  }

  // flytta textens koordinater
  msg_x--;
  if (msg_x < -text_length(font,songs[current].msg)) {
    msg_x = WIDTH;
  }


  // uppdatera ticks
  ticks++;

  // gör allt långsammare
  resting = 0;
  rest_callback(6, hold);
}


///////////////////////////////////////////////////////////////////////////////
// void drawScene();
// Ritar ut scenen
///////////////////////////////////////////////////////////////////////////////
void drawScene() {

  //rensa scenen
  clear_to_color(buff, WHITE);

  blit(backg,buff,0,0,0,0,WIDTH,HEIGHT);

  // rotera blomman
  rotate_sprite(buff, flower, center_x, center_y, flower_angle);

  // gå igenom alla noter och rita ut dem
  for (int i=0; i<N_NOTES; i++) {
    switch(notes[i].type) {
      case 1:
        draw_sprite(buff, note1, notes[i].x, notes[i].y);
        break;

      case 2:
       draw_sprite_h_flip(buff, note1, notes[i].x, notes[i].y);
        break;

      case 3:
        draw_sprite(buff, note2, notes[i].x, notes[i].y);
        break;

      case 4:
        draw_sprite_h_flip(buff, note2, notes[i].x, notes[i].y);
        break;

      default:
        draw_sprite(buff, note1, notes[i].x, notes[i].y);
    }

  }

  // skriv låtnamn
  textout(buff, font, songs[current].title, 12, HEIGHT-49, BLACK);

  // skriv ut bmp/speed
  textprintf(buff, font, 0, 0, BLACK, "speed: %d", FMUSIC_GetSpeed(songs[current].mod));
  textprintf(buff, font, 0, 10, BLACK, "bpm: %d", FMUSIC_GetBPM(songs[current].mod));

  // skriv ut shuffle on/off
  if (shuffle) { textprintf(buff, font, 0, 20, BLACK, "shuffle: on"); }
  else { textprintf(buff, font, 0, 20, BLACK, "shuffle: off"); }

  // skriv volym
  textprintf(buff, font, WIDTH-97, HEIGHT-49, BLACK, "volume: %d", volume );

  // rita linjen
  hline(buff, 0, HEIGHT-30, WIDTH, BLACK);
  hline(buff, 0, HEIGHT-29, WIDTH, BLACK);

  // skriv ut msg
  textout(buff, font, songs[current].msg, msg_x, HEIGHT-19, BLACK);

  // rita ut bufferten på skärmen
  acquire_screen();
  blit(buff,screen,0,0,0,0,WIDTH,HEIGHT);
  release_screen();

}


///////////////////////////////////////////////////////////////////////////////
// void customTimer()
// Räknar ut fps en gång per sekund
///////////////////////////////////////////////////////////////////////////////
void customTimer(void) {
  counter++;
  framerate = ticks;
  ticks=0;
  rested=resting;
}
END_OF_FUNCTION(customTimer)


///////////////////////////////////////////////////////////////////////////////
// void hold()
// En egen rest-funktion, för att hantera en fast framerate
///////////////////////////////////////////////////////////////////////////////
void hold(void) {
  resting++;
}


///////////////////////////////////////////////////////////////////////////////
// void getInput()
// Hanterar knapptryckningar från användaren
///////////////////////////////////////////////////////////////////////////////
void getInput() {

  // vi behöver bara kolla vad som tryckts om någon verkligen tryckt på något
  if (keypressed()) {
    if (key[KEY_ESC]) {
      esc = true;
    }
    if (key[KEY_LEFT]) {
      prev();
    }
    if (key[KEY_RIGHT]) {
      next();
    }
    if (key[KEY_UP]) {
      volume_up();
    }
    if (key[KEY_DOWN]) {
      volume_down();
    }
    if (key[KEY_SPACE]) {
      change_gfxmode();
    }
    if (key[KEY_ENTER]) {
	  shuffle = !shuffle;
      rest(250);
    }
  }
}


///////////////////////////////////////////////////////////////////////////////
// void next()
// Byter till nästa låt
///////////////////////////////////////////////////////////////////////////////
void next() {

  // stoppa nuvarande låten
  FMUSIC_StopSong(songs[current].mod);

  // hitta nästa låt
  if (!shuffle) {  current++; }
  else { current = rand()%(N_SONGS); }
  rest(250);
  if (current > N_SONGS-1) {
    current = 0;
  }

  // spela låten
  FMUSIC_PlaySong(songs[current].mod);

  // nollställ positionen för msg
  msg_x = WIDTH;
}


///////////////////////////////////////////////////////////////////////////////
// void prev()
// Byter till föregående låt
///////////////////////////////////////////////////////////////////////////////
void prev() {

  // stoppa nuvarande låten
  FMUSIC_StopSong(songs[current].mod);

  // hitta föregående låt
  if (!shuffle) {  current--; }
  else { current = 1+rand()%(N_SONGS-1); }
  rest(250);
  if (current < 0) {
    current = N_SONGS-1;
  }

  // spela låten
  FMUSIC_PlaySong(songs[current].mod);

  // nollställ positionen för msg
  msg_x = WIDTH;
}


///////////////////////////////////////////////////////////////////////////////
// void volume_up()
// Ökar volymen
///////////////////////////////////////////////////////////////////////////////
void volume_up() {
  if (volume < 255) {
    volume += 5;
    for (int i=0; i<N_SONGS; i++) {
      FMUSIC_SetMasterVolume(songs[i].mod,volume);
    }
  }
}


///////////////////////////////////////////////////////////////////////////////
// void volume_down()
// Sänker volymen
///////////////////////////////////////////////////////////////////////////////
void volume_down() {
  if (volume > 0) {
    volume -= 5;
    for (int i=0; i<N_SONGS; i++) {
      FMUSIC_SetMasterVolume(songs[i].mod,volume);
    }
  }
}


///////////////////////////////////////////////////////////////////////////////
// void change_gfxmode()
// Växlar mellan fullscreen och windowed
///////////////////////////////////////////////////////////////////////////////
void change_gfxmode() {
  if (gfx_driver && gfx_driver->windowed) {
    if (set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, WIDTH, HEIGHT, 0, 0) != 0) {
      allegro_message(allegro_error);
      exit(-1);
    }
  }
  else {
    if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, WIDTH, HEIGHT, 0, 0) != 0) {
      allegro_message(allegro_error);
      exit(-1);
    }
  }
}


///////////////////////////////////////////////////////////////////////////////
// int main()
// Vår huvudtråd, innehåller logikloopen
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) {

  // initiera allegro
  init();

  // sätt upp musiken
  setupMusic();

  // sätt upp vår scen
  setupScene();

  // kör tills escape trycks
  while(!key[KEY_ESC]) {

    // hantera knapptryckningar
    getInput();

    // uppdatera scenen
    updateScene();

    // rita upp scenen
    drawScene();

  }

  // rensa upp och avsluta
  deinit();
  return 0;
};
END_OF_MAIN();