#include <alias.h>
inherit "/cmds/base";
private nosave string gfilter;
/**
 * Turn the compiled alias array into a string.
 * @param al the alias array
 * @return the string value of the alias array
 * @see compile_alias()
 */
string alias_string(mixed *al) {
   int i;
   int num;
   int *add_thing;
   string str;
   
   str = "";
   add_thing = ({ });
   for (i=0;i<sizeof(al);i++) {
      if (stringp(al[i])) {
         /*
           al[i] = replace(al[i], "@@", "@ @ ");
         */
         str += replace(al[i], ({";", "\\;"}));
      } else {
         num = al[i] & ALIAS_MASK;
         switch (al[i] - num) {
         case NEW_LINE  : 
            str += ";";
            break;
         case ALL_ARGS  : 
            str += "$*$";
            break;
         case ONE_ARG   : 
            str += "$"+num+"$";
            break;
         case TO_ARG    : 
            str += "$*"+num+"$";
            break;
         case FROM_ARG  : 
            str += "$"+num+"*$";
            break;
         case ALL_ARG   : 
            str += "$arg:"+al[++i]+"$";
            break;
         case ARG_THING : 
            str += "$arg"+num+":"+al[++i]+"$";
            break;
         case ELSE_THING :
           str += "$else$";
           /*
             add_thing[sizeof(add_thing)-1] = i+1+al[++i];
           */
           break;
         case ALL_IFARG : 
            str += "$ifarg:";
            /*
              add_thing += ({ i+1+al[++i] });
            */
            break;
         case IFARG_THING :
            str += "$ifarg"+num+":";
            /*
              add_thing += ({ i+1+al[++i] });
            */
            break;
         case CURR_LOC :
            str += "$!$";
            break;
         case END_IF      :
            str += "$endif$";
            break;
         }
      }
      /*
        if (member_array(i, add_thing) != -1)
        str += "~$";
      */
   }
   return str;
} /* alias_string() */
/**
 * Prints out all the aliases on the player object.  This is called by the
 * alias command when no arguments are specified.
 * @return 0 if no aliases are defined, 1 if they are
 * @see alias()
 */
int print_aliases(string filter, int sorted) {
   int i;
   int len;
   string str;
   string str1;
   string str2;
   string *tmp;
   string bing;
   mapping aliases;
   string ret;
 
   aliases = this_player()->query_aliases();
   /* 
    * ahh well here goes the clean. you dont want to know what used to
    * be here ;)
    */
   if (!m_sizeof(aliases)) {
      notify_fail("None defined.\n");
      return 0;
   }
 
   str1 = "";
   str2 = "";
   tmp = m_indices(aliases);
   if (filter) {
      if (regexp(filter, 
           "[\\[\\]\\(\\)\\*\\?\\+][\\[\\]\\(\\)\\*\\?\\+]+") ) {
         add_failed_mess("Bad pattern to alias.\n");
         return 0;
      }
      if (filter[0] == '*' || filter[0] == '+') {
         add_failed_mess("Cannot start a regular expression with a '*' or '+', "
                         "try: '.*' or '.+'.\n");
         return 0;
      }
      gfilter = "^" + filter;
      if (catch(tmp = filter_array(tmp, (: $1 && regexp($1, gfilter) :)))) {
         add_failed_mess("Bad pattern to alias (mismatched brackets?).\n");
         return 0;
      }
   }
    
   tmp = sort_array(tmp, 1);
   ret = "You currently have the following aliases:\n";
   for (i = 0; i < sizeof(tmp); i++) {
      if (!tmp[i]) {
         map_delete(aliases, 0);
         continue;
      }
      bing = alias_string(aliases[tmp[i]]);
      if (!bing) {
         bing = "Error in the alias!";
      }
      if (!tmp[i]) {
         tmp[i] = "icky";
      }
      if (strsrch(bing, "%^") != -1) {
         bing = replace_string(bing, "%^", "% ^");
         tmp[i] += " (colour replace)";
      }
      str = tmp[i] + ": " + bing;
      if (strlen(str) > 39 || sorted) {
         len = this_player()->query_cols() - strlen(tmp[i]) - 2;
         if (len < 0) {
            len = 10;
         }
         /* If it is too long, print it right now. */
         ret += sprintf("%s: %-=*s\n", tmp[i], len, bing);
      } else if (strlen(str) > 19) {
         str1 += str+"\n";
      } else {
         str2 += str+"\n";
      }
   }
   if (strlen(str1)) {
      ret += sprintf("%-#*s\n", this_player()->query_cols(), str1);
   }
   if (strlen(str2)) {
      ret += sprintf("%-#*s\n", this_player()->query_cols(), str2);
   }
   ret += sprintf("A total of %d aliases.\n", sizeof(tmp));
   this_player()->more_string(ret);
   return 1;
} /* print_aliases() */
/**
 * Creates the compiled alias array.  See the alias.h file for the
 * definitions of thevalues in the alias array.
 * @param str the string to compile
 * @return the compiled alias array
 * @see /include/alias.h
 */
mixed *compile_alias(string str) {
   mixed *ret;
   int i;
   int space;
   string *frog;
   string s1;
   int tmp;
   int gumby;
   int nodollar;
   int ending_dollar;
   mixed *ifargs;
   
   str = replace(str, ({ "\\;", "$escaped$", ";", "$new_line$", " ", " " }));
   str = replace(str, "$escaped$", ";");
   if(str[sizeof(str)-1] == '$')
     ending_dollar = 1;
   
   frog = explode("&" + str + "&", "$");
   if (frog[0] == "&") {
      frog[0] = "";
   } else {
      frog[ 0 ] = frog[ 0 ][ 1 .. ];
   }
   s1 = frog[<1];
   if (s1 == "&") {
      frog = frog[0..<2];
   } else {
      frog[<1] = s1[0..<2];
   }
   ret = ({ frog[0] });
   ifargs = ({ });
   nodollar = 1;
   for (i = 1; i < sizeof(frog); i++) {
      switch (frog[i]) {
      case "new_line" :
         ret += ({ NEW_LINE });
         nodollar = 1;
         break;
      case "*" :
         ret += ({ ALL_ARGS });
         gumby = 1;
         nodollar = 1;
         break;
      case "!" :
         /* hack by CPR for andrew so that $!$ substitues current location */
         if (this_object()->query_creator()) {
            ret += ({ CURR_LOC });
            nodollar = 1;
            /* end of hack by CPR */
         }
         break;
      case "else" :
         if (sizeof(ifargs)) {
            ret[ifargs[sizeof(ifargs)-1]] = sizeof(ret) -
               ifargs[sizeof(ifargs)-1]+1;
            ret += ({ ELSE_THING, 0, "" });
            ifargs[sizeof(ifargs)-1] = sizeof(ret)-2;
            nodollar = 1;
         }
         break;
      case "~" :
      case "endif" :
         if (sizeof(ifargs)) {
            ret += ({ END_IF });
            ret[ifargs[sizeof(ifargs)-1]] = sizeof(ret)-
               ifargs[sizeof(ifargs)-1];
            ifargs = delete(ifargs, sizeof(ifargs)-1, 1);
            nodollar = 1;
            space = 1;
         }
         break;
      default :
         if (frog[i][0..4] == "ifarg") {
            if (sscanf(frog[i], "ifarg%d:%s", tmp, s1) == 2) {
               if (tmp < 0) {
                  tmp = 0;
               }
               if (tmp > ALIAS_MASK) {
                  tmp = ALIAS_MASK;
               }
               ret += ({ IFARG_THING+ tmp, 0, "" });
               frog[i--] = s1;
               nodollar = 1;
               ifargs += ({ sizeof(ret)-2 });
               space = 0;
               gumby = 1;
            } else if (frog[i][5] == ':') {
               ret += ({ ALL_IFARG, 0, "" });
               frog[i] = frog[i][6..];
               nodollar = 1;
               ifargs += ({ sizeof(ret)-2 });
               space = 0;
               gumby = 1;
               i--;
            } else {
               if (sizeof(ret) && stringp(ret[sizeof(ret)-1]) && !space) {
                  ret[sizeof(ret)-1] += "$"+frog[i];
               } else if (nodollar) {
                  ret += ({ frog[i] });
                  nodollar = 0;
               } else {
                  ret += ({ "$"+frog[i] });
               }
            }
         } else if (frog[i][0..2] == "arg") {
            if (sscanf(frog[i], "arg%d:%s", tmp, s1) == 2) {
               if (tmp < 0) {
                  tmp = 0;
               }
               if (tmp > ALIAS_MASK) {
                  tmp = ALIAS_MASK;
               }
               ret += ({ ARG_THING+ tmp, s1, "" }); 
               nodollar = 1;
               gumby = 1;
            } else if (frog[i][3] == ':') {
               ret += ({ ALL_ARG, frog[i][4..100], "" });
               nodollar = 1;
               gumby = 1;
            } else {
               if (sizeof(ret) && stringp(ret[sizeof(ret)-1]) && !space) {
                  ret[sizeof(ret)-1] += "$"+frog[i];
               } else if (nodollar) {
                  ret += ({ frog[i] });
                  nodollar = 0;
               } else {
                  ret += ({ "$"+frog[i] });
               }
               gumby = 1;
               space = 0;
            }
         } else if (strlen(frog[i]) && frog[i][<1] == '*' &&
                    sscanf(frog[i], "%d%s*", tmp, s1) == 2 && s1 == "") {
            if (tmp < 0) {
               tmp = 0;
            }
            if (tmp > ALIAS_MASK) {
               tmp = ALIAS_MASK;
            }
            ret += ({ FROM_ARG + tmp });
            gumby = 1;
            nodollar = 1;
         } else if (strlen(frog[i]) && frog[i][0] == '*' && 
                    sscanf(frog[i][1..], "%d%s", tmp,s1) == 2 && s1 == "") {
           if (tmp < 0) {
             tmp = 0;
           }
           if (tmp > ALIAS_MASK) {
             tmp = ALIAS_MASK;
           }
           ret += ({ TO_ARG + tmp });
           gumby = 1;
           nodollar = 1;
         } else if (sscanf(frog[i], "%d%s", tmp, s1) == 2 && s1 == "" &&
                    (i < sizeof(frog)-1 || ending_dollar)) {
           if (tmp < 0) {
             tmp = 0;
           }
           if (tmp > ALIAS_MASK) {
             tmp = ALIAS_MASK;
           }
           ret += ({ ONE_ARG + tmp });
           gumby = 1;
           nodollar = 1;
         } else {
            if (!nodollar) {
               frog[i] = "$"+frog[i];
            }
            nodollar = 0;
            space = 0;
            if (strlen(frog[i]) && frog[i][<1] == '~') {
               if (sizeof(ifargs)) {
                  if (strlen(frog[i]) == 1) {
                     frog[i] = "";
                  } else {
                     frog[i] = frog[i][0..<2];
                  }
                  /* create an offset */
                  ret += ({ END_IF });
                  ret[ifargs[<1]] = sizeof(ret) - ifargs[<1];
                  ifargs = ifargs[0..<2];
                  nodollar = 1;
                  space = 1;
               }
            }
            if (sizeof(ret) && stringp(ret[<1]) && space != 2) {
               ret[<1] += frog[i];
            } else {
               ret += ({ frog[i] });
            }
            if (space) {
               space = 2;
            }
         }
      }
   }
   while (sizeof(ifargs)) {
      ret += ({ END_IF });
      ret[ifargs[sizeof(ifargs)-1]] = sizeof(ret)-
         ifargs[sizeof(ifargs)-1];
      ifargs = delete(ifargs, sizeof(ifargs)-1, 1);
   }
   if (!gumby) {
      if (sizeof(ret) && !stringp(ret[sizeof(ret)-1]) || space) {
         ret += ({ " ", ALL_ARGS });
      } else if(sizeof(ret)) {
         ret[sizeof(ret)-1] += " ";
         ret += ({ ALL_ARGS });
      }
   }
   return ret;
} /* compile_alias() */
/**
 * This method will print out one or more aliases.
 * @param str the aliases to print
 */
int print_some_aliases(string str, int every) {
   if (this_player()->is_alias(str) && !every) {
      printf("%s: %-=*s\n", str, 
                (int)this_player()->query_cols() - strlen(str) -2, 
                alias_string(this_player()->query_player_alias(str)));
      return 1;
   }
   return print_aliases(str, 0);
} /* print_some_aliases() */
/**
 * The main alias control function.  Sets up new aliases and prints out
 * the values of single aliases or all the aliases.
 * @param str the command name
 * @return 0 if the alias command failed, 1 if it succeeded
 * @see edit_alias()
 * @see print_aliases()
 */
protected int alias(string name, string value) {
#ifdef DISALLOW_COLOUR 
   if (strsrch(name, "%^") >= 0 || strsrch(value, "%^") >= 0) {
      notify_fail("Cannot add an alias with a colour escape "
                  "sequence (% ^).\n");
      return 0;
   }
#endif
   if (strsrch(value, "END_ALIAS") != -1) {
      add_failed_mess("You cannot use 'END_ALIAS' in an alias.\n");
      return 0;
   }
   
   name = implode(explode(name, " "), "");
   if (name == "unalias" || name == "alias" || name == "ealias")  {
      add_failed_mess("You can't alias the '" + name + "' command, because "
                      "otherwise, there would be Problems.\n");
      return 0;
   }
   if (!this_player()->is_alias(name)) {
      this_player()->add_player_alias(name, compile_alias(value));
      write("Added alias '" + name + "'.\n");
   } else {
      this_player()->add_player_alias(name, compile_alias(value));
      write("Changed alias '" + name + "'.\n");
   }
   return 1;
} /* alias() */
/** @ignore yes */
mixed *query_patterns() {
   return ({ 
         "", (: print_aliases("", 0) :),
         "sorted", (: print_aliases("", 1) :),
         "every <word'alias'>", (: print_some_aliases($4[0], 1) :), 
         "<word'alias'>", (: print_some_aliases($4[0], 0) :), 
         "<word'alias'> <string>", (: alias($4[0], $4[1]) :)
         });
} /* query_patterns() */