Overall philosophy:

The dialog handler runs the forms package (and any other interaction
with the user?).  it monitors a blackboard area called "user_dialog",
carries out the commands it finds there and posts user actions back
to there.  It deals with generic actions, tell_user, user_said,
new_dialog (to open a new form/interaction program/etc), and converts
these into the form suitable for the interaction program (forms).
The concepts the dialog handler currently understands are:
	new_dialog (=load form),	tell_user (=set field),
	suggest_user (=default value),	offer_user (=set menu),
 	focus_user (=pop form),		unfocus_user,
	ask_user (=pop field), 		unask_user,
	new_query (=new box),		remind (=what value).
Its dead easy to add more - we could make it dynamic (load from file).

There are 2 knowledge bases, the user models kb "kb_um", the dialog
handlers / user conceptualization kb "kb_uc". The simplest is the
user model, so I'l describe it in detail, then give the relevent
detail about the other, finishing up with a template entry.

User model:

The user model module is just a process running nip with "kb_um".
"kb_um"	holds the predicates dealing with the user model.  It gets
a copy of everything the user does (from bb area user_dialog).
It can talk to the user (via user_dialog) and to the rest of the ife
by posting on a bb area "u_mdl".  On startup, it looks at the login
name, and selects a user type (modeller, engineer, architect) and user
level (expert, novice).  It handles the fields user_name, user_type
and user_level on the master form, no-one else should set them.
It posts user_name/type/level on u_mdl and ultimately could adapt them
on the fly.

On startup, it creates the bb area "u_mdl", asks to be notified of all
postings in bb area "user_dialog", gets the login name, sets this in
the  master form field user_name, posts this in u_mdl (kset flags it
as user_model_deduced, uset flags it as user_set), calls classif_user
(see below) to get user level/type and then loops processing messages
sent by the BB
NOTE:  My convention is that variables start with an _ AND a capital
    startup:-
	to_bb(mk_area, u_mdl),
	to_bb(notify_me, user_dialog, user_dialog),
	prompt(_,''),		/* no prompt needed for BB */
	get_login_name(_User_name),
 	to_bb(user_dialog, tell_user, user_name, _User_name),
	kset(user_name, _User_name),
	classif_user(_User_name),
	cmd_loop.
Cmd loop is complicated, by essentially reads messages of the form:
BB_area_of_message	command		arguments
and converts this to a call of the predicate named command with the
given arguments.  Eg DH posts "user_said   user_name   damian"
into BB area user_dialog - BB forwards this to UM ( as requested above)
as "user_dialog   user_said   user_name   damian" - UM ignores the 
"user_dialog" string and calls the predicate
"user_said(user_name,damian)."

At the moment, all we are interested in are the user_said messages,
so we create a number of user_said predicates.  Among these user_said
messages, all the UM is interested in are the "user_said   user_name",
"user_said   user_level" and "user_said   user_type".  So we create
a predicate of the form "user_said(user_name, _X)." - ie matches
a call with arg1 = user_name and anything as arg2.
"user_said(user_name,~" just notes the new name, posts to "u_mdl",
acknowledges to the user and tries to deduce user type/level.
	user_said(name, _User_name) :- 
		uset(user_name, _User_name),
	 	to_bb(user_dialog, tell_user, user_name, _User_name),
		classif_user(_User_name).
When the user hits the button "modeller", we turn off the three buttons
and set the user_type field (saves space on the form), then post on BB
	user_said(modeller,_) :- 
	 	to_bb(user_dialog, unask_user, modeller),
	 	to_bb(user_dialog, unask_user, engineer),
	 	to_bb(user_dialog, unask_user, architect),
	 	to_bb(user_dialog, tell_user, user_type, modeller),
		uset(user_type, modeller).
classif_user is given a user_name and looks at the predicates (in file
default) to see if it can guess the user type, level.  Note that there
is a catchall user_type predicate at the end in case we don't have a
specific one for this user (there are other ways of dealing with
unknown data).
	classif_user(_User_name) :- 
		user_type(_User_name, _User_type),
 		to_bb(user_dialog, tell_user, user_type, _User_type),
		kset(user_type, _User_type),
		user_level(_User_name, _User_level),
 		to_bb(user_dialog, tell_user, user_level, _User_level),
		kset(user_level, _User_level).
	user_level(damian, expert).	/* defaults */
	user_level(joe, novice).
	user_level(james, novice).
	user_level(_User, novice).	/* everyone else is a novice */



User_conceptualization:

This should be 2 kb, one knowing about the fields on the form, the
other knowing about the data structure being build.  however, I can't
separate them properly as they are too interrelated.  Anyway:
"kb_uc" has a startup sequence like kb_um.  It watches two BB areas,
u_mdl and user_dialog.  It has two commands it handles, u_mdl_set
and user_said.  The "u_mdl  u_mdl_set   user_type   ~" message could
be used to change the form_set (change to a different directory), while
the "u_mdl  u_mdl_set   user_level   ~" message is used to select what
feedback message to give at each user interaction (and possible select
different default?)

The utility predicates you will be interested in are:
1/
to post messages on the BB, the "to_bb(bbarea, concept, arg1, arg2)."
predicates (arg1 and arg2 are optional) are provided.  This posts
onto the BB area "bbarea", eg user_dialog.  The last arg can be a list
as for chat_user below.
2/
for general chat with the user, the "chat_user(text)" predicate is
provided.  "text" is a list of strings, each string being put on a
new line in the chat_area field on the master form.  Eg
	chat_user([
		'The first line of a message for the user',
		'It is placed in the chat_user area on the master',
		'form (this could be truned off by the user)',
		'4th and final line'
		  ]).
each list item can be a sublist instead of a simple string as above:
		['Location ', _Loc, ' is at ', _Lat, 'N ', _Lng, 'W']
allowing instantiated variables to be printed.
3/
To give feedback to the user, you supply a sepatate predicate for each
appropriate user level (you dont have to have both), eg
"feedback(location,expert)" and "feedback(location,novice)".  Usually
these contain a call to chat_user.  Then at the appropriate point you
call the feedback predicate "feedback(location)" and the appropriate
message is output to the chat_user area on the form.
4/
To post data to the user conceptualization BB area (the only to store
it), use "kset(concept, arg1, arg2)" or "uset(concept, arg1, arg2)",
depending whether the user set it or the kb deduced it.  uset values
will not be overwritten by kset ones. <<at the moment, the data is
actually stored in the kb itself, but this will change>>
5/
to recall data posted  to the user conceptualization BB area, use
"known(concept,_Value)" or "known(concept,_Value,_Who_set)".  The
2nd and 3rd arguments are variables which will be retuened bound to the
relevant data.
6/
to copare coordinates, use "near(x1,y1,x2,y2,dist)".  This succeeeds
iff point1 and point2 are closer than dist.

NOTE: read ( pred1, pred2 -> pred3, pred4 ; pred5, pred6 ) as
IF pred1 AND pred2 THEN pred3 AND pred4 ELSE pred5 AND pred6 ENDIF
where whole clause (...) fails iff one of pred3 <-> pred6 fails

Template:

Example 1:	building function box - simple
user_said(function, _Function) :-		/* tried 1st */
	known(function, _Function).		% already set to this?

user_said(function, _Function) :-		/* 'known' failed */
	check_function(_Function),		% valid function
	uset(function, _Function).		% yes, so accept it

user_said(function, _Function) :-		/* invalid function */
	feedback(bad_function).			% select 1 below 

check_function(_Function) :-			% fail if invalid
	function(_Function, _).	%is there any pred "function" among the
				% defaults with this string as arg?
				% (only need to update defaults file)

feedback(bad_function, novice) :-
	chat_user([
	    'Sorry, that category does not mean anything to me',
	    'I would suggest selecting a category that is on the menu',
	    'so that, rathter than asking you, I can select sensible',
	    'values for data required in specifying the analysis',
	    'methodology.'
		  ]). 

feedback(bad_function, expert) :-
	chat_user([
		'Dont know that category'
		  ]). 

Examply 2:	environment box, has consequences
user_said(environment, _Site_type) :-		% already set?
	known(environment, _Site_type).		% yes

user_said(environment, _Site_type) :-	% no, new site type
	uset(environment, _Site_type),	% any sitetype string ok
	exposure(_Site_type, _Exposure),	% have we an exposure 
	grnd_rflct(_Site_type, _Grnd_rflct),	%  or gr for this type
	kset(exposure, _Exposure),		% yes, kset them
	kset(grnd_rflct, _Grnd_rflct),
	feedback(environment_known).		% feedback iff novice

user_said(environment, _Site_type) :-	% unknown site type
	feedback(environment_unknown),	% feedback
	to_bb(user_dialog, ask_user, exposure, 1),	% ask user for
	to_bb(user_dialog, ask_user, grnd_rflct, 2.5).	%  exp and gr

feedback(environment_known,novice):-	% note no expert predicate
	chat_user([
		'Thank you ever so much'
		  ]).


feedback(environment_unknown, novice) :-
	chat_user([
	     'Sorry, I don''t know what that means!  Unless you know',
	     'what you are doing, I suggest youselect a standard site',
	     'type from the menu.   Otherwise, you MUST give me an',
	     'indication of site exposure (int:1-7) and a figure for',
	     'the ground reflectivity (real:0-10).  Put these in the',
	     'appropriate boxes on the form, (use the defaults given,',
	     'if necessary'
		  ]).

feedback(environment_unknown, expert) :-
	chat_user([
		'What does that mean? '
		  ]). 


Example 3	lat / long boxs - complicated, depends on location box

user_said(latitude, _Latitude) :-		/* already set */
	known(latitude, _Latitude).

user_said(latitude, _Latitude) :-		/* no */
	uset(latitude, _Latitude),
	to_bb(user_dialog, tell_user, latitude, _Latitude),
	( known(longitude, _Longitude, user_set) ->
		/* if user set longitude, we have a user_set position*/
		user_said(position, _Latitude, _Longitude)
	;
		true
	).
		
user_said(longitude, _Longitude) :-		/* as for latitude */
	uc_known(longitude, _Longitude).

user_said(longitude, _Longitude) :-
	uset(longitude, _Longitude),
	to_bb(user_dialog, tell_user, longitude, _Longitude),
	( known(latitude, _Latitude, user_set) ->
		user_said(position, _Latitude, _Longitude)
	;
		true
	).

user_said(position, _Latitude, _Longitude) :-	/* known position? */
	location_near(_Latitude, _Longitude, _Location),
				% yes, check if location set and if ok
	( \+check_location( _Location, _Latitude, _Longitude) ->
		kset(location, _Location)	% not set, so set it
	;
		true
	).

check_location( _Location, _Latitude, _Longitude) :-
	known(location, _Loc, user_set), 	% has user set loc?
	( position_of(_Loc, _Loc_Lat, _Loc_Long) -> % yes, where?
	     ( near(_Latitude, _Longitude, _Loc_Lat, _Loc_Long, 1.5) ->
		 true				      % pos ok
	     ;
		 feedback(loc_pos_clash),	      % loc pos clash 
				% set appropriate defaults for fields
		 to_bb(user_dialog, suggest_user, location, _Location),
		 to_bb(user_dialog, suggest_user, latitude, _Loc_Lat),
		 to_bb(user_dialog, suggest_user, longitude, _Loc_Long)
	     )
	;
		true		% don't know pos
	).

user_said(position, _Latitude, _Longitude) :- % unknown position
	known(location, _Location).		% but loc set, so ok

user_said(position, _Latitude, _Longitude) :- % unknown position & no
	feedback(position_unknown).		% loc set, ask user

feedback(position_known, novice) :-
	known(location, _Location),
	chat_user([
	    'From the position indicated, I am assuming you mean ',
	     [_Location,' but I will use your latitude & longitude.'], 
	    'If the assumed location is not acceptable, (and you want',
	    'to refer to this exact position again), give a name for',
	    'this location by selecting USER in the Location menu.',
	    'In that case, you might also want to set the environment',
	    'for the new location.',
	    'NOTE. The locations actual coordinates can be obtained',
	    'as the default in the Latitude/Longitude boxes'
		  ]).

feedback(position_known, expert) :-
	known(location, _Location, kb_set),
	chat_user([
		['I am assuming you mean location',_Location]
		  ]).

feedback(position_error, novice) :-
	known(location, _Location, kb_set),
	position_of(_Location, _Loc_Lat, _Loc_Long),
	known(latitude, _Lat),
	known(longitude, _Long),
	chat_user([
	    'ERROR! ',
	    [_Location, ' is at ', _Loc_Lat, 'N ', _Loc_Long, 'W.'],
	    ['whereas the position you gave is ',_Lat,'N ',_Long,'W.'],
	    'You should change the location field to something else,',
	    '(invent a name if you want) or modify the position.  I',
	    'have set the real position and location as defaults in',
	    'the latitude, longitude and location fields'
		  ]).

feedback(position_error, expert) :-
	chat_user([
		'ERROR! ',
		'thats not there!'
		  ]).

feedback(position_unknown, novice) :-
	chat_user([
	   'If you want to refer to this exact position again, give',
	   'a name for it by typing it in the Location field.',
	   'You will also need to set an environment for the location.'
		  ]).

feedback(position_unknown, expert) :-
	chat_user([
		'I could do with a name for this location'
		  ]).
Example 4:	interaction control
The flow of the user interaction is controlled/tracked by several
asserted facts which contain the current focus name.
When the user indiicated he/she wants to look at somethine else,
eg by hitting a button, the user_said predicate for that button
updates the asserted fact and switched the relevant forms off/on
user_said(f_geometry, on) :-
	( b_focus(_Focus) ->		% b_focus exists?
		to_bb(user_dialog, tell_user, _Focus, ' '), % yes, so
		to_bb(user_dialog, unfocus_user, _Focus),   % turn off
		abolish(b_focus, 1)		% form and remove fact
	;
		true
	),
	to_bb(user_dialog, focus_user, geometry),	% turn on form
	assert(b_focus(geomtry)),			% store fact
	feedback(geometry_sel).				% novice only

feedback(geometry_sel, novice) :-
	chat_user([
		'This button switches the focus of discussion to',
		'the geometric and material properties of this',
		'building.  Firstly, the geometry must be given.',
		'Several alternative input mechanisms are provided'
		  ]).


Example 5:	inferencing
All the above make only the necessary deductions from the input data.
As well as this, there are a number of other deductions that can be
made.  Eg. guessing the site type (rural/urban/city) from the location,
selecting a climate set from position, site_type and analysis_type.
These should be in a separate kb concerned solely in fleshing out the 
user conceptualization from data being posted.  However, this hasn't
been done yet, so the guess_~ predicated aren't called yet. SOON!
	guess_climate_set:-
1	   ( \+known(climate_set, _),	%if climate_set not set
2		known(position, _Latitude, _Longitude) :-	
3		( known(analysis_climate_requirment, _Climate_type),
				% must suit analysis requirements
4	    	  climate_type(_Climate_set, _Climate_type, _, _)
5	  	; true		%no particular requirements (yet)
6	  	),
7		climate_set(_Climate_set, _Lat, _Long),
8		near(_Latitude, _Longitude, _Lat, _Long, 1.5) ->
						% 100 miles
9			kset(climate_set, _Climate_set),
10			infer_from(climate_set, _Climate_set)  % chain
11	    ; true	% infer_from must NEVER fail!
12	    ).
note above, if 3 and/or 4 fail, _Climate set is not instantiated.
then 7 picks the 1st climate_set in the defaults file, and 8 checks
the position.  If 8 fails, it backtracks to 7 to continue with the 
next climate_set until it finds one, exec 9 & 10, or fails, backs up
to 1 and fails that and exec 11.  lines 3 to 7 are really to narrow
the backtracking search 7&8 for a climate file.  

File organization:

there are 3 directories under ife/src/KB, UM, DH, UC containing the
files making up the knowledge bases.  There are semi-standard files
initialize, interface, utilities and load_kb of little interest to you.
in DH there are files for each form, currently master, building and
geometry (partialy!) containing the user_said and related predicates.
There is also a defaults file (or files?) containing the facts used
by the forms.  This (these) are the only files that need to be touched
by end-users (once the ife is running).  Changes to the forms should
only require changes to the ?_form files or the addition of more.
Currently UC isn't ready, so DH has a file u_cpt which mimics it.
Each file can be tried in isolation using nip, or the complete kb can
be created by:
mack$ cd DH
mack$ cc -g -I.. utilities.c
mack$ nip -U100

Edinburgh Prolog, version 1.5.02 (1 December 1987)
AI Applications Institute, University of Edinburgh

| ?- [load_kb].
mack$ cd ..
The kb is now in kb_dh or whatever, and can be tried in total by
mack$ nip kb_dh

Edinburgh Prolog, version 1.5.02 (1 December 1987)
AI Applications Institute, University of Edinburgh

| ?- startup.

Messages, as sent by the blackboard can now be typed (there is a sample
script in KB/DH).

I forgot to tell you how to implement the help facility (and an error
handling facility, etc).  The forms package will output the request
for help which will be posted on the BB area "user_dialog".  The
posted message will be something like:
	help_request	concept
In the file for the relevant form (or in a separate file), there will
be a collection of predicates such as:
	help_request(concept1):-
		help_user([
			'The help message, format as for chat_user'
			  ]).
I will provide a help_user predicate, similar to chat_user, which will
load the help string for the appropriate command with the string (and
pop it up if possible?).
The same mechanism can also be used for handling errors, etc.
Don't put too much effort into this as the mechanism may change.
However, generating the text would be usefull no matter what.

NOTE:  we also need to design a protocol for the forms package output -
there will be error reports, user requests for help, user requests
for option menu contents, reports of user mouse movement/positions,
reports of user selection, report of field contents/changes and replies
to queries from the BB).  We further need to decide what is handled by
the forms package and what is passed back to the BB (and how!). 
