#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include "mapa.h"
#include "video.h"
#include "BFont.h"
#include "sdlfunc.h"


#define TICK_INTERVAL 5
#define NMAPA 1 //se e um novo mapa
#define AMAPA 2 //se vai carregar um mapa
#define SESQ 1 //scroll do mapa pra esquerda
#define SDIRE 2 //"" direira
#define SSOBE 3 //"" sobe
#define SDESCE 4//"" desce
//(pq diabos eu nao usei enum{}

//----- variaveis -----
//botoes
SDL_Surface *SrcTile;
SDL_Surface *BtnSobe;
SDL_Surface *BtnDesce;
SDL_Surface *BtnSobe1;
SDL_Surface *BtnDesce1;
SDL_Surface *BtnEsq;
SDL_Surface *BtnDire;
//Rects
SDL_Rect SrcRect;
SDL_Rect ScreenRect;
//Rects dos Botoes
SDL_Rect RBtnDesce;
SDL_Rect RBtnSobe;
SDL_Rect RBtnSobe1;
SDL_Rect RBtnDesce1;
SDL_Rect RBtnEsq;
SDL_Rect RBtnDire;
SDL_Rect MouseRect;

BFont_Info *Font1 = NULL;
//outras
static Uint32 next_time;
struct TTileMap NovoMapa; //struct base onde vai ficar o mapa
int Opcao; //para saber c um novo mapa ou se vai ser editado
int done = 0;//usado no while do loop principal
char tecla; //"" pra obter a tecla que usuario clicou [N/A]
char *path; //caminh do arquivo salvar/carregar
char *tilepath; //caminho do tiles para carregar
char *temp; //sem uso
int TileW; //auxilio quando for criar um novo mapa
int TileH;//""
int NumTiles;//""
int Dpth;//ainda sem uso
int Colunas; //Auxili quando for criar
int Linhas; //""
int TileSelec = 1;//tile selecionaod
int TileDiv; //pra calcular o tanto de tiles a desenhar (a esquerda onde escolhe qual tile vai seenhar no mapa
int **Src_Tile; //surface onde ficam os tiles
//---- funcoes ----

//funcao para um bom loop principal
Uint32 time_left(void)
{
   Uint32 now;
   
   now = SDL_GetTicks();
   if (next_time <= now)
     return 0;
   else
     return next_time - now;
}

//funcao le as opcaoes do ususario
void Inicio(void)
{
   
   printf("Se voce desejar criar um novo mapa digite [N]\n");
   printf("Se voce deseja abrir um mapa existente para edicao digire [A]\n");
   scanf("%c",&tecla);
   getchar();
   if ((tecla == 'N') || (tecla == 'n'))
     {
	printf("Qual o nome do arquivo que deseja criar:\n");
       	scanf("%s",&path);
	//printf("%s",&path);
	
	printf("Digite o arquivo que comtem os tiles:\n");
	scanf("%s",&tilepath);
	//	printf("%s",&tilepath);
	printf("Qual a largura de cada tile (Width) :\n");
	scanf("%d",&TileW);
	
	printf("Qual a altura de cada tile (Height) :\n");
	scanf("%d",&TileH);
	
	printf("Quantos tiles tem o mapa ao total.\n");
	printf("se voce nao sabe esta informacao abra seu arquivo de tiles\n");
	printf("pegue a Largura do seu  mapa e divida pela altura de cada tile\n");
	printf("faca a mesma coisa com a altura depois multiplique os resultados\n");
	printf(": ");
	scanf("%d",&NumTiles);
	
	printf("Quantas linhas voce desaja que o mapa tenha? :\n");
	scanf("%d",&Linhas);
	
	printf("Quantas colunas voce deseja que o mapa tenha? :\n");
	scanf("%d",&Colunas);
	
	Opcao = NMAPA;
     }
   else if ((tecla == 'A') || (tecla == 'a'))
     {
	printf("digite o arquivo que comtem seu mapa:\n");
	scanf("%s",&path);
	
	printf("Digite o arquivo que comtem os tiles:\n");
	scanf("%s",&tilepath);
	Opcao = AMAPA;
     }
   else
     {
	printf (" ESCOLHA UMA OPCAO VALIDA [N] OU [A]\n");
	exit(0);
     }
}

//desenha o quadro da esquerda (Tiles)
void DesenhaSrcTile(void)
{
   SDL_Rect DstRect;
   int Count;
   int x = 0;
   int y = 0;
   int w,h;
   
   if (Opcao == NMAPA)
     {
	NovoMapa.TileW = TileW;
	NovoMapa.TileH = TileH;
	NovoMapa.TileX = Colunas;
	NovoMapa.TileY = Linhas;
     }
   
   TileDiv = (NovoMapa.TileW <= 16) ? 10 : 3; //tres anos programando em C e ate hj eu nao sei usar o operador ?
   w = NovoMapa.TileW * TileDiv;
   h = NovoMapa.TileH * NovoMapa.NumTiles / TileDiv;
   
   SrcTile = SDL_CreateRGBSurface(SDL_SWSURFACE,w,h,16,
				  screen->format->Rmask,screen->format->Gmask,screen->format->Bmask,screen->format->Amask);
   
   if (SrcTile == NULL)
     {
	printf("Nao foi possivel alocar espaco na memoria\n");
	exit(0);
     }
  
   //uma mapa dos tiles a direita pra  fazer o calculo de qual tile o usuario selecionou
  Src_Tile = calloc(sizeof (int *),(h / NovoMapa.TileH)+1);
   
   for (Count=0;Count<(h / NovoMapa.TileH);Count++)
     Src_Tile[Count] = calloc(sizeof (int),TileDiv+1);
 // printf("Desenhando SrcTile\n"); 
   //desenha os tiles a direita
   for(Count=0;Count<NovoMapa.NumTiles;Count++)
     {
	if (x*NovoMapa.TileW >= SrcTile->w)
	  {
	     y++;
	     x = 0;
	  }
	DstRect.x = x * NovoMapa.TileW;
	DstRect.y = y * NovoMapa.TileH;
	DstRect.w = x * NovoMapa.TileW + NovoMapa.TileW;
	DstRect.h = y * NovoMapa.TileH + NovoMapa.TileH;
	x++;
	if (y < (h / NovoMapa.TileH)) //solucao de um dos misterios Segmentation Fault
	  Src_Tile[y][x] = Count;
	  
	SDL_BlitSurface(NovoMapa.TileSrc[Count],NULL,SrcTile,&DstRect);
     }
   //configura rect da onde o tile sera desenhado (a direita)
   ScreenRect.x = ((screen->w) - (NovoMapa.TileW * TileDiv)) - 16;
   ScreenRect.y = 0;
   ScreenRect.w = screen->w;
   ScreenRect.h = screen->h;
   
   SrcRect.x = 0;
   SrcRect.y = 1;
   SrcRect.h = screen->h;
   SrcRect.w = SrcTile->w;
     
   SDL_UpdateRect(SrcTile,0,0,0,0);
}

//carrega os botoes e etc...
void CarregaImagens(void)
{
    Font1 = BFont_LoadFont("font03.png");
   if (Font1 == NULL)
    {
	 printf ("Erro nao foi possivel carregar fontes\n");
	SDL_Quit();
   }
   //as imagens estao todas repetidas nao sou bom com arte grafica
   BtnDesce = IMG_Load("btnsobe.png");
   if (BtnDesce == NULL)
     {
	printf("Nao foi Possivel carreggar: btndece.png\n");
	SDL_Quit();
     }
   
   BtnDesce1 = IMG_Load("btnsobe.png");
   if (BtnDesce1 == NULL)
     {
	printf("Nao foi possivel carregar: btndesce.png\n");
	SDL_Quit();
     }
   
   BtnSobe = IMG_Load("btnsobe.png");
   if (BtnSobe == NULL)
     {
	printf("Nao foi Possivel carregar: btnsobe.png\n");
	SDL_Quit();
     }
   
   BtnSobe1 = IMG_Load("btnsobe.png");
   if (BtnSobe1 == NULL)
     {
	printf("Nao foi Possivel carregar: btnsobe.png\n");
	SDL_Quit();
     }
   
   BtnEsq = IMG_Load("btnsobe.png");
   
   if (BtnEsq == NULL)
     {
	printf("Nao foi possivel carregar: btnesq.png\n");
	SDL_Quit();
     }
   
   BtnDire = IMG_Load("btnsobe.png");
   if (BtnDire  == NULL)
     {
	printf("Nao foi possivel carregar: btnsobre.png\n");
	SDL_Quit();
     }
   
   BFont_SetCurrentFont(Font1);
   
   printf("Criando Mapa\n");
   
}

//Rola o SrcTile para Cima
void SrcTileScrollUp()
{
   if (!(SrcRect.y -NovoMapa.TileH < 0))
     {
	SrcRect.y -= NovoMapa.TileH;
     }
}

//rola o SrcTile para baixo
void SrcTileScrollDown()
{
   if (!(SrcRect.y +screen->h +NovoMapa.TileH >= SrcTile->h))
     {
   SrcRect.y += NovoMapa.TileH;
     }   
}

//Responsavel pelo Scroll do Mapa
void SrcMapaScroll(short int Direcao)
{
  if (Direcao == SESQ) //se e para ir q esquerda
    {
      if (!(NovoMapa.SrcRect.x - NovoMapa.TileW <= 1))
	{
	  NovoMapa.SrcRect.x -= NovoMapa.TileW;
	  return; //so coloquei esse return pra sai da funcao velocidade e levado muito a serio
	}         //quando se esta codando em um 486 :-)
    }

  if (Direcao == SDIRE) //direira
    {
      if (!((NovoMapa.SrcRect.x + NovoMapa.SrcRect.w) >= NovoMapa.Tela->w))
	{
	  NovoMapa.SrcRect.x += NovoMapa.TileW;
	  return;
	}
    }
  if (Direcao == SSOBE) //para cima
    {
      if (!((NovoMapa.SrcRect.y - NovoMapa.TileH) < 0))
	{
	  NovoMapa.SrcRect.y -= NovoMapa.TileH;
	  return;
	}
    }
  if (Direcao == SDESCE) //para baixo
    {
      if (!((NovoMapa.SrcRect.y + NovoMapa.SrcRect.h) >= NovoMapa.Tela->h))
	{
	  NovoMapa.SrcRect.y += NovoMapa.TileH;
	  return;
	}
    }
}        

//detecta colisao entre dois retangulos (ainda sem Uso mais cedo ou tarde vou pescisar)
int RectColisao(SDL_Rect RctA, SDL_Rect RctB)
  {
     if (RctA.h < RctB.y) return (0);
     if (RctA.y > RctB.h) return (0);
     if (RctA.w < RctB.x) return (0);
     if (RctA.x > RctB.w) return (0);
     return (1);
  }

//verefica se uma cordena X Y esta dentro de um Rect
//util para usar com o mouse
int XYRectColisao(int x,int y,SDL_Rect Rct)
{
   //e feia mais funciona
  if (x > (Rct.x+Rct.w))
    return 0;
  
  if (x < Rct.x) 
    return 0;
   
   if (y > (Rct.y+Rct.h))
     return 0;
   
   if (y < Rct.y)
     return 0;
   
   return 1;
}

//essa funcao verifica e se  ususario colocou algum tile no mapa
//caso sim ele desenha esse tile no mapa...
void ChecaPlotagem(void)
{
   float a,b;
   int c;
   SDL_Rect Rct;
   if (XYRectColisao(evento.motion.x,evento.motion.y,NovoMapa.DstRect) == 1) //clicou dentro da area do mapa?
     {
	a = ((evento.motion.x + NovoMapa.SrcRect.x) / NovoMapa.TileW);
	b = ((evento.motion.y + NovoMapa.SrcRect.y) / NovoMapa.TileH);
	c = (float)a*b;
	
	NovoMapa.MapaSrc[(int)b][(int)a] = TileSelec;
	//printf("A:%d B:%d T:%d\n",(int)a,(int)b,TileSelec);
	Rct.x = a * NovoMapa.TileW;
	Rct.y = b * NovoMapa.TileH;
	Rct.w = a * NovoMapa.TileW + NovoMapa.TileW;
	Rct.h = b * NovoMapa.TileH + NovoMapa.TileH;
	SDL_BlitSurface(NovoMapa.TileSrc[TileSelec],NULL,NovoMapa.Tela,&Rct);
	SDL_UpdateRect(NovoMapa.Tela,Rct.x,Rct.y,Rct.w,Rct.h);
     }
}

//checa o tile que o usuario selecionou (SrcTile)
void ChecaSrcTileClic(void)
{
   int a,b;
   a = ((evento.motion.x - ScreenRect.x) / NovoMapa.TileW);
   b = ((evento.motion.y + SrcRect.y) / NovoMapa.TileH);
   //printf("X:%d Y:%d\n",a,b);
   TileSelec = Src_Tile[b][a+1];
      
}

//prepara o mapa para ser usado
//caso seja um novo mapa seta todo mapa para o Tile[0]
//que sempre vai ser ou um preto ou grama etc...
void PreparaMapa(void)
{	
   int a,b;
   int w = NovoMapa.TileW * NovoMapa.TileX;
   int h = NovoMapa.TileH * NovoMapa.TileY;
   SDL_Rect Rct;
   NovoMapa.Tela = SDL_CreateRGBSurface(SDL_SWSURFACE,w,h,16,screen->format->Rmask,
					screen->format->Gmask,screen->format->Bmask,screen->format->Amask);
   /*if (NovoMapa.Tela == NULL)
     {
	printf("ERRO: nao foi possivel criar imagens.\n");
	exit(0);
     }*/
   
   for (a=0;a<NovoMapa.TileY;a++)
     for (b=0;b<NovoMapa.TileX;b++)
       {
	  NovoMapa.MapaSrc[a][b] = 0;
	  Rct.x = b * NovoMapa.TileW;
	  Rct.y = a * NovoMapa.TileH;
	  Rct.w = b * NovoMapa.TileW + NovoMapa.TileW;
	  Rct.h = a * NovoMapa.TileH + NovoMapa.TileH;
	  
	  SDL_BlitSurface(NovoMapa.TileSrc[0],NULL,NovoMapa.Tela,&Rct);
       }
   
   SDL_Flip(NovoMapa.Tela);
}

	  
//configura rects dos botoes e etc...
void SetaRect(void)
{
   ScreenRect.x = (screen->w - NovoMapa.TileW * 3)-16;
   ScreenRect.y = 0;
   ScreenRect.w = screen->w - 16;
   ScreenRect.h = screen->h - 16;
   
   RBtnDesce.x = screen->w - 16;
   RBtnDesce.y = screen->h - 16;
   RBtnDesce.w = screen->w;
   RBtnDesce.h = screen->h;
   
   RBtnSobe.x = screen->w - 16;
   RBtnSobe.y = 0;
   RBtnSobe.w = 16;
   RBtnSobe.h = 16;
   
   NovoMapa.DstRect.x = 2;
   NovoMapa.DstRect.y = 10;
   NovoMapa.DstRect.w = ScreenRect.x - 20;
   NovoMapa.DstRect.h = screen->h - 32;
   
   RBtnSobe1.x = NovoMapa.DstRect.w +1;
   RBtnSobe1.y = NovoMapa.DstRect.y;
   RBtnSobe1.w = 16;
   RBtnSobe1.h = 16;
   
   RBtnDesce1.x = NovoMapa.DstRect.w +1;
   RBtnDesce1.y = NovoMapa.DstRect.h;
   RBtnDesce1.w = 16;
   RBtnDesce1.h = 16;
   
   RBtnEsq.x = NovoMapa.DstRect.x;
   RBtnEsq.y = NovoMapa.DstRect.h +16;
   RBtnEsq.w = 16;
   RBtnEsq.h = 16;
   
   RBtnDire.x = NovoMapa.DstRect.w -16;
   RBtnDire.y = NovoMapa.DstRect.h +16;
   RBtnDire.w = 16;
   RBtnDire.h = 16;
   
   NovoMapa.SrcRect.x = 0;
   NovoMapa.SrcRect.y = 0;
   NovoMapa.SrcRect.w = (NovoMapa.DstRect.w - NovoMapa.SrcRect.x);
   NovoMapa.SrcRect.h = (NovoMapa.DstRect.h - NovoMapa.SrcRect.y);
}

//desenha tudo que tem q ser desenhado
void DesenhaTudo()
{  
   //desenha os botoes
  Slock(screen);
  SDL_BlitSurface(BtnSobe,NULL,screen,&RBtnSobe); //btn Scroll Up (Tiles)
  SDL_BlitSurface(BtnDesce,NULL,screen,&RBtnDesce); // Scroll Down (Tiles)
  SDL_BlitSurface(BtnSobe1,NULL,screen,&RBtnSobe1); //Btn Scroll Up (Mapa)
  SDL_BlitSurface(BtnDesce1,NULL,screen,&RBtnDesce1); //Btn Scroll Down (Mapa)
  SDL_BlitSurface(BtnEsq,NULL,screen,&RBtnEsq); //Btn Scroll esquerda (mapa)
  SDL_BlitSurface(BtnDire,NULL,screen,&RBtnDire); //Btn Scroll Direita (Mapa)

   //Desenha SrcTile
   SDL_BlitSurface(SrcTile,&SrcRect,screen,&ScreenRect);
   
   //desenha caixa onde fica a imagem do mapa (comentei tinha um errinho chato me pentenhando)
   /*h_line(screen,NovoMapa.DstRect.x -1,NovoMapa.DstRect.w +1,NovoMapa.DstRect.y-1,0xffff); //linha superior
   h_line(screen,NovoMapa.DstRect.x -1,NovoMapa.DstRect.w +1,NovoMapa.DstRect.h+1,0xffff); //linha inferior
   v_line(screen,NovoMapa.DstRect.y -1,NovoMapa.DstRect.h +1,NovoMapa.DstRect.x -1,0xffff); //linha direita
   v_line(screen,NovoMapa.DstRect.y -1,NovoMapa.DstRect.h +1,NovoMapa.DstRect.w +1,0xffff)/ //linha esquerda
   */
   
   //desenha Mapa
   SDL_BlitSurface(NovoMapa.Tela,&NovoMapa.SrcRect,screen,&NovoMapa.DstRect);
   Sulock(screen);
   SDL_Flip(screen);
}

int main(int argc,char *argv[])
{
   int a,b;
   //chama funcao que le as opcoes que o usuario deseja;
   Inicio();
   
   //inicia SDL
   if (SDL_Init(SDL_INIT_VIDEO) < 0)
     {
	printf("Nao foi possivel carregar o modo grafico.\n");
	exit(0);
     }
   //nem prescisa falar ne!
   screen =  SDL_SetVideoMode(640,480,16,SDL_HWSURFACE|SDL_FULLSCREEN);
   if (screen == NULL)
     {
	printf ("erro ao inicar o modo grafico %s\n",SDL_GetError());
	exit(0);
     }
   //carregando as imagens
   CarregaImagens();
   
   //se for criar um novo mapa entao
   if (Opcao == NMAPA)
	NovoMapa = CriaTileMap(&tilepath,TileH,TileW,NumTiles,Linhas,Colunas);
   else
     {
       //caso contrario iremos carregar um mapa
	//printf("Careegando seu mapa\n");
	NovoMapa = CarregaTileMap(&path,&tilepath);
     }
   //seta e desenha tiles a esuqerda
    DesenhaSrcTile();
   
   //configura os os Rects
    SetaRect();
   
   //se for um Novo mapa
    if (Opcao == NMAPA) 
     PreparaMapa();
   
   next_time = SDL_GetTicks() + TICK_INTERVAL;
   
   //inicia loop principal
   while (done == 0)
     {
	//antes de mais nada limpa a tela ineficiente porem temporaria
//	SDL_FillRect(screen,&screen->clip_rect,0x0000);
	
	SDL_PollEvent(&evento);
	
	//se apertou esc sai do loop principal
	if (evento.key.keysym.sym == SDLK_ESCAPE)
	    done = 1;
	
	//verifica se o evento tem a ver com o mouse
	if ((evento.type == SDL_MOUSEBUTTONDOWN) && (evento.button.button == SDL_BUTTON_LEFT))
	  {
	     MouseRect.x = evento.motion.x;
	     MouseRect.y = evento.motion.y;
 	     
	      if (XYRectColisao(evento.motion.x,evento.motion.y,RBtnDesce) == 1) //se o usurio clicou Para SrcTile Decer
	       SrcTileScrollDown();
	   
	     if (XYRectColisao(evento.motion.x,evento.motion.y,RBtnSobe) == 1) //se o usuario para SrcTile Subir
		 SrcTileScrollUp();
	     
	     if (XYRectColisao(evento.motion.x,evento.motion.y,RBtnSobe1) == 1) //Se o usuario Clicou para o mapa subir
	       SrcMapaScroll(SSOBE);
	     
	     if (XYRectColisao(evento.motion.x,evento.motion.y,RBtnDesce1) == 1) //se o usuario clicou para o mapa descer
	       SrcMapaScroll(SDESCE);
	     
	     if (XYRectColisao(evento.motion.x,evento.motion.y,RBtnEsq) == 1) //se o o usuario clicou para o mapa ir a esquerda
	       SrcMapaScroll(SESQ);
	     
	     if (XYRectColisao(evento.motion.x,evento.motion.y,RBtnDire) == 1) //se o usuario clicou para o mapa ir a direita
	       SrcMapaScroll(SDIRE);
	 
	     if (XYRectColisao(evento.motion.x,evento.motion.y,ScreenRect) == 1) //se clicou dentro do SrcTile
	       ChecaSrcTileClic();
	       ChecaPlotagem();
	     
	  }
	
	//desenha tudo
	DesenhaTudo();
       
	SDL_Delay(time_left());
	next_time += TICK_INTERVAL;
     }
   printf("Salvando Seu Mapa\n");
   SalvaTileMap(NovoMapa,&path);
   SDL_Quit();
   return 0;
}
