/*
 * Copyright (c) 2010 Jice
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * The name of Jice may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY JICE ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL JICE BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "main.hpp"

#define WIDTH 80
#define HEIGHT 50

TCODNoise noise1d(1);
TCODNoise noise2d(2);
WorldGenerator worldGen;
// world map panning
float wx = 0, wy = 0, cur_w_x = 0, cur_w_y = 0;
// mouse coordinates in world map
float mx = 0, my = 0;

void update(float elapsed, TCOD_key_t k, TCOD_mouse_t mouse) {
  // destination wanted
  wx = (worldGen.getWidth() - 2 * WIDTH) * mouse.cx / WIDTH;
  wy = (worldGen.getHeight() - 2 * HEIGHT) * mouse.cy / HEIGHT;
  cur_w_x += (wx - cur_w_x) * elapsed;
  cur_w_y += (wy - cur_w_y) * elapsed;
  mx = cur_w_x + mouse.cx * 2;
  my = cur_w_y + mouse.cy * 2;
  worldGen.updateClouds(elapsed);
}

TCODColor getMapShadedColor(float worldX, float worldY, bool clouds) {
  // sun color
  static TCODColor sunCol(255, 255, 200);
  float wx = CLAMP(0.0f, worldGen.getWidth() - 1, worldX);
  float wy = CLAMP(0.0f, worldGen.getHeight() - 1, worldY);
  // apply cloud shadow
  float cloudAmount = clouds ? worldGen.getCloudThickness(wx, wy) : 0.0f;
  TCODColor col = worldGen.getInterpolatedColor(worldX, worldY);
  // apply sun light
  float intensity = worldGen.getInterpolatedIntensity(wx, wy);
  intensity = MIN(intensity, 1.5f - cloudAmount);
  int cr = (int)(intensity * (int)(col.r) * sunCol.r / 255);
  int cg = (int)(intensity * (int)(col.g) * sunCol.g / 255);
  int cb = (int)(intensity * (int)(col.b) * sunCol.b / 255);
  TCODColor col2;
  col2.r = CLAMP(0, 255, cr);
  col2.g = CLAMP(0, 255, cg);
  col2.b = CLAMP(0, 255, cb);
  col2.r = MAX(col2.r, col.r / 2);
  col2.g = MAX(col2.g, col.g / 2);
  col2.b = MAX(col2.b, col.b / 2);
  return col2;
}

void render() {
  // subcell resolution image
  static TCODImage map(WIDTH * 2, HEIGHT * 2);
  // compute the map image
  for (int px = 0; px < 2 * WIDTH; px++) {
    for (int py = 0; py < 2 * HEIGHT; py++) {
      // world texel coordinate (with fisheye distorsion)
      float wx = px + cur_w_x;
      float wy = py + cur_w_y;
      map.putPixel(px, py, getMapShadedColor(wx, wy, true));
    }
  }
  map.blit2x(TCODConsole::root, 0, 0);

  TCODConsole::root->setDefaultForeground(TCODColor::white);
  static const char* biomeNames[] = {
      "Tundra",
      "Cold desert",
      "Grassland",
      "Boreal forest",
      "Temperate forest",
      "Tropical/Montane forest",
      "Hot desert",
      "Savanna",
      "Tropical dry forest",
      "Tropical evergreen forest",
      "Thorn forest"};
  if (worldGen.isOnSea(mx, my)) {
    // some information are irrelevant on sea
    TCODConsole::root->printf(
        5, 47, "Alt %5dm\n\nMove the mouse to scroll the map", (int)worldGen.getRealAltitude(mx, my));
  } else {
    TCODConsole::root->printf(
        5,
        47,
        "Alt %5dm  Prec %3dcm/sq. m/y  Temp %d deg C\nBiome : %s\nMove the mouse to scroll the map",
        (int)worldGen.getRealAltitude(mx, my),
        (int)worldGen.getPrecipitations(mx, my),
        (int)worldGen.getTemperature(mx, my),
        biomeNames[worldGen.getBiome(mx, my)]);
  }
}

int main(int argc, char* argv[]) {
  // initialize the game window
  TCODConsole::initRoot(WIDTH, HEIGHT, VERSION, false, TCOD_RENDERER_SDL);
  TCODSystem::setFps(25);
  TCODMouse::showCursor(true);

  TCOD_key_t k = {TCODK_NONE, 0};
  TCOD_mouse_t mouse;

  bool endCredits = false;
  // generate the world with all data (rain, temperature and so on...)
  worldGen.generate(NULL);
  // compute light intensity on ground (depends on light direction and ground slope)
  static float lightDir[3] = {1.0f, 1.0f, 0.0f};
  worldGen.computeSunLight(lightDir);

  while (!TCODConsole::isWindowClosed()) {
    //	read keyboard
    //		TCOD_key_t k=TCODConsole::checkForKeypress(TCOD_KEY_PRESSED|TCOD_KEY_RELEASED);
    //		TCOD_mouse_t mouse=TCODMouse::getStatus();

    TCODSystem::checkForEvent((TCOD_event_t)(TCOD_EVENT_KEY_PRESS | TCOD_EVENT_MOUSE), &k, &mouse);

    if (k.vk == TCODK_PRINTSCREEN) {
      // screenshot
      if (!k.pressed) TCODSystem::saveScreenshot(NULL);
      k.vk = TCODK_NONE;
    } else if (k.lalt && (k.vk == TCODK_ENTER || k.vk == TCODK_KPENTER)) {
      // switch fullscreen
      if (!k.pressed) TCODConsole::setFullscreen(!TCODConsole::isFullscreen());
      k.vk = TCODK_NONE;
    }
    // update the game
    update(TCODSystem::getLastFrameLength(), k, mouse);

    // render the game screen
    render();
    // render libtcod credits
    if (!endCredits) endCredits = TCODConsole::renderCredits(4, 4, true);
    // flush updates to screen
    TCODConsole::root->flush();
  }
  return 0;
}
