#include <type.h>

static void create(varargs int clone) {
}


int char_is_whitespace(int char) {
  if((char == '\n') || (char == '\t')
     || char == ' ')
    return 1;

  return 0;
}


int char_to_lower (int char)
{
        if ((char <= 'Z' && char >= 'A'))
                char |= 0x20;

        return char;
}


int char_to_upper (int char)
{
        if ((char <= 'z' && char >= 'a'))
                char &= ~0x20;

        return char;
}


int is_whitespace(string str) {
  int len;
  int iter;

  len = strlen(str);
  for(iter = 0; iter < len; iter++) {
    if(!char_is_whitespace(str[iter]))
      return 0;
  }
  return 1;
}


int is_alpha(string str) {
  int ctr;

  return !!parse_string("regstring = /[a-zA-Z]+/\n"
			+ "notreg = /[^a-zA-Z]+/\n"
			+ "full : regstring", str);
}


int is_alphanum(string str) {
  int ctr;

  return !!parse_string("regstring = /[a-zA-Z0-9]+/\n"
			+ "notreg = /[^a-zA-Z0-9]+/\n"
			+ "full : regstring", str);
}


int is_ident(string str) {
  return !!parse_string("regstring = /[a-zA-Z\-_]+/\n"
			+ "notreg = /[^a-zA-Z\-_]+/\n"
			+ "full : regstring", str);
}


int string_has_char(int char, string str) {
  int len, iter;

  len = strlen(str);
  for(iter = 0; iter < len; iter++) {
    if(str[iter] == char)
      return 1;
  }
  return 0;
}


string trim_whitespace(string str) {
  int start, end;

  if(!str || str == "") return str;
  start = 0;
  end = strlen(str) - 1;
  while((start <= end) && char_is_whitespace(str[start]))
    start ++;
  while((start <= end) && char_is_whitespace(str[end]))
    end--;

  return str[start..end];
}


string to_lower(string text) {
  int ctr;
  int len;
  string newword;

  newword = text;
  len = strlen(newword);
  for(ctr=0; ctr<len; ctr++) {
    newword[ctr] = char_to_lower(newword[ctr]);
  }
  return newword;
}


string to_upper(string text) {
  int ctr;
  int len;
  string newword;

  newword = text;
  len = strlen(newword);
  for(ctr=0; ctr<len; ctr++) {
    newword[ctr] = char_to_upper(newword[ctr]);
  }
  return newword;
}


/* If s1 is later in alphabetical order, return 1.  If s2 is later,
   return -1.  If neither, return 0. */
int stricmp(string s1, string s2) {
  int tmp1, tmp2, len1, len2;
  int len, iter;

  len1 = strlen(s1);
  len2 = strlen(s2);
  len = len1 > len2 ? len2 : len1;

  for(iter = 0; iter < len; iter++) {
    tmp1 = s1[iter]; tmp2 = s2[iter];
    if(tmp1 <= 'Z' && tmp1 >= 'A')
      tmp1 += 'a' - 'A';
    if(tmp2 <= 'Z' && tmp2 >= 'A')
      tmp2 += 'a' - 'A';

    if(tmp1 > tmp2)
      return 1;
    if(tmp2 > tmp1)
      return -1;
  }

  if(len1 == len2) return 0;
  if(len1 > len2) return 1;
  return -1;
}


/* If s1 is later in alphabetical order, return 1.  If s2 is later,
   return -1.  If neither, return 0. */
int strcmp(string s1, string s2) {
  int len1, len2;
  int len, iter;

  len1 = strlen(s1);
  len2 = strlen(s2);
  len = len1 > len2 ? len2 : len1;

  for(iter = 0; iter < len; iter++) {
    if(s1[iter] > s2[iter])
      return 1;
    if(s2[iter] > s1[iter])
      return -1;
  }

  if(len1 == len2) return 0;
  if(len1 > len2) return 1;
  return -1;
}


string mixed_sprint(mixed data) {
  int    iter;
  string tmp;
  mixed* arr;

  switch(typeof(data)) {
  case T_NIL:
    return "nil";

  case T_STRING:
    return "\"" + data + "\"";

  case T_INT:
    return "" + data;

  case T_FLOAT:
    return "" + data;

  case T_ARRAY:
    if(data == nil) return "array/nil";
    if(sizeof(data) == 0) return "({ })";

    tmp = "({ ";
    for(iter = 0; iter < sizeof(data); iter++) {
      tmp += mixed_sprint(data[iter]);
      if(iter < sizeof(data) - 1) {
	tmp += ", ";
      }
    }
    return tmp + " })";

  case T_MAPPING:
    arr = map_indices(data);
    tmp = "([ ";
    for(iter = 0; iter < sizeof(arr); iter++) {
      tmp += arr[iter] + " => " + mixed_sprint(data[arr[iter]]) + ",";
    }
    return tmp + "])";

  case T_OBJECT:
    return "<Object (" + object_name(data) + ")>";

  default:
    error("Unrecognized DGD type in mixed_sprint");
  }
}

string tree_sprint(mixed data, int indent) {
  string strInd, tmp;
  int iter;

  strInd = "";

  for (iter = 0; iter < indent; ++iter) {
    strInd += " ";
  }
  
  switch (typeof(data)) {
  case T_ARRAY:
    if (data == nil) {
      return strInd + "array/nil";
    }
    if (sizeof(data) == 0) {
      return strInd + "({ })";
    }

    tmp = "";
    for(iter = 0; iter < sizeof(data); iter++) {
      tmp += tree_sprint(data[iter], indent+2);

      if(iter < sizeof(data) - 1) {
	tmp += ",\r\n";
      }
    }

    return strInd + "({ " + tmp[indent+2..] + " })";
  default:
    return strInd + mixed_sprint(data);
  }
}

string unq_escape(string str) {
  string ret;
  int    index;

  if(!str) return nil;

  ret = "";
  for(index = 0; index < strlen(str); index++) {
    switch(str[index]) {
    case '{':
    case '}':
    case '~':
    case '\\':
      ret += "\\" + str[index..index];
    default:
      ret += str[index..index];
      break;
    }
  }
  return ret;
}

int prefix_string(string prefix, string str) {
  if(strlen(str) < strlen(prefix))
    return 0;

  if(str[0..strlen(prefix)-1] == prefix) {
    return 1;
  }

  return 0;
}


/* This function takes a list of strings, sorts them alphabetically,
   and returns them.  Uninitialized (nil) strings aren't guaranteed
   to be preserved. */
string* alpha_sort_list(string* list) {
  int     ctr, new_offset, bottom_offset, len;
  string* new_list;

  if(sizeof(list) <= 1)
    return list;

  new_list = ({ });

  bottom_offset = 0;
  while(1) {
    new_offset = bottom_offset;
    while(bottom_offset < sizeof(list) && !list[new_offset]) {
      new_offset++;
      bottom_offset++;
    }

    if(bottom_offset == sizeof(list)) {
      /* Done. */
      return new_list;
    }

    for(ctr = 1; ctr < sizeof(list); ctr++) {
      if(list[ctr] && strcmp(list[ctr], list[new_offset]) < 0) {
	new_offset = ctr;
      }
    }

    if(!list[new_offset]) {
      /* Nothing but nil entries left, so we're done. */
      return new_list;
    }

    /* Okay, new_offset is now the minimum-sized entry */
    new_list += ({ list[new_offset] });
    list[new_offset] = nil;
  }

  /* We shouldn't actually get here */
  error("Internal error sorting strings!");
}


/********** Locale-specific Functions ************/

/* A specific check for English to see if the word "a" or the word "an"
   is a more appropriate article for the following string. */
int should_use_an(string str) {
  int ctr, letter;

  ctr = 0;
  while(strlen(str) > ctr) {
    letter = str[ctr];

    if(letter <= '9' && letter >= '0') {
      /* It's a leading digit.  Only the word for "eight" begins with a
	 vowel sound ("one" is pronouned as "wun"), so... */
      if(letter == '8') return 1;
      return 0;
    }

    if(letter >= 'a' && letter <= 'z') {
      letter += 'A' - 'a';
    }
    if(letter >= 'A' && letter <= 'Z') {
      if(letter == 'A' || letter == 'E' || letter == 'I' || letter == 'O'
	 || letter == 'U') {
	return 1;
      }
      /* For now, assume a leading H or Y acts as a consonant -- not always
	 true, alas */
      return 0;
    }

    /* Assume English-characters that aren't letters or numbers don't
       affect the a-versus-an thing.  Hard to tell if that's true.  But
       it means, for instance, that we'd say "an %ox", "an #$%@$ automobile",
       or "an ^evil^ mage".  Whatever. */
    ctr++;
  }
  return 0;
}
