/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2006 Tim Angus

This file is part of Tremulous.

Tremulous 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.

Tremulous 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 Tremulous; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/

/**********************************************************************
  UI_ATOMS.C

  User interface building blocks and support functions.
**********************************************************************/
#include "ui_local.h"

qboolean    m_entersound;    // after a frame, so caching won't disrupt the sound

void QDECL Com_Error( int level, const char *error, ... ) {
  va_list    argptr;
  char    text[1024];

  va_start (argptr, error);
  vsprintf (text, error, argptr);
  va_end (argptr);

  trap_Error( va("%s", text) );
}

void QDECL Com_Printf( const char *msg, ... ) {
  va_list    argptr;
  char    text[1024];

  va_start (argptr, msg);
  vsprintf (text, msg, argptr);
  va_end (argptr);

  trap_Print( va("%s", text) );
}

qboolean newUI = qfalse;


/*
=================
UI_ClampCvar
=================
*/
float UI_ClampCvar( float min, float max, float value )
{
  if ( value < min ) return min;
  if ( value > max ) return max;
  return value;
}

/*
=================
UI_StartDemoLoop
=================
*/
void UI_StartDemoLoop( void ) {
  trap_Cmd_ExecuteText( EXEC_APPEND, "d1\n" );
}

char *UI_Argv( int arg ) {
  static char  buffer[MAX_STRING_CHARS];

  trap_Argv( arg, buffer, sizeof( buffer ) );

  return buffer;
}


char *UI_Cvar_VariableString( const char *var_name ) {
  static char  buffer[MAX_STRING_CHARS];

  trap_Cvar_VariableStringBuffer( var_name, buffer, sizeof( buffer ) );

  return buffer;
}



void UI_SetBestScores(postGameInfo_t *newInfo, qboolean postGame) {
  trap_Cvar_Set("ui_scoreAccuracy",     va("%i%%", newInfo->accuracy));
  trap_Cvar_Set("ui_scoreImpressives",  va("%i", newInfo->impressives));
  trap_Cvar_Set("ui_scoreExcellents",   va("%i", newInfo->excellents));
  trap_Cvar_Set("ui_scoreDefends",       va("%i", newInfo->defends));
  trap_Cvar_Set("ui_scoreAssists",       va("%i", newInfo->assists));
  trap_Cvar_Set("ui_scoreGauntlets",     va("%i", newInfo->gauntlets));
  trap_Cvar_Set("ui_scoreScore",         va("%i", newInfo->score));
  trap_Cvar_Set("ui_scorePerfect",       va("%i", newInfo->perfects));
  trap_Cvar_Set("ui_scoreTeam",          va("%i to %i", newInfo->redScore, newInfo->blueScore));
  trap_Cvar_Set("ui_scoreBase",          va("%i", newInfo->baseScore));
  trap_Cvar_Set("ui_scoreTimeBonus",    va("%i", newInfo->timeBonus));
  trap_Cvar_Set("ui_scoreSkillBonus",    va("%i", newInfo->skillBonus));
  trap_Cvar_Set("ui_scoreShutoutBonus",  va("%i", newInfo->shutoutBonus));
  trap_Cvar_Set("ui_scoreTime",          va("%02i:%02i", newInfo->time / 60, newInfo->time % 60));
  trap_Cvar_Set("ui_scoreCaptures",    va("%i", newInfo->captures));
  if (postGame) {
    trap_Cvar_Set("ui_scoreAccuracy2",     va("%i%%", newInfo->accuracy));
    trap_Cvar_Set("ui_scoreImpressives2",  va("%i", newInfo->impressives));
    trap_Cvar_Set("ui_scoreExcellents2",   va("%i", newInfo->excellents));
    trap_Cvar_Set("ui_scoreDefends2",       va("%i", newInfo->defends));
    trap_Cvar_Set("ui_scoreAssists2",       va("%i", newInfo->assists));
    trap_Cvar_Set("ui_scoreGauntlets2",     va("%i", newInfo->gauntlets));
    trap_Cvar_Set("ui_scoreScore2",         va("%i", newInfo->score));
    trap_Cvar_Set("ui_scorePerfect2",       va("%i", newInfo->perfects));
    trap_Cvar_Set("ui_scoreTeam2",          va("%i to %i", newInfo->redScore, newInfo->blueScore));
    trap_Cvar_Set("ui_scoreBase2",          va("%i", newInfo->baseScore));
    trap_Cvar_Set("ui_scoreTimeBonus2",    va("%i", newInfo->timeBonus));
    trap_Cvar_Set("ui_scoreSkillBonus2",    va("%i", newInfo->skillBonus));
    trap_Cvar_Set("ui_scoreShutoutBonus2",  va("%i", newInfo->shutoutBonus));
    trap_Cvar_Set("ui_scoreTime2",          va("%02i:%02i", newInfo->time / 60, newInfo->time % 60));
    trap_Cvar_Set("ui_scoreCaptures2",    va("%i", newInfo->captures));
  }
}

void UI_LoadBestScores(const char *map, int game) {
  char    fileName[MAX_QPATH];
  fileHandle_t f;
  postGameInfo_t newInfo;
  memset(&newInfo, 0, sizeof(postGameInfo_t));
  Com_sprintf(fileName, MAX_QPATH, "games/%s_%i.game", map, game);
  if (trap_FS_FOpenFile(fileName, &f, FS_READ) >= 0) {
    int size = 0;
    trap_FS_Read(&size, sizeof(int), f);
    if (size == sizeof(postGameInfo_t)) {
      trap_FS_Read(&newInfo, sizeof(postGameInfo_t), f);
    }
    trap_FS_FCloseFile(f);
  }
  UI_SetBestScores(&newInfo, qfalse);

  Com_sprintf(fileName, MAX_QPATH, "demos/%s_%d.dm_%d", map, game, (int)trap_Cvar_VariableValue("protocol"));
  uiInfo.demoAvailable = qfalse;
  if (trap_FS_FOpenFile(fileName, &f, FS_READ) >= 0) {
    uiInfo.demoAvailable = qtrue;
    trap_FS_FCloseFile(f);
  }
}

/*
===============
UI_ClearScores
===============
*/
void UI_ClearScores( void ) {
  char  gameList[4096];
  char *gameFile;
  int    i, len, count, size;
  fileHandle_t f;
  postGameInfo_t newInfo;

  count = trap_FS_GetFileList( "games", "game", gameList, sizeof(gameList) );

  size = sizeof(postGameInfo_t);
  memset(&newInfo, 0, size);

  if (count > 0) {
    gameFile = gameList;
    for ( i = 0; i < count; i++ ) {
      len = strlen(gameFile);
      if (trap_FS_FOpenFile(va("games/%s",gameFile), &f, FS_WRITE) >= 0) {
        trap_FS_Write(&size, sizeof(int), f);
        trap_FS_Write(&newInfo, size, f);
        trap_FS_FCloseFile(f);
      }
      gameFile += len + 1;
    }
  }

  UI_SetBestScores(&newInfo, qfalse);

}



static void  UI_Cache_f( void ) {
  Display_CacheAll();
}

/*
=======================
UI_CalcPostGameStats
=======================
*/
static void UI_CalcPostGameStats( void ) {
  char    map[MAX_QPATH];
  char    fileName[MAX_QPATH];
  char    info[MAX_INFO_STRING];
  fileHandle_t f;
  int size, game, time, adjustedTime;
  postGameInfo_t oldInfo;
  postGameInfo_t newInfo;
  qboolean newHigh = qfalse;

  trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
  Q_strncpyz( map, Info_ValueForKey( info, "mapname" ), sizeof(map) );
  game = atoi(Info_ValueForKey(info, "g_gametype"));

  // compose file name
  Com_sprintf(fileName, MAX_QPATH, "games/%s_%i.game", map, game);
  // see if we have one already
  memset(&oldInfo, 0, sizeof(postGameInfo_t));
  if (trap_FS_FOpenFile(fileName, &f, FS_READ) >= 0) {
  // if so load it
    size = 0;
    trap_FS_Read(&size, sizeof(int), f);
    if (size == sizeof(postGameInfo_t)) {
      trap_FS_Read(&oldInfo, sizeof(postGameInfo_t), f);
    }
    trap_FS_FCloseFile(f);
  }

  newInfo.accuracy = atoi(UI_Argv(3));
  newInfo.impressives = atoi(UI_Argv(4));
  newInfo.excellents = atoi(UI_Argv(5));
  newInfo.defends = atoi(UI_Argv(6));
  newInfo.assists = atoi(UI_Argv(7));
  newInfo.gauntlets = atoi(UI_Argv(8));
  newInfo.baseScore = atoi(UI_Argv(9));
  newInfo.perfects = atoi(UI_Argv(10));
  newInfo.redScore = atoi(UI_Argv(11));
  newInfo.blueScore = atoi(UI_Argv(12));
  time = atoi(UI_Argv(13));
  newInfo.captures = atoi(UI_Argv(14));

  newInfo.time = (time - trap_Cvar_VariableValue("ui_matchStartTime")) / 1000;
  adjustedTime = uiInfo.mapList[ui_currentMap.integer].timeToBeat[game];
  if (newInfo.time < adjustedTime) {
    newInfo.timeBonus = (adjustedTime - newInfo.time) * 10;
  } else {
    newInfo.timeBonus = 0;
  }

  if (newInfo.redScore > newInfo.blueScore && newInfo.blueScore <= 0) {
    newInfo.shutoutBonus = 100;
  } else {
    newInfo.shutoutBonus = 0;
  }

  newInfo.skillBonus = trap_Cvar_VariableValue("g_spSkill");
  if (newInfo.skillBonus <= 0) {
    newInfo.skillBonus = 1;
  }
  newInfo.score = newInfo.baseScore + newInfo.shutoutBonus + newInfo.timeBonus;
  newInfo.score *= newInfo.skillBonus;

  // see if the score is higher for this one
  newHigh = (newInfo.redScore > newInfo.blueScore && newInfo.score > oldInfo.score);

  if  (newHigh) {
    // if so write out the new one
    uiInfo.newHighScoreTime = uiInfo.uiDC.realTime + 20000;
    if (trap_FS_FOpenFile(fileName, &f, FS_WRITE) >= 0) {
      size = sizeof(postGameInfo_t);
      trap_FS_Write(&size, sizeof(int), f);
      trap_FS_Write(&newInfo, sizeof(postGameInfo_t), f);
      trap_FS_FCloseFile(f);
    }
  }

  if (newInfo.time < oldInfo.time) {
    uiInfo.newBestTime = uiInfo.uiDC.realTime + 20000;
  }

  // put back all the ui overrides
  trap_Cvar_Set("capturelimit", UI_Cvar_VariableString("ui_saveCaptureLimit"));
  trap_Cvar_Set("fraglimit", UI_Cvar_VariableString("ui_saveFragLimit"));
  trap_Cvar_Set("cg_drawTimer", UI_Cvar_VariableString("ui_drawTimer"));
  trap_Cvar_Set("g_doWarmup", UI_Cvar_VariableString("ui_doWarmup"));
  trap_Cvar_Set("g_Warmup", UI_Cvar_VariableString("ui_Warmup"));
  trap_Cvar_Set("sv_pure", UI_Cvar_VariableString("ui_pure"));
  trap_Cvar_Set("g_friendlyFire", UI_Cvar_VariableString("ui_friendlyFire"));

  UI_SetBestScores(&newInfo, qtrue);
  UI_ShowPostGame(newHigh);


}

static void UI_MessageMode_f( void )
{
  char *arg = UI_Argv( 0 );

  trap_Cvar_Set( "ui_sayBuffer", "" );

  switch( arg[ 11 ] )
  {
    default:
    case '\0':
      // Global
      uiInfo.chatTeam             = qfalse;
      break;

    case '2':
      // Team
      uiInfo.chatTeam             = qtrue;
      break;
  }

  trap_Key_SetCatcher( KEYCATCH_UI );
  Menus_CloseByName( "say" );
  Menus_CloseByName( "say_team" );

  if( uiInfo.chatTeam )
    Menus_ActivateByName( "say_team" );
  else
    Menus_ActivateByName( "say" );
}


/*
=================
UI_ConsoleCommand
=================
*/
qboolean UI_ConsoleCommand( int realTime )
{
  char  *cmd;
  char  *arg1;

  uiInfo.uiDC.frameTime = realTime - uiInfo.uiDC.realTime;
  uiInfo.uiDC.realTime = realTime;

  cmd = UI_Argv( 0 );

  // ensure minimum menu data is available
  //Menu_Cache();

  if ( Q_stricmp (cmd, "ui_test") == 0 ) {
    UI_ShowPostGame(qtrue);
  }

  if ( Q_stricmp (cmd, "ui_report") == 0 ) {
    UI_Report();
    return qtrue;
  }

  if ( Q_stricmp (cmd, "ui_load") == 0 ) {
    UI_Load();
    return qtrue;
  }

  if ( Q_stricmp (cmd, "remapShader") == 0 ) {
    if (trap_Argc() == 4) {
      char shader1[MAX_QPATH];
      char shader2[MAX_QPATH];
      Q_strncpyz(shader1, UI_Argv(1), sizeof(shader1));
      Q_strncpyz(shader2, UI_Argv(2), sizeof(shader2));
      trap_R_RemapShader(shader1, shader2, UI_Argv(3));
      return qtrue;
    }
  }

  if ( Q_stricmp (cmd, "postgame") == 0 ) {
    UI_CalcPostGameStats();
    return qtrue;
  }

  if ( Q_stricmp (cmd, "ui_cache") == 0 ) {
    UI_Cache_f();
    return qtrue;
  }

  if ( Q_stricmp (cmd, "ui_teamOrders") == 0 ) {
    //UI_TeamOrdersMenu_f();
    return qtrue;
  }

  if( Q_stricmp ( cmd, "menu" ) == 0 )
  {
    arg1 = UI_Argv( 1 );

    if( Menu_Count( ) > 0 )
    {
      trap_Key_SetCatcher( KEYCATCH_UI );
      Menus_ActivateByName( arg1 );
      return qtrue;
    }
  }

  if( Q_stricmp ( cmd, "closemenus" ) == 0 )
  {
    if( Menu_Count( ) > 0 )
    {
      trap_Key_SetCatcher( trap_Key_GetCatcher( ) & ~KEYCATCH_UI );
      trap_Key_ClearStates( );
      trap_Cvar_Set( "cl_paused", "0" );
      Menus_CloseAll( );
      return qtrue;
    }
  }

  if( Q_stricmp ( cmd, "messagemode" ) == 0 ||
      Q_stricmp ( cmd, "messagemode2" ) == 0 )
  {
    UI_MessageMode_f();
    return qtrue;
  }

  return qfalse;
}

/*
=================
UI_Shutdown
=================
*/
void UI_Shutdown( void ) {
}

/*
================
UI_AdjustFrom640

Adjusted for resolution and screen aspect ratio
================
*/
void UI_AdjustFrom640( float *x, float *y, float *w, float *h ) {
  // expect valid pointers
#if 0
  *x = *x * uiInfo.uiDC.scale + uiInfo.uiDC.bias;
  *y *= uiInfo.uiDC.scale;
  *w *= uiInfo.uiDC.scale;
  *h *= uiInfo.uiDC.scale;
#endif

  *x *= uiInfo.uiDC.xscale;
  *y *= uiInfo.uiDC.yscale;
  *w *= uiInfo.uiDC.xscale;
  *h *= uiInfo.uiDC.yscale;

}

void UI_DrawNamedPic( float x, float y, float width, float height, const char *picname ) {
  qhandle_t  hShader;

  hShader = trap_R_RegisterShaderNoMip( picname );
  UI_AdjustFrom640( &x, &y, &width, &height );
  trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
}

void UI_DrawHandlePic( float x, float y, float w, float h, qhandle_t hShader ) {
  float  s0;
  float  s1;
  float  t0;
  float  t1;

  if( w < 0 ) {  // flip about vertical
    w  = -w;
    s0 = 1;
    s1 = 0;
  }
  else {
    s0 = 0;
    s1 = 1;
  }

  if( h < 0 ) {  // flip about horizontal
    h  = -h;
    t0 = 1;
    t1 = 0;
  }
  else {
    t0 = 0;
    t1 = 1;
  }

  UI_AdjustFrom640( &x, &y, &w, &h );
  trap_R_DrawStretchPic( x, y, w, h, s0, t0, s1, t1, hShader );
}

/*
================
UI_FillRect

Coordinates are 640*480 virtual values
=================
*/
void UI_FillRect( float x, float y, float width, float height, const float *color ) {
  trap_R_SetColor( color );

  UI_AdjustFrom640( &x, &y, &width, &height );
  trap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );

  trap_R_SetColor( NULL );
}

void UI_DrawSides(float x, float y, float w, float h) {
  UI_AdjustFrom640( &x, &y, &w, &h );
  trap_R_DrawStretchPic( x, y, 1, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
  trap_R_DrawStretchPic( x + w - 1, y, 1, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
}

void UI_DrawTopBottom(float x, float y, float w, float h) {
  UI_AdjustFrom640( &x, &y, &w, &h );
  trap_R_DrawStretchPic( x, y, w, 1, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
  trap_R_DrawStretchPic( x, y + h - 1, w, 1, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
}
/*
================
UI_DrawRect

Coordinates are 640*480 virtual values
=================
*/
void UI_DrawRect( float x, float y, float width, float height, const float *color ) {
  trap_R_SetColor( color );

  UI_DrawTopBottom(x, y, width, height);
  UI_DrawSides(x, y, width, height);

  trap_R_SetColor( NULL );
}

void UI_SetColor( const float *rgba ) {
  trap_R_SetColor( rgba );
}

void UI_UpdateScreen( void ) {
  trap_UpdateScreen();
}


void UI_DrawTextBox (int x, int y, int width, int lines)
{
  UI_FillRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorBlack );
  UI_DrawRect( x + BIGCHAR_WIDTH/2, y + BIGCHAR_HEIGHT/2, ( width + 1 ) * BIGCHAR_WIDTH, ( lines + 1 ) * BIGCHAR_HEIGHT, colorWhite );
}

qboolean UI_CursorInRect (int x, int y, int width, int height)
{
  if (uiInfo.uiDC.cursorx < x ||
    uiInfo.uiDC.cursory < y ||
    uiInfo.uiDC.cursorx > x+width ||
    uiInfo.uiDC.cursory > y+height)
    return qfalse;

  return qtrue;
}