/* MTF v1.0 Rywfol 990910 */
#include "mtfincl.h";
mixed *map;
mapping key_data;
class map_class {
  string filename;
  int counter;
  string inheritname;
  string basename;
  string short;
  string long;
  mapping exits;
}
class exit {
  string dest;
  int ypos;
  int xpos;
}
/*
 * Find how the rooms interconnect.
 * We look in a square around the item for + & - chars.
 * If we find one we've found an exit.
 */
mapping get_exits(int ypos, int xpos) {
  int x, y;
  class map_class data;
  mapping exits = ([ ]);
  
  if(!classp(map[ypos][xpos]))
    return ([ ]);
  // check the rooms either side of this one.
  for(y = -1; y < 2; y++) {
    if((y*2)+ypos < 0)
      continue;
    if((y*2)+ypos >= sizeof(map))
      continue;
    
    for(x = -1; x < 2; x++) {
      if((x*2)+xpos < 0)
        continue;
      if((x*2)+xpos >= sizeof(map[(y*2)+ypos]))
        continue;
      
      if(!x && !y)
        continue;
      if(classp(map[(y*2)+ypos][(x*2)+xpos])) {
        data = map[(y*2)+ypos][(x*2)+xpos];
        if((map[y+ypos][x+xpos] == '*') ||
           (map[y+ypos][x+xpos] == '+' && (y == 0 || x == 0)) ||
           (map[y+ypos][x+xpos] == 'x' && (y != 0 && x != 0)) ||
           (map[y+ypos][x+xpos] == '|' && y != 0 && x == 0) ||
           (map[y+ypos][x+xpos] == '-' && y == 0 && x != 0) ||
           (map[y+ypos][x+xpos] == '\\' && y == -1 && x == -1) ||
           (map[y+ypos][x+xpos] == '\\' && y == 1 && x == 1) ||
           (map[y+ypos][x+xpos] == '/' && y == 1 && x == -1) ||
           (map[y+ypos][x+xpos] == '/' && y == -1 && x == 1)) {
          exits[DIRECTIONS[y+1][x+1]] = new(class exit,
                                            dest : upper_case(data->basename)+
                                            " + \"" + data->filename + "\"",
                                            ypos : y+ypos,
                                            xpos : x+xpos);
        } else if(map[y+ypos][x+xpos] != ' ') {
          debug_printf("Unknown direction char: %O (%c), %d - %d, %d - %d %O %s",
                       map[y+ypos][x+xpos], map[y+ypos][x+xpos], x, xpos, y, ypos,
                       map[ypos][xpos],
                       data->basename);
        }
      }
    }
  }
  //  debug_printf("%0", exits);
  return exits;
}
#ifdef 0
/*
 *
 */
mixed *find_nearby(int ypos, int xpos, int distance, int direc) {
  string *dirs;
  int ny, nx;
  class exit tmp;
  if(distance > 4)
    return 0;
  
  if(!classp(map[ypos][xpos]))
    return 0;
  dirs = keys(map[ypos][xpos]->exits);
  if(direc >= sizeof(dirs))
    return 0;
  tmp = map[ypos][xpos]->exits;
  ny = tmp[]->ypos;
  nx = tmp[]->xpos;
  if(nx == xpos && ny == ypos) {
    if(direc == sizeof(dirs) -1)
      return 0;
    else
      direc++;
  }
  if(!find_nearby(ny, nx, ++distance);
  
}
#endif
     
/*
 * This is a lot like get_exits except that it goes further along the road.
 */
string calc_long(int ypos, int xpos) {
  int x, y, sameroad;
  class map_class data;
  string *exits = ({ });
  string *junctions = ({ });
  string long_str;
  mixed *nearby;
  
  if(!classp(map[ypos][xpos]))
    return "";
  /*
   * First we'll see how many exits we have that lead to this road.
   * 0 == end of the road
   * 1 == nothing special
   * 2 == fork
   */
  sameroad = 0;
  for(y = -1; y < 2; y++) {
    if((y*2)+ypos < 0)
      continue;
    if((y*2)+ypos >= sizeof(map))
      continue;
    
    for(x = -1; x < 2; x++) {
      if((x*2)+xpos < 0)
        continue;
      if((x*2)+xpos >= sizeof(map[(y*2)+ypos]))
        continue;
      
      if(!x && !y)
        continue;
      if(classp(map[(y*2)+ypos][(x*2)+xpos])) {
        data = map[(y*2)+ypos][(x*2)+xpos];
        
        // Do we have another room in this road?
        if(map[y+ypos][x+xpos] == '+' &&
           map[ypos][xpos]->basename ==
           map[(y*2)+ypos][(x*2)+xpos]->basename) {
          sameroad++;
          exits += ({ DIRECTIONS[y+1][x+1] });
        }
      }
    }
  }
  // check the rooms either side of this one to see if this is a junction.
  for(y = -1; y < 2; y++) {
    if((y*2)+ypos < 0)
      continue;
    if((y*2)+ypos >= sizeof(map))
      continue;
    
    for(x = -1; x < 2; x++) {
      if((x*2)+xpos < 0)
        continue;
      if((x*2)+xpos >= sizeof(map[(y*2)+ypos]))
        continue;
      
      if(!x && !y)
        continue;
      if(classp(map[(y*2)+ypos][(x*2)+xpos])) {
        data = map[(y*2)+ypos][(x*2)+xpos];
        
        // Do we have a junction?
        if(((map[y+ypos][x+xpos] == '*') ||
            (map[y+ypos][x+xpos] == '+' && (y == 0 || x == 0)) ||
            (map[y+ypos][x+xpos] == 'x' && (y != 0 && x != 0)) ||
            (map[y+ypos][x+xpos] == '|' && y != 0 && x == 0) ||
            (map[y+ypos][x+xpos] == '-' && y == 0 && x != 0) ||
            (map[y+ypos][x+xpos] == '\\' && y == -1 && x == -1) ||
            (map[y+ypos][x+xpos] == '\\' && y == 1 && x == 1) ||
            (map[y+ypos][x+xpos] == '/' && y == 1 && x == -1) ||
            (map[y+ypos][x+xpos] == '/' && y == -1 && x == 1)) && 
           map[ypos][xpos]->basename !=
           map[(y*2)+ypos][(x*2)+xpos]->basename) {
          if(member_array(map[(y*2)+ypos][(x*2)+xpos]->short, junctions) == -1)
            junctions += ({ map[(y*2)+ypos][(x*2)+xpos]->short });
        }
      }
    }
  }
#ifdef 0
  // Not a junction so lets start looking for junctions nearby.
  if(!sizeof(junctions)) {
    nearby = find_nearby(ypos, xpos);
  }
#endif
  
  /*
   * Build the long desc using priorities of things.
   */
  long_str = "This is ";
  if(sizeof(junctions)) {
    long_str += map[ypos][xpos]->short + " at the junction with " +
      query_multiple_short(junctions) +
      ".\n";
  } else if(sameroad == 0) {
    long_str += "the end of " + map[ypos][xpos]->short;
  } else if(sameroad == 1) {
    long_str += "a fork in " + map[ypos][xpos]->short +
      " where it splits heading " +
      query_multiple_short(exits);
  } else {
    long_str += map[ypos][xpos]->short;
  }
  
  //  debug_printf("%O", exits);
  return long_str;
}
/*
 * Write the file out.
 */
int write_this_file(string fdir, int ypos, int xpos) {
  class map_class room;
  string str, tmp, exit;
  mapping exits;
  int i;
  room = map[ypos][xpos];
  
  str = "#include \"path.h\";\n\n";
  str += "inherit " + room->inheritname + ";\n";
  str += "\n";
  str += "void setup() {\n";
  str += "  set_short(\"" + room->short + "\");\n";
  str += "  set_long(\"" + room->long + "\\n\");\n";
  str += "  set_light( 80 );\n";
  // Build the exits into the string
  exits = room->exits;
  foreach(exit in keys(exits)) {
    /*
     * A little wizardry.
     * ne,se,sw,nw are all odd numbered in the array.
     * so, if we have an odd numbered exit and the exits on either side of it
     * also exist then make it secret. This stops courtyards getting
     * overcrowded with exits.
     */
    i = member_array(exit, DIRECTIONS);
    if(i % 2 == 1 &&
       exits[DIRECTIONS[i-1]] &&
       exits[DIRECTIONS[(i+1) % sizeof(DIRECTIONS)]])
      str += sprintf("  add_exit(\"%s\", %s, \"secret\");\n",
                     exit, exits[exit]->dest);
    else
      str += sprintf("  add_exit(\"%s\", %s, \"road\");\n",
                     exit, exits[exit]->dest);
  }
  
  str += "}\n";
  
  // Create the directory if necessary and a path.h to go in it.
  if(file_size(fdir + "/" + room->basename) != -2) {
    mkdir(fdir + "/" + room->basename);
    tmp = "#include \"../path.h\"\n";
    tmp += "#undef PATH\n";
    tmp += "#define PATH __DIR__\n";
    write_file(fdir + "/" + room->basename + "/path.h", tmp, 1);
  }
  //  debug_printf("Str: %s", str);
  return write_file( fdir + "/" + room->basename + "/" + room->filename + ".c",
                     str, 1 );
}
/**
 * Read the map into a mixed array (be better if it was a class.
 */
mixed *read_map(string mapfile) {
  int i, j;
  mixed *temp_map;
  string *lines;
  
  lines = explode(read_file(mapfile), "\n");
  temp_map = allocate(sizeof(lines));
  for(i=0; i<sizeof(lines); i++) {
    temp_map[i] = allocate(strlen(lines[i]));
    for(j=0; j<strlen(lines[i]); j++) {
      if(key_data[lines[i][j]]) {
        // inc the room count.
        //        debug_printf("%c:%s", lines[i][j], key_data[lines[i][j]][2]);
        key_data[lines[i][j]][0] = to_int(key_data[lines[i][j]][0]) + 1;
        if(sizeof(key_data[lines[i][j]]) < 4)
          debug_printf("Key data too small: %O", key_data[lines[i][j]]);
        temp_map[i][j] = new(class map_class,
                             filename : key_data[lines[i][j]][2] +
                             key_data[lines[i][j]][0],
                             counter : key_data[lines[i][j]][0],
                             inheritname : key_data[lines[i][j]][1],
                             basename : key_data[lines[i][j]][2],
                             short : key_data[lines[i][j]][3]);
      } else
        temp_map[i][j] = lines[i][j];
    }
  }
  return temp_map;
}
/* Read the key file into a mapping.
 * The mapping is indexed by key character and contains
 * ({ counter, inheritname, filename, name })
 * counter is the start value for the counter (so we can start a street at some
 * value if we've already got rooms for it from another map).
 * inheritname is the name of the file to be inherited
 * filename is the base filename for the room eg. short
 * name is the name of the street eg. Short Street.
 */
mapping read_keys(string keyfile) {
  mapping key_data;
  string line, *lines;
  
  key_data = ([ ]);
  lines = explode(read_file(keyfile), "\n");
  foreach(line in lines) {
    key_data[line[0]] = explode(line[1..], "\t");
    //debug_printf("%c: %s", line[0], key_data[line[0]][2]);
  }
  return key_data;
}
/* Do the actual mapping */
int map_to_files( string mapfile, string fdir, string keyfile ) {
  int tot;
  string *file_tmp;
  string pstr;
  int x, y;
  
  if(!mapfile || mapfile == "")
    return NO_MAP_FILE;
  file_tmp = this_player()->get_files(mapfile);
  if(!file_tmp || sizeof(file_tmp) != 1 || file_size(file_tmp[0]) < 1)
    return NO_MAP_FILE;
  else
    mapfile = file_tmp[0];
  if(!fdir || fdir == "")
    file_tmp = ({ this_player()->query_path() });
  else
    file_tmp = this_player()->get_files(fdir);
  if(!file_tmp || sizeof(file_tmp) != 1 || file_size(file_tmp[0]) != -2)
    return NO_FILE_DIR;
  else
    fdir = file_tmp[0];
  
  if(!keyfile || keyfile == "" )
    keyfile = DEFAULT_KEYS;
  file_tmp = this_player()->get_files(keyfile);
  if(sizeof(file_tmp) != 1 || file_size(file_tmp[0]) < 1)
    return NO_KEY_FILE;
  else
    keyfile = file_tmp[0];
  key_data = read_keys(keyfile);
  map = read_map(mapfile);
  //  debug_printf("Map read %O", map);
  // go through the map line by line.
  for(y = 0; y < sizeof(map); y++)
    for(x = 0; x < sizeof(map[ y ]); x++)
      if(classp(map[y][x])) {
        map[y][x]->exits = get_exits(y, x);
      }
  reset_eval_cost();
  for(y = 0; y < sizeof(map); y++)
    for(x = 0; x < sizeof(map[ y ]); x++)
      if(classp(map[y][x]))
        map[y][x]->long = calc_long(y, x);
  reset_eval_cost();
  for(y = 0; y < sizeof(map); y++)
    for(x = 0; x < sizeof(map[ y ]); x++)
      if(classp(map[y][x]))
        tot += write_this_file(fdir, y, x);
  
  pstr = "/* Created at " + ctime( time() ) + " */\n";
  pstr += "#define CITYROOM \"/d/am/cityroom\"\n";
  pstr += "#undef CITY\n";
  pstr += "#define CITY \"" + fdir + "/\"\n";
  foreach(x in keys(key_data))
    pstr += "#define " + upper_case(key_data[x][2]) + " CITY + \"" + key_data[x][2] +
      "/\"\n";
  tot += write_file( fdir+ "/path.h", pstr, 1 );
  return tot;
}