/* Do not remove the headers from this file! see /USAGE for more info. */

/*
** This beast manages function dispatch for shell-specific functions.
** This is a bloody quick hack to get something working.
** It should probably use classes, and definitly should do 
** simple checking on number of args.
** Created.  John Viega(rust@Virginia.EDU).     July 2, 1995
*/


nosave mapping dispatch = ([]);
private nosave mapping personal_bindings = ([]);
private nosave string* modules = ({});
private nosave mapping module_objects = ([]);
private nosave mapping module_func_names = ([]);

protected void call_user_func(string, mixed);


//:FUNCTION setup_for_save
//Sets up M_SAVE to save some variables
void setup_for_save()
{
    /*
    ** Use the call_other() interface so that we are not statically
    ** bound to require M_SAVE.  This object this modules is applied
    ** to may save natively rather than via M_SAVE.
    ** Hmm, I don't think saving personal_bindings here is going to do
    ** any good... =)
    */
    this_object()->add_save(({ "personal_bindings", "modules" }));
}

protected void
shell_bind(string command, function f)
{
  dispatch[command] = f;
}

protected void
shell_bind_if_undefined(string command, function f)
{
    if ( !dispatch[command] )
	dispatch[command] = f;
}

protected void
shell_unbind(string command)
{
  map_delete(dispatch, command);
}

protected int
bind(string command, string *argv)
{
  string fname;

  if(sizeof(argv) != 1)
    return -1;
  fname = argv[0];
  if(undefinedp(personal_bindings[command]) && dispatch[command])
    return -2;
  
  personal_bindings[command] = fname;
  dispatch[command] = (:call_user_func, command :);
  this_object()->save();
}

protected void
unbind(string* argv)
{
  string command;

  if(sizeof(argv) != 1)
    return;
  command = argv[0];
  if(undefinedp(personal_bindings[command]))
    return;

  map_delete(personal_bindings, command);
  map_delete(dispatch, command);
  this_object()->save();
}


protected void 
call_user_func(string fname, mixed argv)
{
  string module;

  foreach(module in modules)
    {
      if(member_array(fname, module_func_names[module]) != -1)
	{
	  call_other(module_objects[module],fname,argv);
	  return;
	}
    }
}

protected int
load_module(mixed argv)
{
  string* flist;
  mapping finfo = ([]);
  mixed item;
  object  module_ob;
  string* funcnames = ({});

  if(!(stringp(argv) || (arrayp(argv) && sizeof(argv) == 1 && 
			 stringp(argv=argv[0]))))
    return 0;
  
  if(!module_ob = load_object(argv))
    return 0;

  module_objects[argv] = module_ob;
  
  flist = functions(module_ob,1);

  foreach(item in flist)
    {
      if(strsrch(item[2],"protected") != -1 || strsrch(item[2],"private") != -1)
	continue;
      finfo[item[0]];
      funcnames += ({item[0]});
    }
  module_func_names[argv] = funcnames;
  return 1;
}
     

protected void
set_module_path(string* mpath)
{
  modules = mpath;
  map(modules, (: load_module :));
}

