/* Inclusion de librerias graficas */
#include "./X11/Xlib.h"
#include "./X11/keysymdef.h"
#include "./X11/keysym.h"
#include "./X11/Xutil.h"
#include "./X11/Xatom.h"
 
/* Inclusion de librerias para procesos UNIX */
#include <pthread.h>
#include <signal.h>
#include <assert.h>
#include <unistd.h>
 
 
/* otros includes */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
/* Definicion de limites */
#define LIM_INFERIOR 300  // Esquina inferior grafica del tablero
#define LIM_SUPERIOR 0    // Esquina superior grafica del tablero
#define VENT_IZQ 100   // Posiciones iniciales de las ventanas
#define VENT_DER 500
#define VENT_SUP 0
#define VENT_INF 310
#define TAM_BLOQUE 20 // Dimension en pixels de un bloque
#define X_INICIAL 5   // Posicion X inicial de las fichas
#define Y_INICIAL 0   // Posicion Y inicial de las fichas
#define TOTAL_X 10    // Numero de columnas del tetris
#define TOTAL_Y 16    // Numero de filas del tetris
 
 
//Cadenas para opciones
#define X_CADENA 250         // Posicion de las cadenas de opciones en pantalla
#define INICIAR "a - Iniciar Partida:"   
#define DEC_DIFICULTAD "b - Disminuir Dificultad"
#define INC_DIFICULTAD "c - Incrementar Dificultad"
#define PUNTOS "Puntos:"
#define FIN_PARTIDA "Fin de partida!!!"
 
 
//GLOBALES
 
/* Tipo que define la posicion de un bloque dentro del tablero del tetris,
 * cada bloque lleva las coordenas x e y */
 
typedef struct strBloque
{
   int x; //Posicion tablero
   int y;
} Bloque;
 
/* La estructura Ficha, es una forma con cuatro bloques */ 
typedef struct strFicha
{
   int tipo;
   Bloque Bl[4];  //Cada ficha son 4 bloques
} Ficha;
 
 
/* Prototipos de funciones propias */
void AlmacenaFicha(Ficha * l);
void DibujaBloque(int x, int y);
void DibujaTablero();
void CompruebaLineas();
int Grafica(int z);
int MovPermitido(Bloque * l,int donde);
int MovFichaPermitido(Ficha * l, int donde);
void FichaAbajo(Ficha * l);
void FichaIzquierda(Ficha * l);
void FichaDerecha(Ficha * l);
void BorraFicha(Ficha * l);
void DibujaFicha(Ficha * l);
int MueveFicha(Ficha * l, int donde);
void GeneraFicha(Ficha * l);
int FinPartida();
void * lanzafichas(Ficha * l);
void Rotar(Ficha * l);
void Escribe(int x, int y, char * cad);
void CalculaPuntos(int n_lineas);
void IniciaPartida();
 
 
// Definiciones globales
Display *dpy;   // Display X
Window w;       // Ventana general
GC gc, gc_borrar, gc_fichas, gc_letras;                // Contextos graficos
enum Movimientos { abajo,izquierda,derecha,rotacion};  // Varias constantes de movimiento
char Tablero[TOTAL_X][TOTAL_Y];                        // Tablero de tetris
int dificultad=800000;      // 0.8 segundos por movimiento hacia abajo
int Puntos;                 // Numero de puntos del usuario
int partida_jugando=0;      // Se está jugando una partida?
Ficha l;                    // Ficha que cae
pthread_mutex_t tab;   // Semaforo para memoria compartida (solo un proceso a la vez puede acceder al tablero)
 
 
// Funcion que calcula los puntos obtenidos por una o varias lineas
void CalculaPuntos(int n_lineas)
{
    char cadena[20];
    
    switch(n_lineas)
    {
  case 1:
    Puntos+=10;
    Escribe(X_CADENA, 250, "Simple: 10 puntos!!");
    break;
  case 2:
    Puntos+=30;
    Escribe(X_CADENA, 250, "Doble: 30 puntos!!");
    break;
  case 3:
    Puntos+=70;
    Escribe(X_CADENA, 250, "Triple: 70 puntos!!");
    break;
  case 4:
    Puntos+=150;
    Escribe(X_CADENA, 250, "Tetris: 150 puntos!!");
    break;
    }
    printf("\a\n"); //Beep!
    sprintf(cadena,"Puntos:%d",Puntos);
    Escribe(X_CADENA,100, cadena);
}
 
 
// Funcion que escribe una cadena de caracteres en una posición de pantalla
void Escribe(int x, int y, char * cad)
{
    XFillRectangle(dpy,w,gc_borrar,x-5,y-10,200,20);
    XDrawString(dpy,w,gc_letras,x,y,cad,strlen(cad));
}
 
// Funcion que dibuja todos los bloques que hay en pantalla
void DibujaTablero()
{
   int x,y;
 
   XFillRectangle(dpy,w,gc_borrar,5,LIM_SUPERIOR+5,200,LIM_INFERIOR);
   for(y=0;y<TOTAL_Y-1;y++)     //Menos 1 por la barrera del final
      for(x=0;x<TOTAL_X;x++)
      if(Tablero[x][y]=='X')
                DibujaBloque(x,y);
   
   XFlush(dpy);
   
}
 
 
// Funcion que comprueba si hay lineas en el tablero de tetris
void CompruebaLineas()
{
   int con_lineas=0; //Contador de lineas
 
   pthread_mutex_lock(&tab);  // Acceso a memoria compartida
 
   /*[COLOR=red] Esta funcion se tiene que jecutar cuando la ficha a terminado de caer, hay que usar la funcion con_lineas (ya que se debe codificar la deteccion de lineas usando ese contador para eliminarlas del tablero)...pero no se me ocurre como hacerlo...ayudarme por favor....[/COLOR]
    */
 
 
   if(con_lineas>0)
   {         
       DibujaTablero();
       CalculaPuntos(con_lineas);
   }
   pthread_mutex_unlock(&tab);  // Liberamos acceso a memoria compartida
}
 
 
/* Funcion que retorna la posicion grafica de un bloque */
int Grafica(int z)  
{
    return z*TAM_BLOQUE+5;
}