#include <lib.h>
#include <modules.h>

private string globalstr, globalstr2, globaltmp;
private string globalroom, globalfile;

varargs int eventCreateExit(string dir, string room, string file, int remote);
varargs int eventCreateEnter(string dir, string room, string file, int remote);
int eventRemoveExit(string dir, string filename);
varargs mixed eventProcessExits(string filename, string dir, string location);
varargs mixed eventProcessEnters(string filename, string dir, string location, object room);
string eventCopyRoom(string source, string dest);

string *cardinal_dirs = ( ({"none", "north","south","east","west", "northeast","northwest","southeast","southwest","up","down", "out"}) );

mixed make(string str) {
    int enter;
    int blank = 0;
    string *exits;
    string *enters;
    string foo, current_dir, current_room, this_room, new_room, room_dir;
    string tmp_path, new_file, arg1, arg2, s1, s2;
    object room;
    globalstr = globalstr2 = globaltmp = "";

    if(!str || str == "") {
	write("You'll need to be more specific. Try 'help create'");
	return 1;
    }

    if(environment(this_player())->GetDirectionMap()){
	write("This is a virtual room. It cannot be modified with the QCS.");
	return 1;
    }

    if(sscanf(str," %s %s", s1, s2) == 2){
	arg1 = s1;
	arg2 = s2;
	if(sizeof(opposite_dir(arg1))) enter = 0;
	else enter = 1;
    }
    else {
	write("Usage: create room <direction> <file>");
	return 1;
    }

    if(arg1 == "none") blank = 1;

    foo = ""+time();
    room = environment(this_player());
    current_dir = this_player()->query_cwd();
    current_room = base_name(room);
    if(!blank) room_dir = path_prefix(current_room);
    else room_dir = current_dir;

    if(file_exists(current_room+".c") && !check_privs(this_player(),current_room+".c")){
	write("You do not appear to have access to this room file. Modification aborted.");
	return 1;
    }

    if(!write_file(room_dir+"/"+foo+".foo","",1)) {
	write("You do not have write privileges to this area.");
	return 1;
    }

    rm(room_dir+"/"+foo+".foo");
    write("It appears you have write access to this area.");
    this_room = read_file(current_room+".c");
    new_room = read_file("/obj/room.c");

    if(!blank){

	if(environment(this_player())->GetNoModify() ){
	    write("This should be edited by hand. Change cancelled.");
	    return 1;
	}

	exits = room->GetExits();
	enters = room->GetEnters();

	if(member_array(arg1,exits) != -1){
	    write("This room already has an exit in that direction.");
	    return 1;
	}

	if(member_array(arg1,enters) != -1){
	    write("This room already has an enter by that name.");
	    return 1;
	}
    }

    if(strsrch(arg2,".c") == -1) arg2 += ".c";
    if(strsrch(arg2," ") != -1) arg2 = replace_string(arg2," ","_");

    if(file_exists(arg2)) new_file = arg2;
    else if(strsrch(arg2,"./") != -1) {
	arg2 = replace_string(arg2,"./","");
	new_file = absolute_path((string)this_player()->query_cwd(), arg2);
    }
    else if(directory_exists(path_prefix(arg2))){
	new_file  = arg2;
    }
    else if(grepp(arg2,"/")){
	new_file = room_dir +"/"+ last_string_element(arg2,"/");
    }

    else {
	new_file = room_dir +"/"+ arg2;
    }

    if(!check_privs(this_player(),new_file)){
	write("Invalid directory.");
	return 1;
    }

    if(new_file[0..7] == "/realms/" && strsrch(new_file,"/area/room/") != -1){
	if(!file_exists(new_file)) cp("/obj/area_room.c",new_file);
    }
    else {
	if(!file_exists(new_file)) cp("/obj/room.c",new_file);
    }

    if(blank){
	reload(new_file);
	this_player()->eventMoveLiving(new_file);
	return 1;
    }

    if(enter == 0) eventCreateExit(arg1, current_room+".c", new_file);
    else eventCreateEnter(arg1, current_room+".c", new_file);
    if(file_exists(new_file) &&
      grepp(read_file(new_file),"SetShort(\"a blank room\");") ) {
	eventCopyRoom(current_room+".c", new_file);
	reload(new_file);
    }
    return 1;
}

varargs int eventCreateExit(string dir, string room, string file, int remote){
    string param;
    string *file_arr;

    if(file_exists(room) && !check_privs(this_player(),room)){
	write("You do not appear to have access to this room file. Modification aborted.");
	return 1;
    }

    if(member_array(dir,cardinal_dirs) == -1) {
	this_object()->eventCreateEnter(dir, room, file, remote);
	return 1;
    }

    globalstr = room;
    unguarded( (: globaltmp = read_file(globalstr) :) );
    file_arr = explode(globaltmp,"\n");

    if(remote && member_array(dir,load_object(room)->GetExits()) != -1) return 0;

    if(strsrch(globaltmp,"SetExits") != -1) param = "SetExits";
    else if(strsrch(globaltmp,"AddExit") != -1) param = "AddExit";
    else if(strsrch(globaltmp,"SetLong") != -1) param = "SetLong";
    else {
    }
    globaltmp = remove_matching_line(globaltmp,"SetObviousExits",1);
    globaltmp = remove_matching_line(globaltmp,"//extras",1);
    unguarded( (: write_file(globalstr,globaltmp,1) :) );
    reload(room);
    eventProcessExits(room, dir, file);

    if(!remote) {
	eventCreateExit(opposite_dir(dir), file, room, 1 );
	write("You begin uttering a magical incantation.");
	say(this_player()->GetCapName()+" begins uttering a magical incantation.");
	this_object()->eventGeneralStuff(room);
    }
    this_object()->eventAddInit(room);
    if(remote){
	this_object()->eventGeneralStuff(room);
	write("You wave your hand, and a new exit appears.");
	say(this_player()->GetCapName()+" waves "+possessive(this_player())+" hand and a new exit appears.");
    }
    return 1;
}

int eventRemoveExit(string dir, string filename){
    string contents, search_str, map_str, key, val, new_file, tmpfile;
    string *file_arr;
    mapping PointlessMap;
    mapping ExitsMap = load_object(filename)->GetExitMap();

    if(file_exists(filename) && !check_privs(this_player(),filename)){
	write("You do not appear to have access to this room's file. Modification aborted.");
	return 1;
    }

    tmpfile = generate_tmp(load_object(filename));
    globalstr = filename;
    globaltmp = tmpfile;
    unguarded( (: globalstr2 = read_file(globalstr) :) );
    contents = globalstr2;
    PointlessMap = ([]);

    PointlessMap = load_object(filename)->GetFullExitData();

    if( member_array(dir,load_object(filename)->GetExits()) != -1 
      && !functionp(PointlessMap[dir]["pre"]) 
      && !functionp(PointlessMap[dir]["post"]) ) {
	this_object()->eventReadMapping(filename,({"SetExits"}), 1);
	map_delete(ExitsMap,dir);
	map_str = "SetExits( ([ \n";
	foreach( key, val in ExitsMap){
	    if(!functionp(PointlessMap[key]["pre"]) 
	      && !functionp(PointlessMap[key]["post"])) map_str += "\""+key+"\" : \""+val+"\",\n";
	}
	map_str += "]) );";

	unguarded( (: globalstr2 = read_file(globalstr) :) );
	contents = globalstr2;

	new_file = remove_matching_line(contents, "SetExits", 1); 
	new_file = this_object()->eventAppend(new_file,({"SetItems","SetLong","SetDayLong","SetNightLong"}),"\n"+map_str+"\n");
	new_file = remove_matching_line(new_file,"SetObviousExits");
	new_file = remove_matching_line(new_file,"//extras");
	new_file = remove_matching_line(new_file,"AddExit(", 1, ":)");
	globalstr2 = new_file;
	unguarded( (: write_file(globaltmp,globalstr2,1) :) );
	this_object()->eventGeneralStuff(tmpfile);
	globalstr = tmpfile;
	globalstr2 = filename;
	unguarded( (: cp(globalstr, globalstr2) :) );
	reload(filename);
	rm(tmpfile);
	write("With a puff of smoke, an exit vanishes!");
	return 1;
    }


    if(member_array(dir,load_object(filename)->GetExits()) != -1){
	globalstr = filename;
	new_file = read_file(filename);
	file_arr = explode(read_file(filename),"\n");
	foreach(string linea in file_arr){
	    if(strsrch(linea,"AddExit") != -1 && strsrch(linea,dir) != -1) {
		search_str = linea;
	    }
	}
	globalstr = tmpfile;
	globalstr2 = filename;
	globaltmp = remove_matching_line(new_file, search_str);
	unguarded( (: write_file(globalstr,globaltmp,1) :) );
	unguarded( (: cp(globalstr, globalstr2) :) );
	eventProcessExits(filename);
	reload(filename);
	rm(tmpfile);
	write("With a puff of smoke, an exit vanishes!");
	return 1;
    }

    write("This room's SetExits does not contain that direction.");
    return 1;
}

varargs mixed eventProcessExits(string filename, string dir, string location){
    string map_str, key, val, new_file;
    mapping PointlessMap;

    mapping ExitsMap = load_object(filename)->GetExitMap();

    if(file_exists(filename) && !check_privs(this_player(),filename)){
	write("You do not appear to have access to this file. Modification aborted.");
	return 1;
    }

    PointlessMap =  load_object(filename)->GetFullExitData();
    map_str = "SetExits( ([\n";

    this_object()->eventReadMapping(filename,({"SetExits"}), 1);
    new_file = remove_matching_line(read_file(filename),"SetObviousExits");
    new_file = remove_matching_line(new_file,"//extras");
    new_file = remove_matching_line(new_file, "AddExit(", 1, ":)");

    foreach( key, val in ExitsMap){
	if(!functionp(PointlessMap[key]["pre"]) &&
	  !functionp(PointlessMap[key]["post"])) map_str += "\""+key+"\" : \""+val+"\",\n";
    }
    if(dir && location && member_array(dir,load_object(filename)->GetExits()) == -1){
	map_str += "\""+dir+"\" : \""+location+"\",\n";
    }
    map_str += "]) );";

    globalstr = filename; 
    globaltmp = generate_tmp();

    globalstr2 = this_object()->eventAppend(new_file,({"SetItems","SetLong","SetDayLong","SetNightLong","SetShort","create()","create"}),"\n"+map_str+"\n");
    unguarded( (: write_file(globaltmp,globalstr2,1) :) );
    unguarded( (: cp(globaltmp,globalstr) :) );
    reload(filename);
    rm(globaltmp);
    return 1;
}

string eventCopyRoom(string source, string dest){
    string homedir, areadir, tmpsource, map_str, new_file;
    mapping DestExits;

    if(file_exists(source) && (!check_privs(this_player(),source) &&
	strsrch(source,"/obj/"))){
	write("You do not appear to have access to this file. Modification aborted.");
	return "";
    }

    if(file_exists(dest) && !check_privs(this_player(),dest)){
	write("You do not appear to have access to that file. Modification aborted.");
	return "";
    }

    tmpsource = generate_tmp(source);
    globalstr2 = source;
    globalstr = tmpsource;
    unguarded( (: cp(globalstr2, globalstr) :) );
    globalstr2 = dest;
    if(!file_exists(source)) return "Source read has failed.";
    if(!file_exists(tmpsource)) return "Read failed.";
    if(!file_exists(dest)) return "Destination read failed.";
    homedir = "/realms/"+this_player()->GetKeyName();
    areadir = homedir+"/area";

    unguarded( (: this_object()->eventReadMapping(globalstr,({"SetExits"}),1) :) ); 
    unguarded( (: this_object()->eventReadMapping(globalstr2,({"SetExits"}),1) :) ); 
    DestExits = load_object(dest)->GetExitMap();

    unguarded( (: globaltmp = read_file(globalstr) :) ); 

    map_str = "SetExits("+this_object()->eventStringifyMap(DestExits)+");\n";
    new_file = this_object()->eventAppend(globaltmp,({"SetItems","SetLong","SetDayLong"}),"\n"+map_str+"\n");
    new_file = replace_line(new_file,({"SetShort(",");"}),"SetShort(\"copy of "+last_string_element(source,"/")+"\");");
    replace_string(new_file,"\n\n\n","\n\n");
    new_file = remove_matching_line(new_file, "SetDoor", 1);

    if(query_verb() == "copy" && grepp(new_file, "customdefs\.h")){
	string *tmparr = explode(new_file,"\n");
	string *tmparr2 = explode(read_file(dest),"\n");
	string bad_def = "";
	string good_def = "";
	foreach(string element in tmparr2){
	    if(!strsrch(element,"#include")){
		if(grepp(element,"customdefs.h")){
		    good_def = element;
		}
	    }
	}
	tmparr2 = ({});
	foreach(string element in tmparr){
	    if(!strsrch(element,"#include")){
		if(grepp(element,"customdefs.h")) element = good_def;
	    }
	    tmparr2 += ({ element });
	}
	new_file = implode(tmparr2,"\n");
    }

    write_file(tmpsource,new_file,1);

    globalstr = tmpsource;
    globalstr2 = dest;

    if(!unguarded( (: cp(globalstr, globalstr2) :) )){
	return "Write failed.";
    }

    this_object()->eventAddInit(dest);
    this_object()->eventGeneralStuff(dest);
    rm(tmpsource);
    return "Room data copy complete.";
}

varargs int eventCreateEnter(string dir, string room, string file, int remote){

    if(file_exists(room) && !check_privs(this_player(),room)){
	write("You do not appear to have access to this room file. Modification aborted.");
	return 1;
    }

    if(!present(dir,environment(this_player()))){ 
	write("This room needs a corresponding SetItem to make a SetEnter ");
	write("of "+dir);
	return 1;
    }

    globalroom = room;
    globalfile = file;
    globaltmp = "";

    if(remote) unguarded( (: globaltmp = read_file(globalroom) :) );
    else unguarded( (: globaltmp = read_file(globalfile) :) );

    if(remote && member_array("out",load_object(room)->GetExits()) != -1) return 0;

    globaltmp = remove_matching_line(globaltmp,"SetEnters",1);
    globaltmp = remove_matching_line(globaltmp,"//extras",1);
    unguarded( (: write_file(globalfile,globaltmp,1) :) );

    if(!remote) {
	eventProcessEnters(room, dir, file);
	this_object()->eventCreateExit("out", file, room, 1 );
	say(this_player()->GetCapName()+" waves "+possessive(this_player())+" hand and a new enter appears.");
	this_object()->eventGeneralStuff(room);
    }
    this_object()->eventAddInit(room);
    if(remote){
	this_object()->eventGeneralStuff(room);
	write("You begin uttering a magical incantation.");
	write("You wave your hand, and a new enter appears.");
	say(this_player()->GetCapName()+" begins uttering a magical incantation.");

    }
    reload(room);
    reload(file);
    room = "";
    file = "";
    globalroom = "";
    globalfile = "";
    globaltmp ="";
    return 1;
}

int eventRemoveEnter(string dir, string filename){
    string contents, search_str, map_str, new_file, tmpfile;
    mixed *key;
    mixed val;
    string *file_arr;
    mixed *key_arr;
    mapping PointlessMap;
    mapping EntersMap = load_object(filename)->GetEnterMap();

    if(file_exists(filename) && !check_privs(this_player(),filename)){
	write("You do not appear to have access to this room's file. Modification aborted.");
	return 1;
    }

    tmpfile = generate_tmp(load_object(filename));
    globalstr = filename;
    globaltmp = tmpfile;
    unguarded( (: globalstr2 = read_file(globalstr) :) );
    contents = globalstr2;
    PointlessMap = ([]);

    PointlessMap = load_object(filename)->GetEnterMap();

    if( member_array(dir,load_object(filename)->GetEnters()) != -1) { 
	this_object()->eventReadMapping(filename,({"SetEnters"}), 1);
	foreach(key,val in EntersMap){
	    if(arrayp(key) && member_array(dir,key) != -1) 
		key_arr = key;
	    true(); 
	}
	map_delete(EntersMap,key_arr);
	map_str = "SetEnters( ([ \n";
	foreach( key, val in EntersMap){
	    map_str += "\""+key[0]+"\" : \""+val+"\",\n";
	}
	map_str += "]) );";

	unguarded( (: globalstr2 = read_file(globalstr) :) );
	contents = globalstr2;

	new_file = remove_matching_line(contents, "SetEnters", 1); 
	new_file = this_object()->eventAppend(new_file,({"AddItem","SetItems"}),"\n"+map_str+"\n");
	new_file = remove_matching_line(new_file,"SetObviousEnters");
	new_file = remove_matching_line(new_file,"//extras");
	new_file = remove_matching_line(new_file,"AddEnter(", 1);
	globalstr2 = new_file;
	unguarded( (: write_file(globaltmp,globalstr2,1) :) );
	this_object()->eventGeneralStuff(tmpfile);
	globalstr = tmpfile;
	globalstr2 = filename;
	unguarded( (: cp(globalstr, globalstr2) :) );
	rm(tmpfile);
	reload(filename);
	write("With a puff of smoke, an enter vanishes!");
	return 1;
    }


    if(member_array(dir,load_object(filename)->GetEnters()) != -1){
	globalstr = filename;
	new_file = read_file(filename);
	file_arr = explode(read_file(filename),"\n");
	foreach(string linea in file_arr){
	    if(strsrch(linea,"AddEnter") != -1 && strsrch(linea,dir) != -1) {
		search_str = linea;
	    }
	}
	globalstr = tmpfile;
	globalstr2 = filename;
	globaltmp = remove_matching_line(new_file, search_str);
	unguarded( (: write_file(globalstr,globaltmp,1) :) );
	unguarded( (: cp(globalstr, globalstr2) :) );
	eventProcessEnters(filename);
	reload(filename);
	rm(tmpfile);
	write("With a puff of smoke, an enter vanishes!");
	return 1;
    }

    write("This room's SetEnters does not contain that direction.");
    return 1;
}

varargs mixed eventProcessEnters(string filename, string dir, string location, object room) {
    string map_str, key, val, new_file;
    string *id_array;
    object *dummies;
    mapping PointlessMap;

    mapping EntersMap = load_object(filename)->GetEnterMap();
    id_array = ({});
    dummies = load_object(filename)->GetDummyItems();
    if(sizeof(dummies)) foreach(object dumdum in dummies){
	id_array += dumdum->GetId();
    }

    if(file_exists(filename) && !check_privs(this_player(),filename)){
	write("You do not appear to have access to this file. Modification aborted.");
	return 1;
    }

    PointlessMap =  load_object(filename)->GetEnterMap();
    map_str = "SetEnters( ([\n";
    globalstr = filename;

    unguarded( (: this_object()->eventReadMapping(globalstr,({"SetEnters"}), 1) :) );
    new_file = remove_matching_line(unguarded( (: read_file(globalstr) :) ),"SetObviousExits");
    new_file = remove_matching_line(new_file,"//extras");
    new_file = remove_matching_line(new_file, "AddEnter(", 1, ":)");

    foreach( key, val in EntersMap){
	map_str += "\""+key[0]+"\" : \""+val+"\",\n";
    }

    if(dir && location && member_array(dir,id_array) != -1){
	map_str += "\""+dir+"\" : \""+location+"\",\n";
    }
    map_str += "]) );";

    globalstr = filename; 
    globaltmp = generate_tmp(load_object(filename));

    globalstr2 = this_object()->eventAppend(new_file,({"AddItem","SetItems","SetExits","AddExit"}),"\n"+map_str+"\n");
    unguarded( (: write_file(globaltmp,globalstr2,1) :) );
    unguarded( (: cp(globaltmp,globalstr) :) );
    reload(filename);
    rm(globaltmp);
    return 1;
}
