/*

 BabbleMud - A MUD server

 Author:  Nick Gammon 
          http://www.gammon.com.au/ 

(C) Copyright Nick Gammon 2004. Permission to copy, use, modify, sell and
distribute this software is granted provided this copyright notice appears
in all copies. This software is provided "as is" without express or implied
warranty, and with no claim as to its suitability for any purpose.
 
*/

#include <stdlib.h>
#include <time.h>

#include "commands.h"

const int getrandom (const int x)
{
	long n;

	if (x <= 0)
		return 0;
		n = rand ();
	return (n % x);
}   // end of getrandom

const int roll (const int howmany, const int die)
{
	int count;
	int total = 0;

	for (count = 0; count < howmany; ++count)
		total += getrandom (die) + 1;

	return total;

} // end of roll


// returns true of a x% probability exists
// eg. percent (80) will be true 80% of the time
const bool percent (const int prob)
  {
  if (prob <= 0)
    return false;
  if (prob >= 100)
    return true;

  return getrandom (100) > (100 - prob);

  }

static int initRandom ()
  {
  srand   (time (NULL));
#ifndef WIN32
  srand48 (time (NULL));
#endif
  return 0;
  }

// initialise random number generator
static int someNumber = initRandom ();

extern ofstream logFileGeneral;
extern ofstream logFileFailedCommands;

void generalLogger (ofstream & f,   // what log file
                    const string & suppliedFileName,  // log file name
                    string & actualFileName,          // log file with date in it
                    const string & what,      // what to log
                    const Character * player) // player, if any
  {
string logFileName = FindAndReplace (suppliedFileName, "~", stringFileDate (time (NULL)));
  
  // if log file not open, open it
  // if already open, and date has changed, close and re-open it
  if (!f.is_open () || actualFileName != logFileName)
    {
    if (f.is_open ())
      f.close (); // close if already open so we can re-open with different name
    
    cout << "Opening log file " << logFileName << endl;
    
    f.open (logFileName.c_str (), ios::out | ios::app);
    if (!f.is_open ())
      throw runtime_error ("Could not open log file: " + logFileName + " for writing.");
    
    actualFileName = logFileName;    // remember name
    }
  
  string who = "Game";
  if (player)
    who = player->gets ("name");
  
  f << stringShortDate (time (NULL)) << " :: " << who << ": " << what << endl;
  
  if (f.fail ())
      throw runtime_error ("Could not write to log file: " + logFileName);
    
  } // end of generalLogger

/*
I am making routines here to statically store the current file name,
so we can detect when to roll over log files to a new day, and a failure
flag, which will remain set if an exception is thrown, so we don't keep
logging to a failed file (eg. disk full)
*/

#define MAKE_LOG_ROUTINE(func_name, log_file, log_file_name)  \
void func_name (const string & what, const Character * player) \
  {\
static bool failed = false;\
static string currentFileName;\
  if (failed) \
    return; \
  failed = true;  \
  generalLogger (log_file, log_file_name, currentFileName, what, player); \
  failed = false; \
  }

// log something
MAKE_LOG_ROUTINE (gamelog, logFileGeneral, LOG_FILE)
 
// log failed commands
MAKE_LOG_ROUTINE (failedlog, logFileFailedCommands, LOG_FILE_FAILED)

// log web server
MAKE_LOG_ROUTINE (webserverlog, logFileWebServer, LOG_FILE_WEB_SERVER)

// convert error code like "comms_error_bind" into its actual message
// you supply a prefix, which is put in front of the code (eg. fr_ )
const string convertErrorCode (const string & code, const string & prefix)
  {
  // lookup message in map
  StringMap::const_iterator iter = errormap ().find (prefix + code);
  
  string msg;
  
  // if found, take it, otherwise use default of code
  if (iter != errormap ().end ())
      msg = iter->second;
  else
      msg = messagemap () [prefix + "no_error_message"] + " [" + prefix + code + "]";
  // return results
  return msg;
  
  } // end of convertErrorCode

const string convertMessageCode (const string & code, const string & prefix)
  {
  // lookup message in map
  StringMap::const_iterator iter = messagemap ().find (prefix + code);
  
  string msg;
  
  // if found, take it, otherwise use default of code
  if (iter != messagemap ().end ())
      msg = iter->second;
  else
      msg = messagemap () [prefix + "no_message_message"] + " [" + prefix + code + "]";
  
  return msg;
  
  } // end of convertMessageCode
