/* This file is part of OpenBubbles.
 *
 * OpenBubbles is an SDL clone of Bubbles.
 * Copyright (C) 2004  Benny Sperisen
 *
 * 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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * main.cpp contains main().
 *
 * Written by:
 *  Benny Sperisen
 *  lasindi@gmail.com
 *  www.freewebs.com/lasindi
 *****************************************************************************/

#include "SDL.h"
#include "SDL_gfxPrimitives.h"
#include "SDL_image.h"
#include <iostream>
#include <string.h>
#include <string>
#include <fstream>
using namespace std;

#include "screen.h"
#include "gameloop.h"
#include "button.h"
#include "highscores.h"
#include "BFont.h"
#include "audioplayer.h"

#define BUTTONS_START 180
#define BUTTONS_SPACING 45

// Used for pulsing the cursor on the high score entry.
#define CURSOR_PULSE_RATE 20
#define UP 1
#define DOWN 0

// The rate at which the logo animation proceeds.
#define ANIMATION_RATE 5

#define ANIMATION_WIDTH 80
#define ANIMATION_HEIGHT 80

enum SCREENS {MENU,INSTRUCTIONS,GAME,HIGHSCORE};
enum ANIMATION_IMAGES {PI_ABUBBLE,ABUBBLE_VERSION,VERSION_ABUBBLE,ABUBBLE_PI};

/* The code in initButtons is called twice, so to save space, it's in a
 * separate function. */
void initButtons();

// Transitions to screen 'to' (from the SCREENS enumeration).
void transition(char to);

SDL_Surface* boxChecked;
SDL_Surface* boxUnchecked;

int main()
{
  SDL_Surface* icon;
  SDL_Surface* logo;
  SDL_Surface* visit;
  SDL_Surface* copyright;
  SDL_Surface* instructions;
  SDL_Surface* enterback;
  SDL_Surface* highbanner;
  SDL_Surface* cursor;
  SDL_Surface* abubble;
  SDL_Surface* pi;
  SDL_Surface* version;
	SDL_Surface* labels;
  SDL_Surface* from;
  SDL_Surface* to;
  SDL_Rect src,dest;
  SDL_Event event;
  BFont_Info* font;
  char* result;
  char* temp=new char[MAX_CHARACTERS+1];
  char cursor_direction,currentimage;
  double score;
  int time1,time2,diff_time,pause_time,cursor_pos,cursor_alpha,totalwidth,
      from_alpha,to_alpha;
  string datadir2,datadir3,name;
	soundOn=fadingOn=true;
  if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)!=0)
  {
    cerr<<"ERROR: unable to initialize SDL: "<<SDL_GetError()<<endl;
    return 1;
  }
  atexit(SDL_Quit);
	atexit(SDL_CloseAudio);
	atexit(saveEverything);
  screen=SDL_SetVideoMode(SCREEN_WIDTH,SCREEN_HEIGHT,32,SDL_HWSURFACE);
  if(screen==NULL)
  {
    cerr<<"ERROR: unable to set video mode: "<<SDL_GetError()<<endl;
    return 1;
  }
  loadHighScores();
	audio=new audioPlayer;
	// Load the sounds.
	datadir=DATA_PREFIX;
	datadir+="/bubble.wav";
	bubbleSound=audio->loadSound(datadir);
	datadir=DATA_PREFIX;
	datadir+="/fire.wav";
	missleSound=audio->loadSound(datadir);
	datadir=DATA_PREFIX;
	datadir+="/gameover.wav";
	gameoverSound=audio->loadSound(datadir);	
	datadir=DATA_PREFIX;
	datadir+="/bounce.wav";
	bounceSound=audio->loadSound(datadir);
	loadSettings(); // Load fadingOn and soundOn.
  // Load all of the surfaces used in main().
  datadir=DATA_PREFIX;
  datadir+="/icon.xpm";
  icon=IMG_Load(datadir.c_str());
  if(icon==NULL)
  {
    cerr<<"ERROR: unable to load icon.\n";
    exit(1);
  }
  SDL_WM_SetIcon(icon,NULL);
  datadir=DATA_PREFIX;
  datadir+="/logo.png";
  logo=IMG_Load(datadir.c_str());
  if(logo==NULL)
  {
    cerr<<"ERROR: unable to load logo.\n";
    exit(1);
  }
  datadir=DATA_PREFIX;
  datadir+="/visit.png";
  visit=IMG_Load(datadir.c_str());
  if(visit==NULL)
  {
    cerr<<"ERROR: unable to load visit.\n";
    exit(1);
  }
  datadir=DATA_PREFIX;
  datadir+="/copyright.png";
  copyright=IMG_Load(datadir.c_str());
  if(copyright==NULL)
  {
    cerr<<"ERROR: unable to load copyright.\n";
    exit(1);
  }
  datadir=DATA_PREFIX;
  datadir+="/instructions.png";
  instructions=IMG_Load(datadir.c_str());
  if(instructions==NULL)
  {
    cerr<<"ERROR: unable to load instructions.\n";
    exit(1);
  }
  datadir=DATA_PREFIX;
  datadir+="/enterback.png";
  enterback=IMG_Load(datadir.c_str());
  if(enterback==NULL)
  {
    cerr<<"ERROR: unable to load enterback.\n";
    exit(1);
  }
  datadir=DATA_PREFIX;
  datadir+="/highbanner.png";
  highbanner=IMG_Load(datadir.c_str());
  if(highbanner==NULL)
  {
    cerr<<"ERROR: unable to load highbanner.\n";
    exit(1);
  }
  datadir=DATA_PREFIX;
  datadir+="/cursor.png";
  cursor=IMG_Load(datadir.c_str());
  if(cursor==NULL)
  {
    cerr<<"ERROR: unable to load cursor.\n";
    exit(1);
  }
  datadir=DATA_PREFIX;
  datadir+="/pi.png";
  pi=IMG_Load(datadir.c_str());
  if(pi==NULL)
  {
    cerr<<"ERROR: unable to load pi.\n";
    exit(1);
  }
  datadir=DATA_PREFIX;
  datadir+="/version.png";
  version=IMG_Load(datadir.c_str());
  if(version==NULL)
  {
    cerr<<"ERROR: unable to load version.\n";
    exit(1);
  }
  datadir=DATA_PREFIX;
  datadir+="/abubble.png";
  abubble=IMG_Load(datadir.c_str());
  if(abubble==NULL)
  {
    cerr<<"ERROR: unable to load abubble.\n";
    exit(1);
  }
	datadir=DATA_PREFIX;
  datadir+="/labels.png";
  labels=IMG_Load(datadir.c_str());
  if(abubble==NULL)
  {
    cerr<<"ERROR: unable to load labels.png.\n";
    exit(1);
  }
	datadir=DATA_PREFIX;
  datadir+="/checkshot.png";
  boxChecked=IMG_Load(datadir.c_str());
  if(boxChecked==NULL)
  {
    cerr<<"ERROR: unable to load checkshot.png.\n";
    exit(1);
  }
	datadir=DATA_PREFIX;
  datadir+="/checkboxshot.png";
  boxUnchecked=IMG_Load(datadir.c_str());
  if(boxUnchecked==NULL)
  {
    cerr<<"ERROR: unable to load checkboxshot.png.\n";
    exit(1);
  }
  datadir=DATA_PREFIX;
  datadir+="/font2.png";
  font=BFont_LoadFont(datadir.c_str());
  if(font==NULL)
  {
    cerr<<"ERROR: unable to load font2.\n";
    exit(1);
  }
	audio->clearSounds();
	SDL_PauseAudio(0);
  for(;;)
  {
    initButtons();
    SDL_WM_SetCaption("OpenBubbles","OpenBubbles");
    currentimage=PI_ABUBBLE;
    from_alpha=255;
    to_alpha=0;
    from=pi;
    to=abubble;
    for(;;)
    {
      time1=clock()/CLOCKS_PER_SEC; //get time at start of loop
      result=handleButtons();
			fadingOn=isChecked("fading");
			soundOn=isChecked("sound");
			audio->mute(!soundOn);
      while(SDL_PollEvent(&event))
      {
        if(event.type==SDL_QUIT)
          goto leave;
        else if((event.type==SDL_KEYUP)&&(event.key.keysym.sym==SDLK_RETURN))
          result="start";
      }
      boxRGBA(screen,0,0,SCREEN_WIDTH-1,SCREEN_HEIGHT-1,0,0,0,255);
      // Animation code.
      switch(currentimage)
      {
        case PI_ABUBBLE:
          from=pi;
          to=abubble;
          break;
        case ABUBBLE_VERSION:
          from=abubble;
          to=version;
          break;
        case VERSION_ABUBBLE:
          from=version;
          to=abubble;
          break;
        case ABUBBLE_PI:
          from=abubble;
          to=pi;
      }
      to_alpha+=ANIMATION_RATE;
      if(to_alpha>=255)
      {
        SDL_SetAlpha(to,SDL_SRCALPHA,255);
        // Rotate the images.
        if(currentimage==ABUBBLE_PI)
          currentimage=PI_ABUBBLE;
        else
          currentimage++;
        to_alpha=0;
      }
      else
      {
        SDL_SetAlpha(from,SDL_SRCALPHA,from_alpha);
        SDL_SetAlpha(to,SDL_SRCALPHA,to_alpha);
      }
      // Logo blitting.
      src.x=0;
      src.y=0;
      src.w=logo->w;
      src.h=logo->h;
      dest.x=SCREEN_WIDTH/2-src.w/2;
      dest.y=10;
      dest.w=src.w;
      dest.h=src.h;
      SDL_BlitSurface(logo,&src,screen,&dest);
      // Animation blitting.
      src.w=ANIMATION_WIDTH;
      src.h=ANIMATION_HEIGHT;
      dest.x=SCREEN_WIDTH/2+105;
      dest.y=115;
      dest.w=src.w;
      dest.h=src.h;
      SDL_BlitSurface(from,&src,screen,&dest);
      SDL_BlitSurface(to,&src,screen,&dest);
      // "Visit ..." blitting.
      src.w=visit->w;
      src.h=visit->h;
      dest.x=SCREEN_WIDTH/2-src.w/2;
      dest.y=360;
      dest.w=src.w;
      dest.h=src.h;
      SDL_BlitSurface(visit,&src,screen,&dest);
      // Copyright notice blitting.
      src.w=copyright->w;
      src.h=copyright->h;
      dest.x=SCREEN_WIDTH/2-src.w/2;
      dest.y=380;
      dest.w=src.w;
      dest.h=src.h;
      SDL_BlitSurface(copyright,&src,screen,&dest);
			// Checkbox label blitting.
			src.w=labels->w;
			src.h=labels->h;
			dest.x=SCREEN_WIDTH/2+120;
			dest.y=232;
			dest.w=src.w;
			dest.h=src.h;
			SDL_BlitSurface(labels,&src,screen,&dest);
      drawButtons();
      SDL_UpdateRect(screen,0,0,screen->w,screen->h);
      if(strcmp(result,"start")==0)
      {
				if(fadingOn)
					transition(GAME);
        break;
      }
      // Load the instructions.
      else if(strcmp(result,"instructions")==0)
      {
        for(list<button*>::iterator i=buttons.begin();i!=buttons.end();i++)
          (*i)->freeSurfaces();
        buttons.clear();
				checkboxes.clear();
				buttons.push_back(new button(SCREEN_WIDTH/2-140,420,"return.png",
																		 "return","return_hilight.png",
																		 "return_pressed.png"));
        if(fadingOn)
					transition(INSTRUCTIONS);
        for(;;)
        {
          time1=clock()/CLOCKS_PER_SEC; //get time at start of loop
          while(SDL_PollEvent(&event))
            if(event.type==SDL_QUIT)
              goto leave;
          boxRGBA(screen,0,0,SCREEN_WIDTH-1,SCREEN_HEIGHT-1,0,0,0,255);
          src.x=0;
          src.y=0;
          src.w=instructions->w;
          src.h=instructions->h;
          dest.x=SCREEN_WIDTH/2-src.w/2;
          dest.y=10;
          dest.w=src.w;
          dest.h=src.h;
          SDL_BlitSurface(instructions,&src,screen,&dest);
          drawButtons();
          SDL_UpdateRect(screen,0,0,screen->w,screen->h);
          if(strcmp(handleButtons(),"return")==0)
            break;
          else if(strcmp(handleButtons(),"quit")==0)
            goto leave;
          time2=clock()/CLOCKS_PER_SEC; //get time at end of loop
          diff_time=time2-time1;    //compare...
          pause_time=30-diff_time;
          SDL_Delay(pause_time);    //and pause for required amount of time
        }
        for(list<button*>::iterator i=buttons.begin();i!=buttons.end();i++)
          (*i)->freeSurfaces();
        buttons.clear();
				checkboxes.clear();
        while(SDL_PollEvent(&event)); // Flush events.
        initButtons();
        currentimage=PI_ABUBBLE;
        from_alpha=255;
        to_alpha=0;
        from=pi;
        to=abubble;
				if(fadingOn)
					transition(MENU);
      }
      else if(strcmp(result,"highscores")==0)
      {
        displayHighScores(fadingOn);
        buttons.clear();
        while(SDL_PollEvent(&event)); // Flush events.
        initButtons();
      }
      else if(strcmp(result,"quit")==0)
        goto leave;
      time2=clock()/CLOCKS_PER_SEC; //get time at end of loop
      diff_time=time2-time1;    //compare...
      pause_time=30-diff_time;
      SDL_Delay(pause_time);    //and pause for required amount of time
    }
    score=gameloop();
    // Check to see if the player got a high score.
    for(vector<highscore>::iterator i=high_scores.begin();i!=high_scores.end();
				i++)
      if(score>(*i).score()) // They got one.
      {
        for(list<button*>::iterator j=buttons.begin();j!=buttons.end();j++)
          (*j)->freeSurfaces();
        buttons.clear();
				checkboxes.clear();
			  buttons.push_back(new button(SCREEN_WIDTH/2-70,
																		 SCREEN_HEIGHT/2-enterback->h/2+62,
																		 "ok.png","ok","ok_hilight.png",
																		 "ok_pressed.png"));
				buttons.push_back(new button(SCREEN_WIDTH/2+3,
																		 SCREEN_HEIGHT/2-enterback->h/2+62,
																		 "cancel.png","cancel",
																		 "cancel_hilight.png",
																		 "cancel_pressed.png"));
        src.x=src.y=0;
        cursor_pos=0;
        name="";
        SDL_EnableKeyRepeat(300,30);
        cursor_alpha=0;
        cursor_direction=UP;
				if(fadingOn)
					transition(HIGHSCORE);
        for(;;)
        {
          time1=clock()/CLOCKS_PER_SEC; //get time at start of loop
          result=handleButtons();
          while(SDL_PollEvent(&event))
          {
            if(event.type==SDL_QUIT)
              goto leave;
            else if((event.type==SDL_KEYUP)&&
                    (event.key.keysym.sym==SDLK_RETURN))
              result="ok";
            else
              typestr(event,name,cursor_pos,font);
          }
          if(cursor_direction==UP)
          {
            cursor_alpha+=CURSOR_PULSE_RATE;
            if(cursor_alpha>=255)
            {
              cursor_alpha=255;
              cursor_direction=DOWN;
            }
          }
          else
          {
            cursor_alpha-=CURSOR_PULSE_RATE;
            if(cursor_alpha<=0)
            {
              cursor_alpha=0;
              cursor_direction=UP;
            }
          }
          SDL_SetAlpha(cursor,SDL_SRCALPHA,cursor_alpha);
          boxRGBA(screen,0,0,SCREEN_WIDTH-1,SCREEN_HEIGHT-1,0,0,0,255);
          src.w=highbanner->w;
          src.h=highbanner->h;
          dest.x=SCREEN_WIDTH/2-src.w/2;
          dest.y=SCREEN_HEIGHT/4-src.h/2;
          dest.w=src.w;
          dest.h=src.h;
          SDL_BlitSurface(highbanner,&src,screen,&dest);
          src.w=enterback->w;
          src.h=enterback->h;
          dest.x=SCREEN_WIDTH/2-src.w/2;
          dest.y=SCREEN_HEIGHT/2-src.h/2;
          dest.w=src.w;
          dest.h=src.h;
          SDL_BlitSurface(enterback,&src,screen,&dest);
          for(unsigned int j=0;j<name.length();j++)
            temp[j]=name[j];
          temp[name.length()]='\0';
          BFont_PutStringFont(screen,font,dest.x+33,dest.y+40,temp);
          totalwidth=0;
          for(int j=0;j<cursor_pos;j++)
            totalwidth+=BFont_CharWidth(font,name[j]);
          src.w=cursor->w;
          src.h=cursor->h;
          dest.x+=33+totalwidth;
          dest.y+=40;
          dest.w=src.w;
          dest.h=src.h;
          SDL_BlitSurface(cursor,&src,screen,&dest);
          drawButtons();
          SDL_UpdateRect(screen,0,0,screen->w,screen->h);
          if(strcmp(result,"ok")==0)
          {
            high_scores.insert(i,highscore(name,(int)score));
            high_scores.pop_back();
            saveEverything();
            break;
          }
          else if(strcmp(result,"cancel")==0)
            break;
          time2=clock()/CLOCKS_PER_SEC; //get time at end of loop
          diff_time=time2-time1;    //compare...
          pause_time=30-diff_time;
          SDL_Delay(pause_time);    //and pause for required amount of time
        }
        SDL_EnableKeyRepeat(0,0);
        for(list<button*>::iterator i=buttons.begin();i!=buttons.end();i++)
          (*i)->freeSurfaces();
        buttons.clear();
				checkboxes.clear();
        while(SDL_PollEvent(&event)); // Flush events.
        initButtons();
        break;
      }
		if(fadingOn)
			transition(MENU);
    for(list<bubble*>::iterator i=bubs.begin();i!=bubs.end();i++)
      (*i)->freeSurfaces();
    bubs.clear();
    crumbs.clear();
		missles.clear();
    for(list<button*>::iterator i=buttons.begin();i!=buttons.end();i++)
      (*i)->freeSurfaces();
    buttons.clear();
		checkboxes.clear();
  }
leave:
  bubs.clear();
  crumbs.clear();
  for(list<button*>::iterator i=buttons.begin();i!=buttons.end();i++)
    (*i)->freeSurfaces();
  buttons.clear();
	checkboxes.clear();
	SDL_FreeSurface(labels);
	SDL_FreeSurface(boxChecked);
	SDL_FreeSurface(boxUnchecked);
  SDL_FreeSurface(pi);
  SDL_FreeSurface(version);
  SDL_FreeSurface(abubble);
  SDL_FreeSurface(enterback);
  SDL_FreeSurface(highbanner);
  SDL_FreeSurface(screen);
  SDL_FreeSurface(icon);
  SDL_FreeSurface(logo);
  SDL_FreeSurface(instructions);
  SDL_FreeSurface(visit);
  SDL_FreeSurface(copyright);
  SDL_FreeSurface(cursor);
  BFont_FreeFont(font);
  delete[] temp;
	delete audio;
  return 0;
}

void initButtons()
{
	checkbox* fadingbox=new checkbox(SCREEN_WIDTH/2+128,246,"fading",fadingOn);
	checkbox* soundbox=new checkbox(SCREEN_WIDTH/2+128,269,"sound",soundOn);
	buttons.push_back(new button(SCREEN_WIDTH/2-101,BUTTONS_START,"start.png",
															 "start","start_hilight.png",
															 "start_pressed.png"));
	buttons.push_back(new button(SCREEN_WIDTH/2-101,
															 BUTTONS_START+BUTTONS_SPACING,
															 "instructions_button.png","instructions",
															 "instructions_hilight.png",
															 "instructions_pressed.png"));
  buttons.push_back(new button(SCREEN_WIDTH/2-101,
															 BUTTONS_START+2*BUTTONS_SPACING,
															 "highscores.png",
															 "highscores","highscores_hilight.png",
															 "highscores_pressed.png"));
	buttons.push_back(new button(SCREEN_WIDTH/2-101,
															 BUTTONS_START+3*BUTTONS_SPACING,"quit.png",
															 "quit","quit_hilight.png","quit_pressed.png"));
	checkboxes.push_back(fadingbox);
	checkboxes.push_back(soundbox);
	buttons.push_back(fadingbox);
	buttons.push_back(soundbox);
}

void transition(char to)
{
  string datadir;
  int time1,time2,diff_time,pause_time; // Time loop
  SDL_Surface* from_surface;
  SDL_Surface* to_surface;
  SDL_Rect src,dest;
  datadir=DATA_PREFIX;
  datadir+="/menushot.png";
  from_surface=IMG_Load(datadir.c_str());
  if(from_surface==NULL)
  {
    cerr<<"ERROR: unable to load from_surface.\n";
    exit(1);
  }
	// Get the SDL_Rects ready.
  src.x=src.y=dest.x=dest.y=0;
  src.w=dest.w=SCREEN_WIDTH;
  src.h=dest.h=SCREEN_HEIGHT;
  SDL_BlitSurface(screen,&src,from_surface,&dest);
  switch(to)
  {
  case MENU:
    datadir=DATA_PREFIX;
    datadir+="/menushot.png";
    to_surface=IMG_Load(datadir.c_str());
    if(to_surface==NULL)
    {
      cerr<<"ERROR: unable to load menushot.\n";
      exit(1);
    }
		src.x=src.y=0;
		src.w=boxChecked->w;
		src.h=boxChecked->h;
		dest.x=448;
		dest.y=246;
		dest.w=src.w;
		dest.h=src.h;
		if(fadingOn)
			SDL_BlitSurface(boxChecked,&src,to_surface,&dest);
		else
			SDL_BlitSurface(boxUnchecked,&src,to_surface,&dest);
		dest.y=269;
		if(soundOn)
			SDL_BlitSurface(boxChecked,&src,to_surface,&dest);
		else
			SDL_BlitSurface(boxUnchecked,&src,to_surface,&dest);
    boxRGBA(screen,0,0,SCREEN_WIDTH-1,SCREEN_HEIGHT-1,0,0,0,255);
		// Reset the SDL_Rects.
		src.x=src.y=dest.x=dest.y=0;
		src.w=dest.w=SCREEN_WIDTH;
		src.h=dest.h=SCREEN_HEIGHT;
    break;
  case INSTRUCTIONS:
    datadir=DATA_PREFIX;
    datadir+="/instructionsshot.png";
    to_surface=IMG_Load(datadir.c_str());
    if(to_surface==NULL)
    {
      cerr<<"ERROR: unable to load instructionsshot.\n";
      exit(1);
    }
    break;
  case GAME:
    datadir=DATA_PREFIX;
    datadir+="/gameshot.png";
    to_surface=IMG_Load(datadir.c_str());
    if(to_surface==NULL)
    {
      cerr<<"ERROR: unable to load gameshot.\n";
      exit(1);
    }
    break;
  case HIGHSCORE:
    datadir=DATA_PREFIX;
    datadir+="/highshot.png";
    to_surface=IMG_Load(datadir.c_str());
    if(to_surface==NULL)
    {
      cerr<<"ERROR: unable to load highshot.\n";
      exit(1);
    }
    break;
  default:
    cerr<<"ERROR: invalid argument passed to transition().\n";
    exit(1);
  }
  for(int i=0;i<256;i+=TRANSITION_SPEED)
  {
    time1=clock()/CLOCKS_PER_SEC; //get time at start of loop
    boxRGBA(screen,0,0,SCREEN_WIDTH-1,SCREEN_HEIGHT-1,0,0,0,255);
    SDL_SetAlpha(from_surface,SDL_SRCALPHA,255-i);
    SDL_SetAlpha(to_surface,SDL_SRCALPHA,i);
    SDL_BlitSurface(from_surface,&src,screen,&dest);
    SDL_BlitSurface(to_surface,&src,screen,&dest);
    SDL_UpdateRect(screen,0,0,screen->w,screen->h);
    time2=clock()/CLOCKS_PER_SEC; //get time at end of loop
    diff_time=time2-time1;    //compare...
    pause_time=25-diff_time;
    SDL_Delay(pause_time);    //and pause for required amount of time
  }
  SDL_FreeSurface(from_surface);
  SDL_FreeSurface(to_surface);
}
