/*    /adm/simul_efun/english.c
 *    from Dead Souls
 *    efuns for dealing with the oddity we know as the English language
 *    created by Descartes of Borg 940207
 *    Version: @(#) english.c 1.5@(#)
 *    Last modified: 97/01/01
 */

#include <daemons.h>

string *localcmds;

string match_command(string verb){
    string *local_arr;
    localcmds = ({});
    filter(this_player()->GetCommands(), (: localcmds += ({ $1[0] }) :));
    localcmds += CMD_D->GetCommands();
    localcmds += keys(VERBS_D->GetVerbs());
    if(member_array(verb,localcmds) == -1){
	if(alphap(verb[0..0])) local_arr = regexp(localcmds,"^"+verb);
	if(sizeof(local_arr) == 1) {
	    return local_arr[0];
	}
    }
    return "";
}

varargs string add_article(string str, int def) {
    if( !stringp(str) ) {
	error("Bad argument 1 to add_article().\n");
    }
    if( def ) {
	str = remove_article(str);
	return "the " + str;
    }
    if( !strlen(str) ) {
	return str;
    }
    switch(str[0]) {
    case 'a': case 'e': case 'i': case 'o': case 'u':
    case 'A': case 'E': case 'I': case 'O': case 'U':
	return "an " + str;

    default:
	return "a " + str;
    }
}

string remove_article(string str) {
    string tmp;

    if( !stringp(str) ) error("Bad argument 1 to remove_article().\n");
    if( sscanf(str, "the %s", tmp) ) return tmp;
    if( sscanf(str, "a %s", tmp) ) return tmp;
    if( sscanf(str, "an %s", tmp) ) return tmp;
    return str;
}

string array explode_list(string list) {
    string array items;
    string one, two;

    list = lower_case(list);
    if( sscanf(list, "%s and %s", one, two) == 2 ) {
	items = explode(one, ",") + explode(two, ",");
    }
    else {
	items = explode(list, ",");
    }
    items = map(items, function(string str) {
	  if( !str ) {
	      return 0;
	  }
	  str = trim(str);
	  if( strlen(str) > 4 && str[0..3] == "and " ) {
	      str = str[4..];
	  }
	  str = remove_article(str);
	  if( strlen(str) > 3 && str[0..2] == "my " ) {
	      str = str[3..];
	  }
	  return str;
	});
      return filter(items, (: $1 && $1 != "" :));
  }

    varargs string item_list(mixed array items...) {
	mapping list = ([]);
	string str;
	int maxi;

	if( !sizeof(items) ){
	    error("Bad argument 1 to item_list().\n");
	}
	if( arrayp(items[0]) ) {
	    if( !sizeof(items[0]) ) {
		return "";
	    }
	    items = items[0];
	}
	foreach(mixed value in items) {
	    if( objectp(value) ) {
		if( living(value) ) {
		    value = value->GetName();
		}
		else {
		    value = value->GetShort();
		}
	    }
	    if( !value ) {
		continue;
	    }
	    if( !list[value] ) {
		list[value] = 1;
	    }
	    else {
		list[value]++;
	    }
	}
	maxi = sizeof(items = keys(list));
	if( maxi < 1 ) {
	    return "";
	}
	str = consolidate(list[items[0]], items[0]);
	if( maxi == 1 ) {
	    return str;
	}
	if( maxi > 2 ) {
	    str += ",";
	}
	for(int i=1; i<maxi; i++) {
	    if( i == maxi-1 ) {
		str += " and ";
	    }
	    else {
		str += " ";
	    }
	    str += consolidate(list[items[i]], items[i]);
	    if( i < maxi-1 ) {
		str += ",";
	    }
	}
	return str;
    }

    string possessive_noun(mixed val) {
	if(objectp(val)) val = (string)val->GetName();
	else if(!stringp(val)) error("Bad argument 1 to possessive_noun().\n");
	switch(val[strlen(val)-1]) {
	case 'x': case 'z': case 's': return sprintf("%s'", val);
	default: return sprintf("%s's", val);
	}
    }

    string possessive(mixed val) {
	switch(objectp(val) ? (string)val->GetGender() : (string)val) {
	case "male": return "his";
	case "female": return "her";
	case "neutral": return "hir";
	default: return "its";
	}
    }

    string strip_article(mixed val) {
	int x;

	if( objectp(val) ) val = (string)val->GetShort();
	x = strlen(val);
	if( x <= 2 ) return val;
	if( val[0..1] == "a " || val[0..1] == "A " ) return val[2..];
	if( x <= 3 ) return val;
	if( val[0..2] == "an " || val[0..2] == "An " ) return val[3..];
	if( x <= 4 ) return val;
	if( val[0..3] == "the " || val[0..3] == "The " ) return val[4..];
	return val;
    }

    string nominative(mixed val) {
	switch(objectp(val) ? (string)val->GetGender() : (string)val) {
	case "male": return "he";
	case "female": return "she";
	case "neutral": return "sie";
	default: return "it";
	}
    }

    string objective(mixed val) {
	switch(objectp(val) ? (string)val->GetGender() : (string)val) {
	case "male": return "him";
	case "female": return "her";
	case "neutral": return "hir";
	default: return "it";
	}
    }

    string reflexive(mixed val) { return sprintf("%sself", objective(val)); }
    /*
#define VOWELS ({"a","e","i","o","u"})

#define ABNORMAL ([ "moose":"moose", "mouse":"mice", "die":"dice", "index":"indices", "human":"humans", "sheep":"sheep", "fish":"fish", "child":"children", "ox":"oxen", "tooth":"teeth", "deer":"deer", "bus":"busses" ])

    string pluralize(mixed single) {
	int x, i, y, ind;
	string str, tmp, tmp1;
	string *words;

	if(objectp(single)) {
	    if(str = (string)single->query_plural_name()) return str;
	    else str = (string)single->GetKeyName();
	}
	else if(stringp(single)) str = (string)single;
	else error("Bad argument 1 to pluralize()");
	if(!str) return str;
	i = sizeof(words = explode(str, " "));
	 if( i > 1 && words[i-1][0] == '(' && words[i-1][1<] == ')' )
	    return pluralize( implode(words[1..(i-2)]), " " );
	if(words[0] == "a" || words[0] == "an" || words[0] == "the")
	  i = sizeof(words = words[1..(i-1)]);
	if((y=member_array("of", words)) > 0 || (y=member_array("Of",words))>0)
	    str = words[ind = y-1];
	else str = words[ind = i-1];
	x = strlen(str);
	if(ABNORMAL[str]) return ABNORMAL[str];
	if(x > 2 && str[x-3..x-1] == "man") {
	    words[ind] = str[0..x-3]+"en";
	    return implode(words, " ");
	  }
	if(x > 1) {
	    tmp = str[x-2..x-1];
	    switch(tmp) {
		case "ch": case "sh":
		  words[ind] = sprintf("%ses", str);
		  return implode(words, " ");
		case "ff": case "fe":
		  words[ind] = sprintf("%sves", str[0..x-3]);
		  return implode(words, " ");
		case "us":
		  words[ind] = sprintf("%si", str[0..x-3]);
		  return implode(words, " ");
		case "um":
		  words[ind] = sprintf("%sa", str[0..x-3]);
		  return implode(words, " ");
		case "ef":
		  words[ind] = sprintf("%ss", str);
		  return implode(words, " ");
	    }
	}
	tmp = str[x-1..x-1];
	switch(tmp) {
	    case "o": case "x": case "s":
	      words[ind] = sprintf("%ses", str);
	      return implode(words, " ");
	    case "f":
	      words[ind] = sprintf("%sves", str[0..x-2]);
	      return implode(words, " ");
	    case "y":
		if(member_array(str[x-2..x-2],VOWELS)!=-1)
				   words[ind] = sprintf("%ss",str);
		else
		words[ind] = sprintf("%sies", str[0..x-2]);
		return implode(words, " ");
	}
	words[ind] = sprintf("%ss", str);
	return implode(words, " ");
    }
    */
    string cardinal(int x) {
	string tmp;
	int a;

	if(!x) return "zero";
	if(x < 0) {
	    tmp = "negative ";
	    x = absolute_value(x);
	}
	else tmp = "";
	switch(x) {
	case 1: return tmp+"one";
	case 2: return tmp+"two";
	case 3: return tmp+"three";
	case 4: return tmp+"four";
	case 5: return tmp+"five";
	case 6: return tmp+"six";
	case 7: return tmp+"seven";
	case 8: return tmp+"eight";
	case 9: return tmp+"nine";
	case 10: return tmp+"ten";
	case 11: return tmp+"eleven";
	case 12: return tmp+"twelve";
	case 13: return tmp+"thirteen";
	case 14: return tmp+"fourteen";
	case 15: return tmp+"fifteen";
	case 16: return tmp+"sixteen";
	case 17: return tmp+"seventeen";
	case 18: return tmp+"eighteen";
	case 19: return tmp+"nineteen";
	case 20: return tmp+"twenty";
	default:
	    if(x > 1000000000) return "over a billion";
	    else if(a = x /1000000) {
		if(x = x %1000000) 
		    return sprintf("%s million %s", cardinal(a), cardinal(x));
		else return sprintf("%s million", cardinal(a));
	    }
	    else if(a = x / 1000) {
		if(x = x % 1000) 
		    return sprintf("%s thousand %s", cardinal(a), cardinal(x));
		else return sprintf("%s thousand", cardinal(a));
	    }
	    else if(a = x / 100) {
		if(x = x % 100) 
		    return sprintf("%s hundred %s", cardinal(a), cardinal(x));
		else return sprintf("%s hundred", cardinal(a));
	    }
	    else {
		a = x / 10;
		if(x = x % 10) tmp = "-"+cardinal(x);
		else tmp = "";
		switch(a) {
		case 2: return "twenty"+tmp;
		case 3: return "thirty"+tmp;
		case 4: return "forty"+tmp;
		case 5: return "fifty"+tmp;
		case 6: return "sixty"+tmp;
		case 7: return "seventy"+tmp;
		case 8: return "eighty"+tmp;
		case 9: return "ninety"+tmp;
		default: return "error";
		}
	    }
	}
    }

    varargs string conjunction(mixed expressions, string coordinator) {
	int size;
	string tmp;

	if(!expressions) error("Bad argument 1 to conjunction().\n");
	else if(stringp(expressions)) expressions = ({ expressions });
	else if(!pointerp(expressions))
	    error("Bad argument 1 to conjunction().\n");

	size = sizeof(expressions);
	if(size < 2) return expressions[0];

	// Form the conjunction.
	if(!coordinator) coordinator = "and";
	tmp = "";
	for(int i = 0; i < size; i++) {
	    tmp += expressions[i];
	    if(i < size - 2) tmp += ", ";
	    else return tmp + ", " + coordinator + " " + expressions[size - 1];
	}
    }

    string consolidate(int x, string str) {
	string array words;
	string tmp;

	if( x == 1 || !sizeof(str) ) return str;
	words = explode(str, " ");
	if( sscanf(words[<1], "(%s)", tmp) ) {
	    if( sizeof(words) == 1 ) 
		return "(" + consolidate(x, tmp) + ")";
	    else return consolidate(x, implode(words[0..<2], " ")) + 
		" (" + tmp + ")";
	}
	if( sscanf(words[<1], "[%s]", tmp) ) {
	    if( sizeof(words) == 1 )
		return "[" + consolidate(x, tmp) + "]";
	    else return consolidate(x, implode(words[0..<2], " ")) +
		" [" + tmp + "]";
	}
	if( words[0][0..1] == "%^" ) {
	    string array parts;
	    string part, colour = "";
	    int i = 0;

	    parts = explode(words[0], "%^");
	    if( sizeof(parts) == 1 ) {
		if( sizeof(words) == 1 ) return words[0];
		else return words[0] + consolidate(x, implode(words[1..], " "));
	    }

	    foreach(part in parts) {
		if( sizeof(part) && !sizeof(strip_colours("%^" + part + "%^")) )
		    colour += ("%^" + part + "%^"); 
		else return colour + consolidate(x, 
		      (implode(parts[i..], "%^")) + " " + 
		      (implode(words[1..], " ")) );
		i++;
	    }
	    return words[0] + " " + consolidate(x, implode(words[1..], " "));

	}
	if( member_array(lower_case(strip_colours(words[0])), 
	    ({"a", "an", "the", "one"}) ) > -1 ) words = words[1..];
	return (cardinal(x) + " " + pluralize(implode(words, " ")));
    }
