/***************************************************************************
                          pipenightdreams.cpp  -  description
                             -------------------
    begin                : Thu Aug 17 2000
    copyright            : (C) 2000 by Waldemar Baraldi
    email                : baraldi@lacasilla.com.ar
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "pipenightdreams.h"
#include "SDL.h"
#include "str.h"
#include "imagemanager.h"
#include "eventmanager.h"
#include "playeronestream.h"
#include "level.h"
#include "score.h"
#include "sprite.h"
#include "paper.h"
#include "fire.h"
#include "random.h"

PipeNightDreams::PipeNightDreams(bool fullscreen){
  SDL_Init(SDL_INIT_VIDEO);
  VideoManager::VideoFlag fs = VideoManager::None;
  if (fullscreen) fs=VideoManager::FullScreen;

  video_manager=new VideoManager(fs);
  video_manager->setCaption(new Str("PipeNightDreams"));
  event_manager=new EventManager();
  sys = new SystemStream();
  event_manager->addStream(sys);
  data_dir=new Str();
  images_dir=new Str();
  starting_level=1;
  fullscreen=false;
}

PipeNightDreams::~PipeNightDreams(){
  delete data_dir;
  delete images_dir;
  delete video_manager;
  delete event_manager;
  delete nextlevel;
  delete tryagain;
  delete pressenter;
  SDL_Quit();
  reportLeaks();
}

void PipeNightDreams::setStartingLevel(int level){
  starting_level=level;
}

void PipeNightDreams::setDataDir(Str * dir_name){
  delete data_dir;
  delete images_dir;
  data_dir=dir_name;

  images_dir=new Str(data_dir);
  images_dir->concat("/images/");
  video_manager->getImageManager()->setBaseDir(new Str(images_dir));
}

void PipeNightDreams::run(){
  char aux[128];
  quit=false;

  load();
  showMainMenu();

  while (!quit){
    PlayerOneStream * pone = new PlayerOneStream();
    player= new Player(pone);
    player->setPos(0,0);

    bool game_over=false;
    int level_number=starting_level;
    BoardState bs;

    event_manager->addStream(pone);
    event_manager->pumpEvents();

    board=new Board();
    Level * level=new Level();

    Str * str= new Str(data_dir);
    sprintf(aux, "/levels/%i.level", level_number);
    str->concat(aux);
    int error=level->load(str);
    switch (error){
      case 1:{
        showFinal();
        break;
      }
      case -1:{
        delete level;
        game_over=true;
        break;
      }
      default:{
        sprintf(aux, "PipeNightDreams : Level %i", level_number);
        video_manager->setCaption(new Str(aux));
        break;
      }
    }


    while (!game_over){
      int entry_row, entry_column, exit_row, exit_column;
      Entry * aux_entry=level->getEntry(entry_row, entry_column);
      Exit * aux_exit=level->getExit(exit_row, exit_column);

      board->setPos(100,0);
      board->setStartDelay(level->getStartDelay());
      board->setSpeed(level->getSpeed());
      board->setBackgroundType(level->getBackgroundType());
      board->setEntry(aux_entry, entry_row, entry_column);
      board->setExit(aux_exit, exit_row, exit_column);
      board->setRequired(level->getRequired());
      video_manager->getImageManager()->addDirList(level->getGraphDirs());
      player->setRestrictionCoef(level->getRestrictionCoef());
      player->setFixedCoef(level->getFixedCoef());

      int i=level->getPipeIndex();
      int pipe_row, pipe_column;
      Pipe * aux_pipe=level->getPipe(i, pipe_row, pipe_column);

      while (aux_pipe != NULL){
        board->setPipe(aux_pipe, pipe_row, pipe_column);
        aux_pipe=level->getPipe(i, pipe_row, pipe_column);
      }

      play();
      bs=board->getState();
      delete board;
      if (bs==Playing){
        game_over=true;
        (video_manager->getImageManager())->empty();
      }else{
        sys->clear();
        switch (bs){
          case OverLost:{
            if (player->lives()>0){
              player->decLives();
              SDL_Delay(750);
              showTryAgain();
              board=new Board();
            }else{
              game_over=true;
              (video_manager->getImageManager())->empty();
              showGameOver();
            }
            break;
          }
          case OverWon:{
            (video_manager->getImageManager())->empty();
            level_number++; //Incremento el nivel
            board=new Board();

            delete level;
            level=new Level();
            Str * str= new Str(data_dir);
            sprintf(aux, "/levels/%i.level", level_number);
            str->concat(aux);
            int error=level->load(str);
            switch (error){
              case 1:{
                showFinal();
                game_over=true;
                break;
              }
              case -1:{
                game_over=true;
                break;
              }
              default:{
                showNextLevel();
                sprintf(aux, "PipeNightDreams : Level %i", level_number);
                video_manager->setCaption(new Str(aux));
                break;
              }
            }
            break;
          }
          default:break;
        }
      }
    }
    delete player;
    delete level;
    showMainMenu();
  }
}

void PipeNightDreams::showIntro(){}

void PipeNightDreams::showOptions(){}

void PipeNightDreams::play(){
  Event event;
  int c,d;
  player->setBoard(board);
  while (event!=BACK && board->getState()==Playing){
    c=SDL_GetTicks();
    event=sys->get();
    player->play();
    player->tick();
    if (player->isChanged())
      player->paint(video_manager);
    board->tick();
    board->paint(video_manager);
    video_manager->flush();
    event_manager->pumpEvents();
    d=SDL_GetTicks();
    if (d-c<(int)(1000/FPS)){
      SDL_Delay((int)(1000/FPS)-(d-c));
    }
  }
}

void PipeNightDreams::showMainMenu(){
  Event event;
  Str * aux;
  Image * main;
  Image * enter;
  bool paint=false;
  Random * r=new Random();
  int enter_delay=0;

  Fire * fire= new Fire(video_manager->getImageManager());
  fire->setPos(318, 186);

  const int nPapers=40;

  Paper * papers[nPapers];

  for (int i=0; i<nPapers; i++){
    Paper::PaperColor color;

    switch (r->getRandomNumber(0,2)){
      case 0: color=Paper::Red;break;
      case 1: color=Paper::Green;break;
      case 2: color=Paper::Blue;break;
    }
    papers[i]=new Paper(480, color, video_manager->getImageManager());
    papers[i]->setPos(r->getRandomNumber(0,630), r->getRandomNumber(0,480));
  }
  delete r;

  aux=new Str(images_dir);
  aux->concat("start.jpg");
  main=new Image(aux);

  aux=new Str(images_dir);
  aux->concat("entertostart.png");
  enter=new Image(aux);

  video_manager->setCaption(new Str("PipeNightDreams"));
  video_manager->blit(main, 0,0);

  video_manager->flush();
  do{
    for (int i=0;i<nPapers;i++){
      video_manager->blit(main,
        papers[i]->getX(),
        papers[i]->getY(),
        papers[i]->getX(),
        papers[i]->getY(),
        papers[i]->width(),
        papers[i]->height());
     }
    video_manager->blit(main, 248, 440, 248, 440, 143, 15);
    video_manager->blit(main, fire->getX(), fire->getY(),
                              fire->getX(), fire->getY(),
                              fire->width(), fire->height());

    for (int i=0;i<nPapers;i++){
      papers[i]->tick();
      papers[i]->paint(video_manager);
    }

    if ((enter_delay=(enter_delay+1)%3)==0) paint=!paint;
    if (paint) video_manager->blit(enter, 248, 440);


    fire->paint(video_manager);
    fire->tick();

    video_manager->flush();
    SDL_Delay(100);
    event_manager->pumpEvents(false);
    event=sys->get();
  }while (event!=GO && event!=BACK);
  delete main;
  delete enter;

  for (int i=0; i<nPapers; i++)
    delete papers[i];

  delete fire;

  if (event==BACK) quit=true;
}

void PipeNightDreams::showGameOver(){
  Event event;
  Image * gameover;
  Str * aux;

  aux= new Str(images_dir);
  aux->concat("gameover.png");
  gameover=new Image(aux);

  video_manager->blit(gameover, 100+270-gameover->width()/2,240-gameover->height());
  video_manager->blit(pressenter, 100+270-pressenter->width()/2,240);
  video_manager->flush();
  delete gameover;

  do{
    event_manager->pumpEvents(true);
    event=sys->get();
  }while (event!=GO);
}

void PipeNightDreams::showHallOfFame(){
}

void PipeNightDreams::showNextLevel(){
  Event event;

  video_manager->blit(nextlevel, 100+270-nextlevel->width()/2,240-nextlevel->height());
  video_manager->blit(pressenter, 100+270-pressenter->width()/2,240);
  video_manager->flush();

  do{
    event_manager->pumpEvents(true);
    event=sys->get();
  }while (event!=GO);
}

void PipeNightDreams::showTryAgain(){
  Event event;
  video_manager->blit(tryagain, 100+270-tryagain->width()/2,240-tryagain->height());
  video_manager->blit(pressenter, 100+270-pressenter->width()/2,240);
  video_manager->flush();

  do{
    event_manager->pumpEvents(true);
    event=sys->get();
  }while (event!=GO);
}

void PipeNightDreams::showFinal(){
  Event event;
  Image * done;
  Str * aux;

  aux= new Str(images_dir);
  aux->concat("alllevelsdone.png");
  done=new Image(aux);

  video_manager->blit(done, 100+270-done->width()/2,240-done->height());
  video_manager->blit(pressenter, 100+270-pressenter->width()/2,240);
  video_manager->flush();
  delete done;

  do{
    event_manager->pumpEvents(true);
    event=sys->get();
  }while (event!=GO);
}

void PipeNightDreams::load(){
  Image * loading;
  Str * aux;

  aux= new Str(images_dir);
  aux->concat("loading.png");
  loading=new Image(aux);
  video_manager->blit(loading, 320-loading->width()/2,240-loading->height()/2);
  video_manager->flush();
  delete loading;

  aux= new Str(images_dir);
  aux->concat("tryagain.png");
  tryagain=new Image(aux);

  aux= new Str(images_dir);
  aux->concat("nextlevel.png");
  nextlevel=new Image(aux);

  aux= new Str(images_dir);
  aux->concat("pressenter.png");
  pressenter=new Image(aux);
}

