/*
 	File:        Utils.cpp
  Description: Various util functions
  Program:     BlockOut
  Author:      Jean-Luc PONS

  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.
*/

#include "Types.h"
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <CImage.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>

static char bl2Home[512];
static char usrHome[512];

//-----------------------------------------------------------------------------
// Name: v()
// Desc: Construct a VERTEX.
//-----------------------------------------------------------------------------
VERTEX v(float x,float y,float z) {

  static VERTEX ret;
  ret.x = x;
  ret.y = y;
  ret.z = z;
  return ret;

}

//-----------------------------------------------------------------------------
// Nomalize a 3D vector
//-----------------------------------------------------------------------------
void Normalize(VERTEX *v) {

	float n = sqrtf( v->x * v->x + v->y * v->y + v->z * v->z );
	v->x = v->x / n;
	v->y = v->y / n;
	v->z = v->z / n;

}

//-----------------------------------------------------------------------------
// Name: fround()
// Desc: Round to the nearest integer
//-----------------------------------------------------------------------------
int fround(float x) {

  int i;
  if( x<0.0f ) {
    i = (int)( (-x) + 0.5f );
    i = -i;
  } else {
    i = (int)( x + 0.5f );
  }

  return i;

}

//-----------------------------------------------------------------------------
// Name: FormatTime(float seconds)
// Desc: Format time as XXmin YYsec
//-----------------------------------------------------------------------------
char *FormatTime(float seconds) {

  static char ret[32];
  int min = (int)seconds / 60;
  int sec = (int)seconds % 60;
  sprintf(ret,"%dmin %02dsec",min,sec);

  return ret;

}

//-----------------------------------------------------------------------------
// Name: FormatDate(int time)
// Desc: Format date as DD-MM-YYYY HH:MM:SS
//-----------------------------------------------------------------------------
char *FormatDate(int time) {

  static char ret[32];
  if( time>0 ) {
#ifdef LOCALTIME32
    struct tm *ts = _localtime32((__time32_t *)&time);
#else
    struct tm *ts = localtime((time_t *)&time);
#endif
    sprintf(ret,"%02d-%02d-%04d %02d:%02d:%02d",ts->tm_mday,ts->tm_mon+1,ts->tm_year+1900,
                                                ts->tm_hour,ts->tm_min,ts->tm_sec);
  } else {
    strcpy(ret,"");
  }

  return ret;

}

//-----------------------------------------------------------------------------
// Name: FormatDate(int time)
// Desc: Format date as DD-MM-YYYY
//-----------------------------------------------------------------------------
char *FormatDateShort(int time) {

  static char ret[32];
  if( time>0 ) {
#ifdef LOCALTIME32
    struct tm *ts = _localtime32((__time32_t *)&time);
#else
    struct tm *ts = localtime((time_t *)&time);
#endif
    sprintf(ret,"%02d-%02d-%04d",ts->tm_mday,ts->tm_mon+1,ts->tm_year+1900);
  } else {
    strcpy(ret,"..........");
  }

  return ret;

}

//-----------------------------------------------------------------------------
// Name: DirExists()
// Desc: Return TRUE if the specified directory exists
//-----------------------------------------------------------------------------

BOOL DirExists(char *dirname) {

  DIR    *dp;

  if((dp  = opendir(dirname)) == NULL) {
    return FALSE;
  }
  closedir(dp);
	
  return TRUE;

}

//-----------------------------------------------------------------------------
// Name: CheckEnv()
// Desc: Check environemt
//-----------------------------------------------------------------------------
BOOL CheckEnv() {

#ifdef __AROS__
	char *homePath = "/PROGDIR";
#else
	char *homePath = getenv("HOME");
#endif
	if( homePath==NULL ) {
	  printf("HOME environement variable if not defined !\n");
	  printf("Please set the HOME variable to your home directory (ex: HOME=/users/jeanluc)\n");
		return FALSE;
	}

#ifdef __AROS__        
	char *blockoutHome = "/PROGDIR";
#else
	char *blockoutHome = getenv("BL2_HOME");
#endif
	if( blockoutHome==NULL ) {
	  printf("BL2_HOME environement variable if not defined !\n");
	  printf("Please set the BL2_HOME to the BlockOut II installation directory (ex: BL2_HOME=/usr/local/bl2).\n");
		return FALSE;
	}
	strcpy( bl2Home , blockoutHome );
		
	char bl2Dir[512];
	sprintf(bl2Dir,"%s/.bl2",homePath);
	if( !DirExists(bl2Dir) ) {
	  // Create it
	  if( mkdir(bl2Dir,S_IRWXU) < 0 ) {
	    printf("Directory %s cannot be created or accessed !\n",bl2Dir);
		  return FALSE;
		}
		// Set rigth
     chmod(bl2Dir,S_IRWXU);  
	}
	strcpy( usrHome , bl2Dir );
	
	return TRUE;

}

//-----------------------------------------------------------------------------
// Name: LID()
// Desc: Locate file in the installation directory
//-----------------------------------------------------------------------------
char *LID(char *fileName) {

  static char ret[512];
	sprintf(ret,"%s/%s",bl2Home,fileName);
	return ret;

}

//-----------------------------------------------------------------------------
// Name: LHD()
// Desc: Locate file in the home directory
//-----------------------------------------------------------------------------
char *LHD(char *fileName) {

  static char ret[512];
	sprintf(ret,"%s/%s",usrHome,fileName);
	return ret;

}

//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Name: CreateTexture()
// Desc: Create a texture (no alpha)
//-----------------------------------------------------------------------------
int CreateTexture(int width,int height,char *imgName,GLuint *hmap) {

  *hmap = 0;
  CImage img;

  if( !img.LoadImage(LID(imgName)) ) {

    printf( "CreateTexture(): %s\nFile: %s\n",img.GetErrorMessage(),imgName );
    return GL_FAIL;

  }

  if( img.Width() != width || img.Height() != height ) {

    printf( "CreateTexture(): Wrong image dimension (%dx%d required)\nFile: %s\n",width,height,LID(imgName) );
    return GL_FAIL;

  }

	BYTE *buff32 = (BYTE *)malloc(width*height*3);
	BYTE *data = img.GetData();
  for(int j=0;j<height;j++)
		for(int i=0;i<width;i++ ) {
			buff32[i*3+0 + j*width*3] = data[i*3+2 + j*width*3];
			buff32[i*3+1 + j*width*3] = data[i*3+1 + j*width*3];
			buff32[i*3+2 + j*width*3] = data[i*3+0 + j*width*3];
		}

  glGenTextures(1,hmap);
  glBindTexture(GL_TEXTURE_2D,*hmap);

  glTexImage2D (
	  GL_TEXTURE_2D, 	    // Type
    0, 	                // No Mipmap
    3,                  // Format RGB
    width, 	            // Width
    height,             // Height
    0, 	                // Border
    GL_RGB, 	          // Format RGB
    GL_UNSIGNED_BYTE, 	// 8 Bit/color
    buff32              // Data
  ); 	

  img.Release();
	free(buff32);

	if( glGetError() != GL_NO_ERROR ) {
    printf( "CreateTexture(): OpenGL error (code=%d)\n",glGetError() );
  	return GL_FAIL;
	}

  return GL_OK;
}

//-----------------------------------------------------------------------------
// Reset memory to 0
//-----------------------------------------------------------------------------
void ZeroMemory(void *buff,int size) {
  memset(buff,0,size);
}

//-----------------------------------------------------------------------------
// Name: GetChar()
// Desc: Return char according to pressed key
//-----------------------------------------------------------------------------
extern char GetChar(BYTE *keys) {

  char retChar = 0;

  // Check letters
  for(BYTE i='A';i<='Z';i++) 
    if( keys[i] ) retChar = i;

	for(BYTE i='a';i<='z';i++) 
    if( keys[i] ) retChar = i;

  // Check numbers
  for(BYTE i=0;i<=9;i++)
    if( keys[i+'0'] ) retChar = (char)i+'0';

  // Space
  if( keys[SDLK_SPACE] ) {
    retChar = ' ';
  }

  // Dot
  if( keys['.'] ) retChar = '.';

  // Comma
  if( keys[','] ) retChar = ',';
  
  // Minus
  if( keys['-'] ) retChar = '-';

  // Plus
  if( keys['+'] ) retChar = '+';

  // Divide
  if( keys['/'] ) retChar = '/';

  // ':'
	if( keys[':'] ) retChar = ':';

  // '@'
	if( keys['@'] ) retChar = '@';

  // '''
	if( keys['\''] ) retChar = '\'';

  // '!'
	if( keys['!'] ) retChar = '!';

  // '$'
	if( keys['$'] ) retChar = '$';

  // '%'
	if( keys['%'] ) retChar = '%';

  // '&'
	if( keys['&'] ) retChar = '&';

  // '*'
	if( keys['*'] ) retChar = '*';

  // '('
	if( keys['('] ) retChar = '(';

  // ')'
	if( keys[')'] ) retChar = ')';

  // '_'
	if( keys['_'] ) retChar = '_';

  // '?'
	if( keys['?'] ) retChar = '?';

  // ';'
	if( keys[';'] ) retChar = ';';

  // Reset keys
  for(BYTE i='A';i<='Z';i++)
    keys[i]=0;

	for(BYTE i='a';i<='z';i++)
    keys[i]=0;

  for(BYTE i=0;i<=9;i++)
    keys[i+'0']=0;

  keys[SDLK_SPACE]=0;
  keys['.']=0;
  keys['/']=0;
  keys['-']=0;
  keys['+']=0;
	keys[':']=0;
	keys[',']=0;
  keys['.']=0;
  keys['@']=0;
  keys['\'']=0;
  keys['!']=0;
  keys['$']=0;
  keys['%']=0;
  keys['&']=0;
  keys['*']=0;
  keys['(']=0;
  keys[')']=0;
  keys['_']=0;
  keys['?']=0;
  keys[';']=0;

  return retChar;

}
