#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include <SDL/SDL.h>
#include <SDL/SDL_audio.h>
#include <SDL/SDL_mixer.h>

/* P.K. */
#include "macros.h"
#include "types.h"
#include "common.h"

#include "SFont.h"

#include "main.h"
#include "sprites.h"
#include "options.h"
#include "son.h"

#include "scenario.h"

/* P.K. Various languages localization */
#include <locale.h>
#include <libintl.h>

int ntourbillon = 5000;
struct {
  float x;
  float y;
} tourbillon[5000];

typedef struct {
  int x;
  int y;
  int coul;
} Blob;

Coord centre;
int delai=30;
float T=0.05;
float coef=1.05;
SDL_Surface * police;
SDL_Surface * texte[100];
Sprite * citrouille;
Sprite * bombe;
Sprite * rien;

void defiltourbillon(void)
{
  int i, coul;
  float x, y, X, Y;

  X=(float)centre.x;
  Y=(float)centre.y;

  for (i=0; i < ntourbillon; i++) {
    x=tourbillon[i].x-X;
    y=tourbillon[i].y-Y;
    x=x*coef;
    y=y*coef;
    tourbillon[i].x=x*cos(T)-y*sin(T)+X;
    tourbillon[i].y=y*cos(T)+x*sin(T)+Y;
  }

  VERROUILLE;
  for (i=0; i<ntourbillon; i++) {
    if (0 <= tourbillon[i].x && tourbillon[i].x < resolution.window_width && 0 <= tourbillon[i].y && tourbillon[i].y < resolution.window_height) {
      coul = 9-(sqrt( pow( (int)(tourbillon[i].x-X),2 ) + pow( (int)(tourbillon[i].y-Y),2 ) )/50)+2;
      if (coul<11)
	((Uint8 *)ecran->pixels) [(int)(tourbillon[i].y)*resolution.window_width+(int)(tourbillon[i].x)] = coul;
    }
    else {
      tourbillon[i].x = aleat(resolution.window_width);
      tourbillon[i].y = aleat(resolution.window_height);
    }
  }
  DEVERROUILLE;
}


void mixe(int n, int ligne, int ord)
{
  int i, j;
  int x, y;
#define HMIN 120
#define HLIGNE 25
  //  SDL_Surface *a;
  //  SDL_Rect r={0, ord, 640, 25};

  /* Cas 1: le texte se forme */
  if (n<30)// || n>80)
    {
      if (n>60) {
	n = HMIN-n;
      }
      VERROUILLE;
      //a=SDL_DisplayFormat(texte[ligne]);
      //SDL_BlitSurface(a, NULL, ecran, &r);
      for (i=0; i<25; i++) {
	for (j=0; j<resolution.window_width; j++)
	  {
	    if ( ((Uint16 *)(texte[ligne]->pixels + i*texte[ligne]->pitch)) [j] )
	      {
		y = ord + i + (aleat(30-n)-(30-n)/2) /3;
		x =       j + (aleat(30-n)-(30-n)/2) /3;
		if (0<=x && x<resolution.window_width 
		    && 0<=y && y<resolution.window_height && aleat(30-n)<10)
		  ((Uint8 *)(ecran->pixels + y*ecran->pitch)) [x] = aleat(8)+3;
	      }
	  }
      }
      DEVERROUILLE;
    }
  /* Cas 2 : Le texte défile */
  else
    {
      VERROUILLE;
      for (i = ord<HMIN ? HMIN-ord : 0; i<HLIGNE; i++) {
	for (j=0; j<resolution.window_width; j++) {
	  if ( ((Uint16 *)(texte[ligne]->pixels + i*texte[ligne]->pitch)) [j] ) {
	    ((Uint8 *)ecran->pixels) [(ord+i)*ecran->pitch + j] = aleat(8)+3;
	  }
	}
      }
      x = aleat(560)+40;
      //      for (i=-20; i<20; i++)
      //	((Uint8 *)ecran->pixels) [HMIN*ecran->pitch+x+i] = aleat(6)+3;
      DEVERROUILLE;
    }
}


void etapes(void)
{
  int i, j, k;
  int vit=3;
  int y=-32;
  SDL_Rect tout={0, 0, resolution.window_width, resolution.window_height};

  /* Étape 1 : arrivée de la citrouille */

  VITESSE=10;
  for (i=-32; i<304; i++)
    {
      ajustevitesse();
      SDL_PumpEvents();
      blitsprit(citrouille, 0, ((i+32)/8)%6, i, 224);
      if ((i+32)%48 == 47)
	bruitsplus(s_citrouille, 1);
      SDL_Flip(ecran);
      if (dblebuf) {
	blitsprit(rien, 0, 0, i-1, 224);
      }
      else {
	blitsprit(rien, 0, 0, i, 224);
      }
      clavier = SDL_GetKeyState(NULL);
      if (clavier[SDLK_ESCAPE] == SDL_PRESSED) {
	return;
      }
    }

  /* Étape 2 : pose de la bombe et fuite */
  bruitsplus(s_rire, 1);
  for (i=304; i <= resolution.window_width; i+=2)
    {
      ajustevitesse();
      SDL_PumpEvents();
      blitsprit(bombe, 0, ((i+32)/16)%4, 304, 224);
      blitsprit(citrouille, 0, ((i+32)/8)%6, i, 224);
      if ((i+32)%48 == 46) {
	bruitsplus(s_citrouille, 1);
      }
      SDL_Flip(ecran);
      blitsprit(rien, 0, 0, 304, 224);
      if (dblebuf) {
	blitsprit(rien, 0, 0, i-2, 224);
      }
      else {
	blitsprit(rien, 0, 0, i, 224);
      }
      clavier=SDL_GetKeyState(NULL);
      if (clavier[SDLK_ESCAPE]==SDL_PRESSED) {
	return;
      }
    }

  /* Étape 3 : la mèche se consume... */
  for (i=0; i < 5; i++) {
    for (j=0; j < 40; j++) {
	ajustevitesse();
	SDL_PumpEvents();
	blitsprit(bombe, i, (j/8)%4, 304, 224);
	SDL_Flip(ecran);
	blitsprit(rien, 0, 0, 304, 224);
	clavier=SDL_GetKeyState(NULL);
	if (clavier[SDLK_ESCAPE]==SDL_PRESSED) {
	  return;
	}
    }
  }

  /* Étape 4 : EXPLOSION ! */
  bruitsplus(s_expl, 1);
  for (i=0; i < 10; i++)
    {
      SDL_FillRect(ecran, &tout, i);
      SDL_Flip(ecran);
    }
  if (avecmusique) {
    Mix_PlayMusic(musintro, 1);
  }

  /* Étape 5 : défilement du texte */
  for (i=-13, j=0; i < nlignes-3; i++, j-=30)
    while (j<30) {
      Uint32 temps=SDL_GetTicks();

      SDL_PumpEvents();
      SDL_FillRect(ecran, &tout, 0);
      defiltourbillon();
      for (k=4; k<13; k++)
	if (0<=k+i && k+i<nlignes)
	  mixe(j-k*30+300, k+i, k*30-j);

      if (i>=nlignes-13) { /* Étape 6 : Toutes les lignes ont apparu ; maintenant, une nouvelle bombe ! */
	int i2=(i-(nlignes-13))*30+j;
	if (vit!=0 || y < 224) vit += 3-vit%3;
	y += vit;
	if (y>=224)
	  {
	    y=224;
	    vit = -abs(vit*0.9);
	    //if (vit) bruitsplus(s_bouton, 1);
	  }
	if (i2/40 >= 5)
	  goto Suite; /* La bombe explose : on sort des deux boucles */
	blitsprit(bombe, (i2/40)%5, (i2/4)%3, 304, y);
      }

      SDL_Flip(ecran);

      clavier=SDL_GetKeyState(NULL);
      if (clavier[SDLK_SPACE] == SDL_PRESSED) {
	j=30;
	break;
      }
      if (clavier[SDLK_ESCAPE] == SDL_PRESSED) {
	return;
      }

      temps = (SDL_GetTicks()-temps) /32;
      j+= temps ? temps : 1;	
    }

 Suite:

  /* Étape 7 : EXPLOSION ! */
  for (i=0; i <10 ; i++) {
    SDL_FillRect(ecran, &tout,  i);
    SDL_Flip(ecran);
  }
  videcran();
  return;
}


void intro(void)
{
  int i;
  char chemin[MAX_STRING_LENGTH];
  int vitessesg=VITESSE;
  /* Sauvegarder la vitesse de jeu car l'intro la modifie */
  decl=0;

  for (i=0; i < nlignes; i++) {
    texte[i]=SDL_CreateRGBSurface (0, resolution.window_width, 25, 16, 0,0,0,0);
    if (texte[i]==NULL) errormessage("Pas assez de mémoire disponible, désolé", NULL);
  }
  rien = charge_sprite("intro.spr", decl);
  citrouille = charge_sprite("citrouille.spr", decl);
  bombe = charge_sprite("bombe.spr", decl);


  sprintf(chemin, "%s/font.bmp", prefixeimg);
  police = SDL_LoadBMP(chemin);
  if (police == NULL) {
    errormessage("Impossible de charger", chemin);
  }

  InitFont(police);
  for (i=0; i < nlignes; i++) {
    PutString(texte[i], (resolution.window_width-TextWidth(scenario[langue][i]))/2, 0, scenario[langue][i]);
  }

  for (i=0; i < ntourbillon; i++) {
    tourbillon[i].x=aleat(resolution.window_width);
    tourbillon[i].y=aleat(resolution.window_height);
  }
  centre.x = resolution.window_width/2;
  centre.y = resolution.window_height/2;
  
  etapes();

  for (i=0; i < nlignes; i++) {
    SDL_FreeSurface(texte[i]);
  }
  detruit_sprites();
  if (s_citrouille) {
    Mix_FreeChunk(s_citrouille);
  }
  if (s_rire) {
    Mix_FreeChunk(s_rire);
  }
  VITESSE = vitessesg;

  return;
}

/* Mmmm, pas mal de code assez pas beau qui sert à faire l'effet de flammes dans le titre */
Blob * genereblob(Blob * blob, SDL_Surface * sortie, int deb_pal, int nb_coul, int x, int y)
{
  int i, j;
  int nblobs=x*y/60;
  SDL_Rect rect={0, 0, x, y};

  SDL_FillRect(sortie, &rect, deb_pal);
  if (blob == NULL) {
    blob=(Blob *)calloc(nblobs, sizeof(Blob));
    for (i=0; i<nblobs; i++) {
      blob[i].x=aleat(x);
      blob[i].y=aleat(y+20)-10;
      blob[i].coul=0;
    }
  }
  else {
    for (i=0; i<nblobs; i++) {
      blob[i].x += aleat(9)-4;
      blob[i].y -= 3;
      blob[i].coul += aleat(3)-1;
      if (blob[i].coul<0) blob[i].coul=nb_coul-1;
      if (blob[i].coul>=nb_coul || blob[i].y<-10) {
	blob[i].coul=0;
	blob[i].x=aleat(x);
	blob[i].y=y+10;
      }
    }
  }
  for (i=0; i<nb_coul; i++) {
    for (j=0; j<nblobs; j++) {
      if (nb_coul-blob[j].coul>=i)
	{
	  rect.w=rect.h=nb_coul-i-blob[j].coul+1;
	  rect.x=blob[j].x-rect.w/2;
	  rect.y=blob[j].y-rect.h/2;
	  SDL_FillRect(sortie, &rect, deb_pal+i);
	}
    }
  }
  return blob;
}


void blobifietexte(SDL_Surface * dest, SDL_Surface * texte, SDL_Surface * motif, int y)
{
  int i, j;
  int a, l; /* Bornes pour la copie mémoire */
  int w = texte->w;
  int orig = y * motif->pitch + (motif->w - texte->w) / 2;

  Uint16 * pixtexte = (Uint16 *) texte->pixels;

  SDL_FillRect(dest, NULL, 0);
  SDL_LockSurface(dest);
  for (i=0; i<texte->h; i++) {
    j = 0;
    pixtexte = (Uint16 *) (texte->pixels + i*texte->pitch);
    while (j<w) {
      while ( j<w && pixtexte[j]==0 ) {
	j++;
      }
      a=j; l=1; j++;
      while ( j<w && pixtexte[j]!=0 ) {
	j++;
	l++;
      }
      if (a<w) {
	memcpy(dest->pixels + i*dest->pitch + a, motif->pixels + orig + i*motif->pitch + a, l);
      }
    }
  }

  SDL_UnlockSurface(dest);
}


SDL_Surface * zoom(SDL_Surface * S1, float factx, float facty)
{
  int i, j, x, y;
  SDL_Surface * S2;
  int w1 = S1->w, h1 = S1->h;
  int w2 = (int)(factx*(float)w1), h2 = (int)(facty*(float)h1);
  S2 = SDL_CreateRGBSurface(SDL_HWSURFACE|SDL_SRCCOLORKEY, w2, h2, 8, 0,0,0,0);
  
  SDL_SetColors(S2, S1->format->palette->colors, 0, S1->format->palette->ncolors);
  SDL_SetColorKey(S2, SDL_SRCCOLORKEY, 0);

  factx=(float)w2/(float)w1;
  facty=(float)h2/(float)h1;

  SDL_LockSurface(S2);
  SDL_LockSurface(S1);
  for (i=0; i < h2; i++) {
    y = (int)(i/facty);
    for (j=0; j < w2; j++) {
      x=(int)(j/factx);
      ((Uint8 *)S2->pixels) [i*S2->pitch +j] = ((Uint8 *)S1->pixels) [y*S1->pitch +x];
    }
  }
  SDL_UnlockSurface(S1);
  SDL_UnlockSurface(S2);

  return S2;
}  


void ecrantexte(char texte[8][20], char *fond, int nlignes, int effet)
{
  int i, j;
  int longueur[20], ncoul=1;
  char chemin[MAX_STRING_LENGTH];

  Blob * text_blob=NULL;
  SDL_Rect dest[20], recfond; //x, tout; P.K.
  //  SDL_Surface * svgecran;
  SDL_Surface * imgfond=NULL;
  SDL_Surface * imgtexte[20];
  SDL_Surface * imgblob;
  SDL_Surface * lignefinale[20];
  SDL_Event evt;
  SDL_Color degrade[15];

  //  svgecran=SDL_DisplayFormat(ecran);

  videcran();

  sprintf(chemin, "%s/font.bmp", prefixeimg);
  police=SDL_LoadBMP(chemin);

  if (fond)
    {
      sprintf(chemin, "%s/%s", prefixeimg, fond);
      imgfond=SDL_LoadBMP(chemin);
      if (imgfond==NULL) fond=NULL;
      else {
	ncoul=imgfond->format->palette->ncolors+1;
	SDL_SetColors(ecran, imgfond->format->palette->colors, 1, ncoul-1); }
    }

  for (i=0; i<15; i++)
    {
      degrade[i].r=180+5*i;
      degrade[i].g=17*i;
      degrade[i].b=i;
    }
  SDL_SetColors(ecran, degrade, ncoul, 15);
      
  if (police==NULL) 
    errormessage("Impossible de charger", chemin);

  InitFont(police);
  
  imgblob=SDL_CreateRGBSurface(0, resolution.window_width, 30*nlignes-5, 8, 0,0,0,0);

  //SDL_SetColors(imgblob, degrade, ncoul, 15);

  for (i=0; i<nlignes; i++)
    {
      while ( resolution.window_width < (longueur[i] = TextWidth(texte[i])) )
	texte[i][strlen(texte[i])-1]='\0';
      dest[i].y=(resolution.window_height-(30*nlignes-5))/2+30*i;
      dest[i].x=(resolution.window_width-longueur[i])/2;
      dest[i].w=longueur[i];
      dest[i].h=25;
      imgtexte[i]=SDL_CreateRGBSurface(0, resolution.window_width, 25, 16, 0,0,0,0);
      //SDL_FillRect(imgtexte[i], NULL, 0);
      PutString(imgtexte[i], 0, 0, texte[i]);
      //SDL_BlitSurface(imgtexte, NULL, ecran, &dest);
      //SDL_FreeSurface(imgtexte);
      lignefinale[i]=SDL_CreateRGBSurface(SDL_SRCCOLORKEY, dest[i].w, dest[i].h, 8,0,0,0,0);
      SDL_SetColors(lignefinale[i], degrade, ncoul, 15);
      SDL_SetColorKey(lignefinale[i], SDL_SRCCOLORKEY, 0);
    }


  //  SDL_UpdateRect(ecran, 0, 0, 0, 0);
  //  SDL_Delay(2000);

  if (fond)
    {
      recfond.w=imgfond->w;
      recfond.h=imgfond->h;
      recfond.x=(resolution.window_width-recfond.w)/2;
      recfond.y=(resolution.window_height-recfond.h)/2;
      SDL_BlitSurface(imgfond, NULL, ecran, &recfond);
      SDL_Flip(ecran);
      if (dblebuf)
	SDL_BlitSurface(imgfond, NULL, ecran, &recfond);
    }
  
  while (SDL_PollEvent(&evt)); /* Vider la file d'évènements */

  for (i=4; i<54 || evt.type!=SDL_KEYDOWN; i++)
    {
      text_blob=genereblob(text_blob, imgblob, ncoul, 15, resolution.window_width, 30*nlignes-5);
      for (j=0; j<nlignes; j++) {
	if (texte[j]!='\0') {
	  blobifietexte(lignefinale[j], imgtexte[j], imgblob, j ? j*30-5 : 0);
	}
      }

      for (j=0; j < nlignes; j++) {
	if (effet == 1) {
	  float a = i < 16 ? 54.0 / (i*1.5+3.0) : 2.0;
	  SDL_Surface * S;
	  SDL_Rect dest;
	  S = zoom(lignefinale[j], a, a);
	  dest.x=(resolution.window_width - S->w)/2;
	  dest.y=(int)((1.0*resolution.window_height - (nlignes*S->h))/2.0 + (float)(j*S->h));
	  dest.w=S->w; dest.h=S->h;
	  SDL_BlitSurface(S, NULL, ecran, &dest);
	  SDL_FreeSurface(S);
	}
	    
	else {
	  SDL_BlitSurface(lignefinale[j], NULL, ecran, &dest[j]);
	}
      }
      SDL_Flip(ecran);
      if (effet) {
	SDL_FillRect(ecran, NULL, 0);
	if (fond) SDL_BlitSurface(imgfond, NULL, ecran, &recfond);
      }
      SDL_PollEvent(&evt);
      SDL_Delay(20);
    }
  
  videcran();
  //  SDL_SetColors(ecran, svgecran->format->palette->colors, 0, svgecran->format->palette->ncolors);
  //  tout.x=tout.y=0; tout.w=640; tout.h=480;
  //  SDL_BlitSurface(svgecran, NULL, ecran, &tout);
  //  SDL_Flip(ecran);

  //  SDL_FreeSurface(svgecran);
  if (fond) SDL_FreeSurface(imgfond);
  if (text_blob) free(text_blob);
  SDL_FreeSurface(police);
  SDL_FreeSurface(imgblob);
  for (i=0; i<nlignes; i++) {
    SDL_FreeSurface(imgtexte[i]);
    SDL_FreeSurface(lignefinale[i]);
  }
  return;
}
