/*
 * Multi-Lingual function library
 *
 * By Ravenous Bugblatter Beast
 * ravenousbugblatterbeast@hotmail.com
 * http://www.ravenousbugblatterbeast.pwp.blueyonder.co.uk
 *
 *
 * This include file contains the functions necessary to support multi-lingual
 * messaging in your plugins.
 *
 *
 * Remember that the player must have plugin_blatt_language installed with your plugin
 * in order for them to choose a language.
 *
 *
 * Functions:
 *
 * language_init()  -  You must call this from plugin_init()
 * language_update()  -  Used for communication with plugin_blatt_language - ignore
 *
 * language_get(UserIndex)  -  Returns a players chosen language ID
 * language_getbyname(UserName)  -  As above
 *
 * language_say(UserIndex,MessageList,Location)  -  Sends a message to the user in their chosen language.
 * language_saybyname(UserName,MessageList,Location)  -  As above using user name instead of index to identify user
 * language_sayall(MessageList,Locaiton)  -  Sends a message to all users in their chosen languages
 *
 * language_sayf(UserIndex,MessageList,Location,...) - Same as langauge_say, with a format string
 * language_saybynamef(UserName,MessageList,Location,...) - Same as langauge_saybyname, with a format string
 * language_sayallf(MessageList,Locaiton,...) - Same as language_sayallf, with a format string
 *
 *
 *
 *
 * Message Lists
 *
 * You declare a MessageList for use with this plugin by creating a string with the | character
 * seperating the versions for each language. English must be the first language and must always
 * be present. The order for other languages is:
 *
 * 1: English
 * 2: French
 * 3: German
 * 4: Spanish
 *
 * E.g.
 * new g_MSG_ONE[] = "One|Un|Ein|Uno";
 *
 * If you do not have a transalation for a particular language available, leave an empty message
 * in the string - .e.g If you have no german translation, the above string would be:
 *
 * new g_MSG_ONE[] = "One|Un||Uno";
 *
 *
 *
 * Formatted Message Lists
 *
 * If you use the "sayf" versions of the functions, you can include snprintf-type format strings in the message lists.
 * However, unlike printf you must include a number between the % and the letter code - e.g. "%2s" instead of "%s". The
 * number is the position of the argument in the argument list. This allows you to repeat the same argument twice, and
 * to place the arguments in a different order in different languages as the grammar may demand.
 * e.g.
 *
 * new g_MSG_INSERT[] = "Player %1s has chosen map %2s|La carte %2s a choisie par le joueur %1s";
 * language_sayallf(g_MSG_INSERT.print_pretty,PlayerName,Mapname);
 *
 * Supported format goes are %1s = string, %1i and %1d = integer and %1c = character. For %1c provide a number value containing
 * the ascii code of the character.
 *
 *
 *
 * Location
 *
 * The location argument should be one of: print_console, print_center,  print_chat, print_tty, print_pretty
 *
 */
 
#if defined _language_included
  #endinput
#endif
#define _language_included
 
 
/* Versions of adminmod 2.50.56 or later define ADMINMOD_VERISON.
 * If its not defined, assume this is 2.50.50 */
#if !defined(ADMINMOD_VERSION)
  #define ADMINMOD_VERSION 25050
#endif
 
 
#define LANGUAGE_MAX_WIDTH 600;
#define DEFAULT_DEFAULT_LANGUAGE 1;
#define MIN_DEFAULT_LANGUAGE 1;
#define MAX_DEFAULT_LANGUAGE 3;
 
new g_Languages[MAX_PLAYERS] = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
new g_Width[256];
new g_DefaultLanguage = DEFAULT_DEFAULT_LANGUAGE;
/*
 * All plugins must call language_init() from their plugin_init(). No "stock" specifier
 * is used, so a compiler warning is generated if they don't.
 */
language_init() {
  readvaultnum("bblanguage_default",g_DefaultLanguage,DEFAULT_DEFAULT_LANGUAGE,MIN_DEFAULT_LANGUAGE,MAX_DEFAULT_LANGUAGE);
  plugin_registercmd("language_update","language_update",ACCESS_ALL,"");
 
  new i=0;
 
  for (i=0;i<256;i++) {
    g_Width[i] = 7;
  }
 
  /* These are the pixel withs of each character in counter-strike's console font */
  g_Width['a'] = 7;
  g_Width['b'] = 7;
  g_Width['c'] = 7;
  g_Width['d'] = 7;
  g_Width['e'] = 7;
  g_Width['f'] = 5;
  g_Width['g'] = 7;
  g_Width['h'] = 7;
  g_Width['i'] = 3;
  g_Width['j'] = 3;
  g_Width['k'] = 6;
  g_Width['l'] = 3;
  g_Width['m'] = 9;
  g_Width['n'] = 7;
  g_Width['o'] = 7;
  g_Width['p'] = 7;
  g_Width['q'] = 7;
  g_Width['r'] = 5;
  g_Width['s'] = 7;
  g_Width['t'] = 4;
  g_Width['u'] = 3;
  g_Width['v'] = 7;
  g_Width['w'] = 11;
  g_Width['x'] = 7;
  g_Width['y'] = 7;
  g_Width['z'] = 7;
 
  g_Width['1'] = 5;
  g_Width['2'] = 7;
  g_Width['3'] = 7;
  g_Width['4'] = 7;
  g_Width['5'] = 7;
  g_Width['6'] = 7;
  g_Width['7'] = 7;
  g_Width['8'] = 7;
  g_Width['9'] = 7;
  g_Width['0'] = 7;
  g_Width['-'] = 5;
  g_Width['='] = 7;
 
  g_Width['A'] = 9;
  g_Width['B'] = 8;
  g_Width['C'] = 8;
  g_Width['D'] = 8;
  g_Width['E'] = 7;
  g_Width['F'] = 7;
  g_Width['G'] = 9;
  g_Width['H'] = 8;
  g_Width['I'] = 3;
  g_Width['J'] = 6;
  g_Width['K'] = 8;
  g_Width['L'] = 7;
  g_Width['M'] = 9;
  g_Width['N'] = 8;
  g_Width['O'] = 9;
  g_Width['P'] = 7;
  g_Width['Q'] = 9;
  g_Width['R'] = 8;
  g_Width['S'] = 8;
  g_Width['T'] = 7;
  g_Width['U'] = 8;
  g_Width['V'] = 9;
  g_Width['W'] = 12;
  g_Width['X'] = 8;
  g_Width['Y'] = 9;
  g_Width['Z'] = 8;
 
  g_Width['!'] = 3;
  g_Width['@'] = 12;
  g_Width['#'] = 7;
  g_Width['$'] = 7;
  g_Width['%'] = 11;
  g_Width['^^'] = 7;
  g_Width['&'] = 8;
  g_Width['*'] = 5;
  g_Width['('] = 5;
  g_Width[')'] = 5;
  g_Width['_'] = 8;
  g_Width['+'] = 7;
 
  g_Width['['] = 4;
  g_Width[']'] = 4;
  g_Width['{'] = 5;
  g_Width['}'] = 6;
  g_Width[';'] = 3;
  g_Width['^''] = 3;
  g_Width['\'] = 5;
  g_Width[':'] = 3;
  g_Width['"'] = 5;
  g_Width['|'] = 3;
  g_Width['.'] = 4;
  g_Width[','] = 4;
  g_Width['/'] = 5;
  g_Width['<'] = 7;
  g_Width['>'] = 7;
  g_Width['?'] = 7;
  g_Width[' '] = 8;
 
  return 0;
}
 
 
 
/*
 * Receives updates on player's preferred languages from plugin_blatt_language
 * Should not be called from anywhere else
 */
public language_update(HLCommand,HLData,HLUserName,UserIndex) {
  new Data[MAX_DATA_LENGTH];
  convert_string(HLData,Data,MAX_DATA_LENGTH);
 
  if (strlen(Data)==MAX_PLAYERS-1) {
    strcpy(g_Languages,Data,MAX_PLAYERS);
  }
  else {
    snprintf(Data,MAX_DATA_LENGTH,"Language update got %i, expected %i",strlen(Data),MAX_PLAYERS);
    log("ERROR: language_update received invalid data");
  }
 
  return PLUGIN_CONTINUE;
}
 
 
 
/* Extracts the message in the requested language from a messagelist
 * If the list contains no message for the requested language, the
 * English message is returned.
 */
public language_message(MessageList[],Index,Message[]) {
 
  new c=strcount(MessageList, '|');
  if (Index > c) {
    Index=0;
  }
 
  new i=0;
  new st=0;
  new ed=0;
 
  while (st<Index) {
    if (MessageList[i] == '|') {
      st++;
    }
    i++;
  }
 
  st=i; /* st now contains start index */
 
  if (Index == c) {
    ed = strlen(MessageList);
  }
  else {
    while (MessageList[i] != '|') {
      i++;
    }
    ed = i;
  }
 
  /* ed now cotnain stop index+1 */
 
  new out=0;
  while (st < ed) {
    Message[out] = MessageList[st];
    out++;
    st++;
  }
  Message[out]=0;
 
}
 
 
 
/*
 * Returns the language index for the preferred language of the
 * specified player index. No stock as amx has a bug that stock functions
 * can't see global varaibles properly + all plugins that use this include must
 * call it in order to do anything usefull, even if call is by virtue of using
 * one of the language_say family of functions rather than direct.
 */
language_get(UserIndex) {
  if (UserIndex<=0) {
    /* Server console use */
    return g_DefaultLanguage-1;
  }
  if (g_Languages[UserIndex-1] < 65) {
    return g_DefaultLanguage-1;
  }
  return max(0,g_Languages[UserIndex-1]-65);
}
 
stock language_getbyname(UserName[]) {
  new Index;
  if (get_userindex(UserName,Index)) {
    return language_get(Index);
  }
  return 0;
}
 
 
 
 
/* Inserts linefeeds in the message a appropraite points
 * for the chosen location.
 *
 * NOTE: All processing of languages has finised by this point
 * You can call this function directly as a replacement for messageex
 * to automatically insert linefeeds at the required places for
 * each location.
 */
 
stock language_output(UserName[],MessageIn[],print_type:Location,iTime,iRed,iGreen,iBlue) {
  new msg[MAX_TEXT_LENGTH+4]; /* 200 characters may wrap onto 4 lines */
  new i=0;
  new j=0;
  new c=strlen(MessageIn);
  new width=0;
  new linelen=0;
 
  while (i<c) {
    width+=g_Width[MessageIn[i]];
    if ((MessageIn[i]=='^n') || (width > LANGUAGE_MAX_WIDTH) || (((Location==print_type:print_center) || (Location==print_type:print_pretty)) && (linelen>77))){
 
      /* Going to break line, search back for a suitable character */
      if (MessageIn[i]!='^n') {
        new oi=i;
        new oj=j;
        while ((MessageIn[i] != ' ') && (j>0)) {
          i--;
          j--;
        }
        if (j==0) {
          i=oi;
          j=oj;
        }
      }
 
      if ((Location==print_type:print_center) || (Location==print_type:print_pretty)) {
        if (msg[j] == ' ') {
          msg[j]='^n';
          i++;
          j++;
        }
        else {
          msg[j]='^n';
          j++;
        }
      } else {
        if (MessageIn[i]=='^n') {
          i++;
        }
        msg[j]=NULL_CHAR;
        messageex(UserName,msg,Location);
        j=0;
      }
      width=g_Width[MessageIn[i]];
      linelen=0;
    }
    msg[j]=MessageIn[i];
    j++;
    i++;
    linelen++;
  }
  msg[j]=NULL_CHAR;
 
#if ADMINMOD_VERSION >= 25055
  if (Location==print_type:print_pretty) {
    centersayex(UserName,msg,iTime,iRed,iGreen,iBlue);
  }
  else {
    messageex(UserName,msg,Location);
  }
#else
  /* This is pointless but prevents compiler warnings on 2.50.50 */
  iTime=iRed;
  iRed=iTime;
  iGreen=iBlue;
  iBlue=iGreen;
  messageex(UserName,msg,Location);
#endif
 
}
 
 
/*
 * Sends a message to the specified player in their preferred language
 * Location is as for messageex function
 */
stock language_say(Index,MessageList[],print_type:Location,iTime=10,iRed=255,iGreen=255,iBlue=255) {
 
  new Message[MAX_TEXT_LENGTH];
  language_message(MessageList,language_get(Index),Message);
 
  new Name[MAX_NAME_LENGTH];
 
  if (Index>0) {
    if (playerinfo(Index,Name,MAX_NAME_LENGTH)) {
      language_output(Name,Message,Location,iTime,iRed,iGreen,iBlue);
    }
  }
  else {
    log(Message);
  }
}
 
 
 
/*
 * Sends a message to the specified player in their preferred language
 * Location is as for messageex function
 */
stock language_saybyname(Name[],MessageList[],print_type:Location,iTime=10,iRed=255,iGreen=255,iBlue=255)
{
  new Message[MAX_TEXT_LENGTH];
  language_message(MessageList,language_getbyname(Name),Message);
  language_output(Name,Message,Location,iTime,iRed,iGreen,iBlue);
}
 
 
 
/*
 * Sends a message all players in their preferred language
 * Location is as for messageex function
 */
stock language_sayall(MessageList[],print_type:Location,iTime=10,iRed=255,iGreen=255,iBlue=255) {
  new c = maxplayercount();
  new Name[MAX_NAME_LENGTH];
  new dummy;
  new i;
  new wonid;
  new team;
  new dead;
  new AuthID[MAX_AUTHID_LENGTH];
 
  for(i=1;i<=c;i++) {
    if (playerinfo(i,Name,MAX_NAME_LENGTH,dummy,wonid,team,dead,AuthID)) {
      if ((strcmp(AuthID,"BOT") != 0)) {
        new Message[MAX_TEXT_LENGTH];
        language_message(MessageList,language_get(i),Message);
        language_output(Name,Message,Location,iTime,iRed,iGreen,iBlue);
      }
    }
  }
}
 
 
 
/*
 * Sends a message to the specified player in their preferred language
 * Location is as for messageex function
 */
stock language_sayf(Index,MessageList[],print_type:Location,iTime,iRed,iGreen,iBlue,...) {
 
  new Messagef[MAX_TEXT_LENGTH];
  new Message[MAX_TEXT_LENGTH];
  language_message(MessageList,language_get(Index),Messagef);
 
 
  /* My implementation of snprintf - must be inserted rather than
   * called as a function in order to work properly :( */
  new i=0;
  new j=0;
  new apos=0;
  new aval=0;
  new num[16];
  new c = strlen(Messagef);
  new arg;
  while((i<c) && (j<MAX_TEXT_LENGTH-1)) {
    if(Messagef[i] != '%') {
      Message[j] = Messagef[i];
      j++;
    }
    else {
      if (Messagef[i+1] == '%') {
        Message[j] = '%';
        i++;
        j++;
      }
      else {
        arg=(Messagef[i+1]-49);
        if ((arg<0) || (arg>9)) {
          plugin_message("ERROR: Message format error in language_sayf - character other than 1-9 after a %%");
          return;
        }
        arg+=7;
        if (Messagef[i+2] == 'c') {
          Message[j] = getarg(arg);
          j++;
          i=i+2;
        } else if ((Messagef[i+2] == 'd') || (Messagef[i+2] == 'i'))  {
          numtostr(getarg(arg),num);
          strcat(Message,num,MAX_TEXT_LENGTH);
          j=j+strlen(num);
          i=i+2;
        } else if (Messagef[i+2] == 's') {
          apos=0;
          aval=getarg(arg,apos);
          while ((aval != 0) && (j<MAX_TEXT_LENGTH-1)) {
            Message[j] = aval;
            apos++;
            j++;
            aval=getarg(arg,apos);
          }
          i=i+2;
        } else {
          plugin_message("ERROR: Message format error in language_sayf - character other than c/d/i/s 2 after a %%");
          return;
        }
      }
    }
    i++;
  }
  Message[j] = 0;
  /* End of snprintf implementation */
 
 
  new Name[MAX_NAME_LENGTH];
 
  if (Index>0) {
    if (playerinfo(Index,Name,MAX_NAME_LENGTH)) {
      language_output(Name,Message,Location,iTime,iRed,iGreen,iBlue);
    }
  } else {
    log(Message);
  }
}
 
 
 
/*
 * Sends a message to the specified player in their preferred language
 * Location is as for messageex function
 */
stock language_saybynamef(Name[],MessageList[],print_type:Location,iTime,iRed,iGreen,iBlue,...)
{
  new Messagef[MAX_TEXT_LENGTH];
  new Message[MAX_TEXT_LENGTH];
  language_message(MessageList,language_getbyname(Name),Messagef);
 
  /* My implementation of snprintf - must be inserted rather than
   * called as a function in order to work properly :( */
  new i=0;
  new j=0;
  new apos=0;
  new aval=0;
  new num[16];
  new c = strlen(Messagef);
  new arg;
  while((i<c) && (j<MAX_TEXT_LENGTH-1)) {
    if(Messagef[i] != '%') {
      Message[j] = Messagef[i];
      j++;
    }
    else {
      if (Messagef[i+1] == '%') {
        Message[j] = '%';
        i++;
        j++;
      }
      else {
        arg=(Messagef[i+1]-49);
        if ((arg<0) || (arg>9)) {
          plugin_message("ERROR: Message format error in language_sayf - character other than 1-9 after a %%");
          return;
        }
        arg+=7;
        if (Messagef[i+2] == 'c') {
          Message[j] = getarg(arg);
          j++;
          i=i+2;
        } else if ((Messagef[i+2] == 'd') || (Messagef[i+2] == 'i'))  {
          numtostr(getarg(arg),num);
          strcat(Message,num,MAX_TEXT_LENGTH);
          j=j+strlen(num);
          i=i+2;
        } else if (Messagef[i+2] == 's') {
          apos=0;
          aval=getarg(arg,apos);
          while ((aval != 0) && (j<MAX_TEXT_LENGTH-1)) {
            Message[j] = aval;
            apos++;
            j++;
            aval=getarg(arg,apos);
          }
          i=i+2;
        } else {
          plugin_message("ERROR: Message format error in language_sayf - character other than c/d/i/s 2 after a %%");
          return;
        }
      }
    }
    i++;
  }
  Message[j] = 0;
  /* End of snprintf implementation */
 
 
  language_output(Name,Message,Location,iTime,iRed,iGreen,iBlue);
}
 
 
 
/*
 * Sends a message all players in their preferred language
 * Location is as for messageex function
 */
stock language_sayallf(MessageList[],print_type:Location,iTime,iRed,iGreen,iBlue,...) {
  new plc = maxplayercount();
  new Name[MAX_NAME_LENGTH];
  new dummy;
  new wonid;
  new team;
  new dead;
  new pl;
  new AuthID[MAX_AUTHID_LENGTH];
 
  for(pl=1;pl<=plc;pl++) {
    if (playerinfo(pl,Name,MAX_NAME_LENGTH,dummy,wonid,team,dead,AuthID)) {
      if ((streq(AuthID,"BOT") == 0)) {
        new Messagef[MAX_TEXT_LENGTH];
        new Message[MAX_TEXT_LENGTH];
        language_message(MessageList,language_get(pl),Messagef);
 
        /* My implementation of snprintf - must be inserted rather than
         * called as a function in order to work properly :( */
        new i=0;
        new j=0;
        new apos=0;
        new aval=0;
        new num[16];
        new c = strlen(Messagef);
        new arg;
        while((i<c) && (j<MAX_TEXT_LENGTH-1)) {
          if(Messagef[i] != '%') {
            Message[j] = Messagef[i];
            j++;
          }
          else {
            if (Messagef[i+1] == '%') {
              Message[j] = '%';
              i++;
              j++;
            }
            else {
              arg=(Messagef[i+1]-49);
              if ((arg<0) || (arg>9)) {
                plugin_message("ERROR: Message format error in language_sayf - character other than 1-9 after a %%");
                return;
              }
              arg+=6; /* NOTE: This is different to the other copies as there are only 6 fixed args */
              if (Messagef[i+2] == 'c') {
                Message[j] = getarg(arg);
                j++;
                i=i+2;
              } else if ((Messagef[i+2] == 'd') || (Messagef[i+2] == 'i'))  {
                numtostr(getarg(arg),num);
                strcat(Message,num,MAX_TEXT_LENGTH);
                j=j+strlen(num);
                i=i+2;
              } else if (Messagef[i+2] == 's') {
                apos=0;
                aval=getarg(arg,apos);
                while ((aval != 0) && (j<MAX_TEXT_LENGTH-1)) {
                  Message[j] = aval;
                  apos++;
                  j++;
                  aval=getarg(arg,apos);
                }
                i=i+2;
              } else {
                plugin_message("ERROR: Message format error in language_sayf - character other than c/d/i/s 2 after a %%");
                return;
              }
            }
          }
          i++;
        }
        Message[j] = 0;
        /* End of snprintf implementation */
 
        language_output(Name,Message,Location,iTime,iRed,iGreen,iBlue);
      }
    }
  }
}
 
 
/*
 * Sends a message all players that are dead in their preferred language
 * Location is as for messageex function
 */
stock language_saydeadf(MessageList[],print_type:Location,iTime,iRed,iGreen,iBlue,...) {
  new plc = maxplayercount();
  new Name[MAX_NAME_LENGTH];
  new dummy;
  new wonid;
  new team;
  new dead;
  new pl;
  new AuthID[MAX_AUTHID_LENGTH];
 
  for(pl=1;pl<=plc;pl++) {
    if (playerinfo(pl,Name,MAX_NAME_LENGTH,dummy,wonid,team,dead,AuthID)) {
      if ((streq(AuthID,"BOT") == 0) && (dead==1)) {
        new Messagef[MAX_TEXT_LENGTH];
        new Message[MAX_TEXT_LENGTH];
        language_message(MessageList,language_get(pl),Messagef);
 
        /* My implementation of snprintf - must be inserted rather than
         * called as a function in order to work properly :( */
        new i=0;
        new j=0;
        new apos=0;
        new aval=0;
        new num[16];
        new c = strlen(Messagef);
        new arg;
        while((i<c) && (j<MAX_TEXT_LENGTH-1)) {
          if(Messagef[i] != '%') {
            Message[j] = Messagef[i];
            j++;
          }
          else {
            if (Messagef[i+1] == '%') {
              Message[j] = '%';
              i++;
              j++;
            }
            else {
              arg=(Messagef[i+1]-49);
              if ((arg<0) || (arg>9)) {
                plugin_message("ERROR: Message format error in language_sayf - character other than 1-9 after a %%");
                return;
              }
              arg+=6; /* NOTE: This is different to the other copies as there are only 6 fixed args */
              if (Messagef[i+2] == 'c') {
                Message[j] = getarg(arg);
                j++;
                i=i+2;
              } else if ((Messagef[i+2] == 'd') || (Messagef[i+2] == 'i'))  {
                numtostr(getarg(arg),num);
                strcat(Message,num,MAX_TEXT_LENGTH);
                j=j+strlen(num);
                i=i+2;
              } else if (Messagef[i+2] == 's') {
                apos=0;
                aval=getarg(arg,apos);
                while ((aval != 0) && (j<MAX_TEXT_LENGTH-1)) {
                  Message[j] = aval;
                  apos++;
                  j++;
                  aval=getarg(arg,apos);
                }
                i=i+2;
              } else {
                plugin_message("ERROR: Message format error in language_sayf - character other than c/d/i/s 2 after a %%");
                return;
              }
            }
          }
          i++;
        }
        Message[j] = 0;
        /* End of snprintf implementation */
 
        language_output(Name,Message,Location,iTime,iRed,iGreen,iBlue);
      }
    }
  }
}