// - - - - - - - - - - - - - - - - - - - - - - - -
// File: main.cpp                                 |
// Purpose: Program for testing neural nets       |
//           in a light-sensitive moving creature |
// Author: Taivo Lints, Estonia                   |
// Date: May, 2003                                |
// Copyright: see copyright.txt                   |
// - - - - - - - - - - - - - - - - - - - - - - - -

#include "creature/creature.h"
#include "light/light.h"
#include "palette/mypalette.h"
#include "allegro.h"
#include "stdio.h"  // For sprintf() and strcat() (Allegro needs char* -s)
#include <vector>
using namespace std;

int main() {

  // ******************************
  // * Setting up the environment *
  // ******************************

  allegro_init();
  install_keyboard();
  install_mouse();
  install_timer();

  set_color_depth(8);
  set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0);

  // Configures the text to be drawn with transparent background.
  text_mode(-1);

  // Sets the color of warning texts.
  int color_of_wtxt = 90;
  change_color(color_of_wtxt, 63, 5, 0);

  // Sets the color of notice texts.
  int color_of_ntxt = 91;
  change_color(color_of_ntxt, 55, 45, 10);

  // Sets colors for file loading menu.
  int color_of_gui_bg = 92,
      color_of_gui_fg = 93;

  change_color(color_of_gui_bg, 0, 0, 20);
  change_color(color_of_gui_fg, 0, 50, 0);

  gui_bg_color = color_of_gui_bg;
  gui_fg_color = color_of_gui_fg;

  // Sets colors for help background.
  int color_of_help_bg = 94;
  change_color(color_of_help_bg, 0, 0, 10);

  // Sets the colors of creature.
  int color_of_icircle = 95,
      color_of_ocircle = 96;
  change_color(color_of_icircle, 0, 0, 63);
  change_color(color_of_ocircle, 0, 58, 0);

  // Creates gradient for light.
  int start_of_gradient = 100;
  make_grayscale_palette_64(start_of_gradient);

  // Creates a bitmap object for double buffering (to avoid screen flickering).
  BITMAP* dblbuf = create_bitmap(SCREEN_W, SCREEN_H);
  clear_bitmap(dblbuf);


  // ********************************
  // * Initializing other variables *
  // ********************************

  // Initializes variables for loading the configuration file.
  char config_file[500];
  sprintf(config_file, "config_generated.txt");

  char message[] = "Load new configuration file";  // Message for load menu.
  char* ext = "TXT";   // File filter for load menu.

  char help_msg1[150];  // Creating some help messages.
  sprintf(help_msg1, "File ");
  strcat(help_msg1, config_file);
  strcat(help_msg1, " is missing");

  char help_msg2[150];
  sprintf(help_msg2, "Quit, fix ");
  strcat(help_msg2, config_file);
  strcat(help_msg2, " and restart program");


  // Creates a Creature object.
  Creature* pCreature= new Creature(dblbuf, color_of_icircle, color_of_ocircle,
                                     start_of_gradient, config_file);

  // Variables for tuning creature's speed.
  const double default_speedup_factor = pCreature->speedup_factor;
  double change_of_speedup_factor = 0.01;

  // Creates a Light object.
  Light* pLight = new Light(dblbuf, start_of_gradient);

  // Variable for changing spotlight's speed and radius.
  double change_of_lightspeed = 0.1;
  int change_of_radius = 5;

  // Variables for storing mouse information;
  int mickey_x = 0,
      mickey_y = 0;

  // A flag noticing what kind of additional help to print for user.
  bool flag_just_started = true;

  // Program loops while this flag is "true".
  bool keepgoing = true;
 

  // *****************
  // * The main loop *
  // *****************

  while(keepgoing) {

    //  ----------------------------
    // | Updating & drawing objects |
    //  ----------------------------

    // Done first because these objects should be behind any texts
    // that may be printed later.

    pLight->update();
    pLight->draw();

    pCreature->update();
    pCreature->draw();


    //  -------------------------------
    // | Printing some additional help |
    //  -------------------------------

    if(pCreature->flag_incor_net) {
      textout(dblbuf, font, "Network is incorrect!", 2, 10, color_of_wtxt);

      if(flag_just_started) {
        textout(dblbuf, font, "Possible reasons:", 15, 30, color_of_wtxt);
        textout(dblbuf, font, help_msg1, 35, 42, color_of_wtxt);
        textout(dblbuf, font,
         "or is incorrect (wrong number of inputs or outputs)", 35, 54, color_of_wtxt);
        textout(dblbuf, font, "Solutions:", 15, 74, color_of_wtxt);
        textout(dblbuf, font, help_msg2, 35, 86, color_of_wtxt);
        textout(dblbuf, font,
         "or press L and load another configuration file", 35, 98, color_of_wtxt);
      }
      else {
        textout(dblbuf, font, "Possible reasons:", 15, 30, color_of_wtxt);
        textout(dblbuf, font,
          "Loaded file is incorrect (wrong number of inputs or outputs)",
            35, 42, color_of_wtxt);
        textout(dblbuf, font,
          "or path contains non-english characters", 35, 54, color_of_wtxt);
        textout(dblbuf, font, "Solutions:", 15, 74, color_of_wtxt);
        textout(dblbuf, font, "Fix your file and reload it", 35, 86, color_of_wtxt);
        textout(dblbuf, font,
          "or press L and load another configuration file", 35, 98, color_of_wtxt);
        textout(dblbuf, font,
          "or in case of incorrect path move your file into", 35, 110, color_of_wtxt);
        textout(dblbuf, font, "correct path and load again", 35, 122, color_of_wtxt);
        textout(dblbuf, font, "Your selected path was:", 15, 140, color_of_ntxt);
        textout(dblbuf, font, config_file, 35, 152, color_of_ntxt);
      }
    }


    //  -----------------------------
    // | Processing user interaction |
    //  -----------------------------

    // Gets mouse movement information.
    get_mouse_mickeys(&mickey_x, &mickey_y);


    // - - Moving objects - - -

    if(key[KEY_ALT]) {           // creature
      pCreature->x += mickey_x;
      pCreature->y += mickey_y;
    }
    else {                       // or light
      pLight->x += mickey_x;
      pLight->y += mickey_y;            
    }

    // - - Changing spotlight's speed - - -

    if(key[KEY_9_PAD])
      pLight->speed_x += change_of_lightspeed;
    if(key[KEY_8_PAD])
      pLight->speed_x -= change_of_lightspeed;
    if(key[KEY_4_PAD])
      pLight->speed_y += change_of_lightspeed;
    if(key[KEY_7_PAD])
      pLight->speed_y -= change_of_lightspeed;

    if(key[KEY_6_PAD])
      pLight->speed_x = 0;
    if(key[KEY_5_PAD])
      pLight->speed_y = 0;

    // - - Tuning creature's speed - - -

    if(key[KEY_ASTERISK]) {
      pCreature->speedup_factor += change_of_speedup_factor;

      char buf[80];
      sprintf(buf, "speedup_factor = %f", pCreature->speedup_factor);
      textout_right(dblbuf, font, buf, 625, 8, color_of_ntxt);
    }

    if(key[KEY_SLASH_PAD]) {
      pCreature->speedup_factor -= change_of_speedup_factor;
      if(pCreature->speedup_factor < 0)
        pCreature->speedup_factor = 0;

      char buf[80];
      sprintf(buf, "speedup_factor = %f", pCreature->speedup_factor);
      textout_right(dblbuf, font, buf, 625, 8, color_of_ntxt);
    }

    if(key[KEY_MINUS_PAD]) {
      pCreature->speedup_factor = default_speedup_factor;

      char buf[80];
      sprintf(buf, "speedup_factor = %f", pCreature->speedup_factor);
      textout_right(dblbuf, font, buf, 625, 8, color_of_ntxt);
    }

    // - - Changing light's radius - - -

    if(mouse_b bitand 1) pLight->radius += change_of_radius;
    if( (mouse_b bitand 2) and (pLight->radius > 5) )
      pLight->radius -= change_of_radius;

    // - - Loading new network - - -

    if(key[KEY_L]) {

      // Calls file selection menu.
      int i = file_select_ex(message, config_file, ext, 490, 400, 450);
      rest(250);  // In case menu was exited by pressing Esc, this avoids
                  // quitting the program.

      // If user chose something, then loads it into creature.
      if(i != 0) {
        pCreature->load_network(config_file);
        flag_just_started = false;
      }

      // After using menu the mickeys are screwed (moving mouse while in menu
      // shouldn't move light or creature). For correction:
      get_mouse_mickeys(&mickey_x, &mickey_y);
    }

    // - - Other user interactions - - -

    // Press Escape to exit.
    if(key[KEY_ESC]) {
      text_mode(0);
      textout(screen, font, "ESC pressed, will QUIT", 2, 2, color_of_wtxt);
      rest(2000);
      keepgoing = false;
    }

    // Press F1 for help.
    if(key[KEY_F1]) {
      rectfill(screen, 0, 0, 445, 200, color_of_help_bg);

      textout(screen, font, "Keys:", 4, 10, color_of_ntxt);
      textout(screen, font, "mouse         - move spotlight", 15, 30, color_of_ntxt);
      textout(screen, font, "Alt + mouse   - move creature", 15, 42, color_of_ntxt);
      textout(screen, font,
       "mouse buttons - change size of spotlight", 15, 54, color_of_ntxt);
      textout(screen, font,
       "Numpad: 8,9,6  - change horizontal speed of spotlight", 15, 76, color_of_ntxt);
      textout(screen, font,
       "Numpad: 4,7,5  - change vertical speed of spotlight", 15, 88, color_of_ntxt);
      textout(screen, font,
       "Numpad: /,*,-  - tune creature's speed", 15, 100, color_of_ntxt);
      textout(screen, font, "L   - load network", 15, 122, color_of_ntxt);
      textout(screen, font, "F1  - this help", 15, 144, color_of_ntxt);
      textout(screen, font,
       "F12 - save screenshot (does NOT work in menus)", 15, 156, color_of_ntxt);
      textout(screen, font, "Esc - quit program", 15, 168, color_of_ntxt);
      textout(screen, font, "Press any key to leave help", 15, 190, color_of_ntxt);

      rest(100);
      clear_keybuf();
      while(!keypressed());
      rest(250);

      // After using menu the mickeys are screwed (moving mouse while in menu
      // shouldn't move light or creature). For correction:
      get_mouse_mickeys(&mickey_x, &mickey_y);
    }

    // Press F12 to save screenshot.
    if(key[KEY_F12]) {
      PALETTE pal;
      get_palette(pal);
      save_bitmap("screenshot.bmp", dblbuf, pal);
      textout(screen, font, "Screenshot saved", 2, 2, color_of_ntxt);
      rest(2000);

      // After using menu the mickeys are screwed (moving mouse while in menu
      // shouldn't move light or creature). For correction:
      get_mouse_mickeys(&mickey_x, &mickey_y);

    }


    //  ----------
    // | Blitting |
    //  ----------

    // Copies the dblbuf into video memory at the right moment
    // (when vertical retrace is beginning in monitor).
    vsync();
    blit(dblbuf, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
    clear_bitmap(dblbuf);

  }


  // ***************
  // * Cleaning up *
  // ***************

  destroy_bitmap(dblbuf);
  delete pCreature;
  delete pLight;

}

END_OF_MAIN();