% Discourse 2009

go(S) :-
	retractall(tel(_)), assert(tel(1)),	
	%blank slate
	DRS = drs([], []),
	analyse([S], DRS, _).


gokat :-
	retractall(tel(_)), assert(tel(1)),	
	%blank slate
	DRS = drs([], []),
	S = [ 
		[ik,zie,een,rode,kat], 
		[ik,zie,een,blauwe,mat],
		[de,kat,zit,op,de,mat] 
	],
	analyse(S, DRS, _).  

go :-
	retractall(tel(_)), assert(tel(1)),	
	%blank slate
	DRS = drs([], []),
	S = [
		['in', 'het', 'midden', 'van', 'het', 'hartje', 'van', 'het', 'binnenste', 
			'van', 'het', 'muiskleurig', 'gebergte', 'woonde', 'de', 'weerwolf'],
		['hij', 'was', 'groot', 'en', 'verschrikkelijk'],
		['zijn', 'ogen', 'sproeiden', 'vuur', 'en', 'zijn', 'tong', 'had', 'karteltjes']
	],
	analyse(S, DRS, NewDRS),
	%S1 = ['iedere', 'avond', 'om', 'zes', 'uur', 'stiet', 'hij', 'een', 'gebrul', 'uit', 'waarvan', 'het', 'hele', 'muiskleurige', 'gebergte', 'sidderde'], interpret(S1, M1, NewDRS),
	%this sentence is not interpreted correctly yet, so here is a hardcoded version
        M1 = [  lex(hij, [], [find(33), pronoun(1), male(33), singular(1), animate(33)], 1),
                lex(had, [1, 3], [verb(2), pastTense(2), eat(1), eat(3), singular(1), noun(1), before(1), noun(3), after(3)], 2),
                lex(lange, [4], [adj(3), eat(4), noun(4), next(4), same_features(3, 4)], 3),
                lex(witte, [5], [adj(4), eat(5), noun(5), next(5), same_features(4, 5)], 4),
                lex(scherpe, [6], [adj(5), eat(6), noun(6), next(6), same_features(5, 6)], 5),
                lex(tanden, [], [noun(6), plural(6), inanimate(6)], 6),
                lex(en, [2, 18], [conn(7), eat(2), eat(18)], 7),
                lex(iedere, [9, 13], [univ(8), eat(9), noun(9), next(9), singular(9), same_features(8, 9), verb(13), eat(13)], 8),
                lex(avond, [], [noun(9), inanimate(9), singular(9), male(9)], 9),
%               lex(om, [8, 11], [prep(10), eat(8), before(8), noun(8), eat(11), noun(11), after(11)], 10),
%               lex(zes, [12], [det(11), eat(12), noun(12), next(12), same_features(11, 12)], 11),
%               lex(uur, [], [noun(12), neuter(12), inanimate(12)], 12),
                lex(stiet, [14, 15, 17], [verb(13), pastTense(13), eat(14), eat(15), eat(17), singular(14), animate(14), noun(15), after(15), particle(17)], 13),
                lex(hij, [], [find(33), pronoun(14), male(33), singular(14), animate(33)], 14),
                lex(een, [16], [det(15), bind(15), eat(16), next(16), noun(16), singular(16), same_features(15, 16)], 15),
                lex(gebrul, [], [noun(16), singular(16), neuter(16), inanimate(16)], 16),
                lex(uit, [], [particle(17)], 17) ,
                lex(waarvan, [16, 23], [prep(18), eat(10), eat(23), prep(10), verb(23)], 18),
                lex(het, [20], [det(19), find(11), eat(20), next(20), neuter(20), same_features(19, 20)], 19),
                lex(hele, [21], [adj(20), eat(21), noun(21), next(21), same_features(20, 21)], 20),
                lex(muiskleurige, [22], [adj(21), noun(22), next(22), same_features(21, 22), eat(22)], 21) ,
                lex(gebergte, [], [noun(22), neuter(22), singular(22)], 22),
                lex(sidderde, [19], [verb(23), pastTense(23), singular(19), before(19), noun(19), eat(19)], 23)],
	docontext(M1, M1, NewDRS, NNewDRS),
	analyse([ ['dat', 'is', 'de', 'weerwolf'] ], NNewDRS, _NNNewDRS).

analyse([], DRS, DRS).
analyse([Sentence | Rest], DRS, Result) :-
        interpret(Sentence, Meaning, DRS),
        writeln('Interpretation: '), writelist(Meaning), nl,
        %generatie check?
        docontext(Meaning, Meaning, DRS, drs(Ref, Cond)),
        writeln('Sentence: '), writeln(Sentence), nl,
        writeln('Meaning: '), writelist(Meaning), nl,
        writeln('Context: '),
        % 'pretty-print' DRS
        writeln(Ref), writeln('--------------'), writelist(Cond), nl,
        analyse(Rest, drs(Ref, Cond), Result).

writelist([]).
writelist([Head | Tail]) :-
        writeln(Head),
        writelist(Tail).



% Groep 1: Lexicon
%lex(word, VariablesToEat, Features).
%Features:
%   - eat, find, bind
%   - part of speech (det, pron, neg, prep, adj, noun, verb)
%   - after, before, next (difference between before and next is that next 
%               only matches the word directly next to it)
%   - male, female, neuter
%   - plural, singular
%   - animate
%
% All features take one argument. The argument is anonymous (_) if it is about
% the word itself, or it specifies a constraint for eat/find/bind.

% in het midden van het hartje van het binnenste van het muiskleurig gebergte woonde de weerwolf
lex(in, [X, Y], [prep(This), eat(X), eat(Y), verb(X), prep(Y), after(Y)], This).
lex(het, [X], [det(This), find(This), eat(X), next(X), neuter(X), same_features(This, X)], This).
lex(midden, [], [noun(This), neuter(This)], This).
lex(van, [X,Y], [prep(This), eat(X), eat(Y), noun(X), prep(Y), before(X), after(Y)], This).
lex(van, [X,Y], [prep(This), eat(X), eat(Y), noun(X), noun(Y), before(X), after(Y)], This).
lex(hartje, [], [noun(This), neuter(This)], This).
lex(binnenste, [], [noun(This), neuter(This)], This).
lex(muiskleurig, [X], [adj(This), eat(X), noun(X), next(X), same_features(This, X)], This).
lex(gebergte, [], [noun(This), neuter(This),singular(This)], This).
lex(woonde, [X], [verb(This), singular(This), past(This), eat(X), noun(X), animate(X)], This).
lex(de, [X], [det(This), find(_), eat(X), noun(X), next(X), male(X), same_features(This, X)], This).
lex(de, [X], [det(This), find(_Y), eat(X), next(X), female(X), same_features(This, X)], This).
lex(de, [X], [det(This), find(_Y), eat(X), next(X), plural(X), same_features(This, X)], This).
lex(weerwolf, [], [noun(This), animate(This), male(This), singular(This)], This).


% hij was groot en verschrikkelijk
lex(hij, [], [pronoun(This), find(X), male(X), animate(X), singular(This)], This).
lex(was, [X,Y], [verb(This), pastTense(This), singular(This), eat(X), eat(Y)],This).
lex(groot, [], [adj(This)], This).
lex(en, [X,Y], [npconj(This), eat(X), eat(Y), before(X), after(Y)], This). % een ‘en’ zoals in een opsomming
lex(verschrikkelijk, [], [adj(This)], This).

% zijn ogen sproeiden vuur en zijn tong had karteltjes
lex(zijn, [X], [pronoun(This), eat(X), noun(X), next(X), find(This), male(This), same_features(This, X)], This).
lex(ogen, [], [noun(This), plural(This), inanimate(This)], This).
lex(sproeiden, [X,Y], [verb(This), pastTense(This), eat(X), eat(Y), plural(X), noun(X), before(X), noun(Y), after(Y)], This).
lex(vuur, [], [noun(This), inanimate(This), singular(This), neuter(This)], This).
lex(en, [X,Y], [conn(This), eat(X), eat(Y), before(X), after(Y), verb(X),verb(Y)], This). % een ‘en’ die twee complete zinnen verbindt
lex(tong, [], [noun(This), inanimate(This), singular(This), female(This)], This).
%lex(had, [X,Y], [verb(This), pastTense(This), eat(X), eat(Y), singular(X), noun(X), before(X), noun(Y), after(Y)], This).
lex(had,[X,Y],[verb(This), singular(This),pastTense(This),eat(X),eat(Y), noun(Y)],This).
lex(karteltjes, [], [noun(This), plural(This)], This).

% hij had lange witte scherpe tanden en
lex(lange, [X], [adj(This),eat(X),next(X),same_features(This,X)], This).
lex(witte, [X], [adj(This),eat(X),next(X),same_features(This,X)], This).
lex(scherpe,[X],[adj(This),eat(X),next(X),same_features(This,X)], This).
lex(tanden, [], [noun(This),plural(This),inanimate(This)], This).

% iedere avond om zes uur stiet hij een gebrul uit waarvan het hele muiskleurige gebergte sidderde
lex(iedere, [X,Y], [det(This), univ(This),eat(X),noun(X),next(X),singular(X),same_features(This,X),verb(Y),eat(Y)], This).
lex(avond, [] , [noun(This),inanimate(This),singular(This),male(This)], This).
lex(om, [X,Y], [prep(This),eat(X),before(X),noun(X),eat(Y),noun(Y),after(Y)], This).
lex(zes, [X], [det(This),eat(X),noun(X),next(X),same_features(This,X)], This).
lex(uur, [], [noun(This),neuter(This),inanimate(This)], This).
lex(stiet,[X,Y,Z], [verb(This),pastTense(This),eat(X),eat(Y),eat(Z),singular(X),animate(X),noun(Y),after(Y),particle(Z)], This).
lex(een, [X], [det(T), eat(X), bind(_Y), next(X), same_features(T, X)], T). 

lex(gebrul, [], [noun(This),singular(This),neuter(This),inanimate(This)], This).

% deze ‘uit’ hoort bij ‘stiet’ (uitstoten)
% ik maak er daarom een particle van en geen preposition
% zie http://en.wikipedia.org/wiki/Preposition_and_postposition#Particles
% -- Jeroen
lex(uit, [], [particle(This)], This).
lex(waarvan, [X,Y], [prep(This),eat(X),eat(Y),prep(X),verb(Y)], This). % ‘waarvan’ is een betrekkelijk voornaamwoord
lex(hele, [X], [adj(This),eat(X),noun(X),next(X),same_features(This,X)], This).
lex(muiskleurige, [X], [adj(This),noun(X),next(X),same_features(This,X),eat(X)], This).
lex(sidderde, [X], [verb(This),pastTense(This),singular(X),before(X),noun(X),eat(X)], This).

% dat is de weerwolf
lex(dat,[X],[pronoun(This),noun(X),find(X)],This).
lex(is, [X,Y],[verb(This),presentTense(This),singular(This),noun(X),eat(X),eat(Y)],This).

% ik zie een rode kat en een blauwe mat. de kat zit niet op de mat.
lex(ik, [], [pronoun(T), find(Y), animate(Y), animate(T), male(Y)], T).
lex(zie, [X, Y], [eat(X), eat(Y), before(X), verb(T), animate(X), noun(Y)], T).
lex(rode, [X], [eat(X), adj(T), next(X), same_features(T, X)], T).
lex(kat, [], [noun(Y), animate(Y), male(Y)], Y).
lex(blauwe, [X], [adj(T), eat(X), next(X), same_features(T, X)], T).
lex(zit, [X], [eat(X), before(X), verb(T)], T).
lex(niet, [X], [eat(X), before(X), verb(X), neg(T)], T).
lex(mat, [], [noun(T), male(T)], T).
lex(op, [X,Y], [prep(T), eat(X), eat(Y), before(X), next(Y), verb(X)], T).

:- dynamic tel/1.

% Groep 2
interpret(S, M, _):-
    def(S, M),
    eat_in_order(M).
% Get word definitions and assign unique word IDs
def([], []).
def([H|T], [lex(H, A2, A3, Tel)|M]) :-
    tel(Tel),
    lex(H, A2, A3, Tel),
    NewTel is Tel + 1,
    retractall(tel(_)),
    assert(tel(NewTel)),
    def(T, M).

%apply predicate to all elements of the list and retain unifications
eat_in_order(Sentence):-
    eat_in_order(Sentence, [], Breakfast, adj),
    eat_in_order(Sentence, Breakfast, Snack1, pronoun),
    eat_in_order(Sentence, Snack1, Lunch, det),
    eat_in_order(Sentence, Lunch, Snack2, verb),
    eat_in_order(Sentence, Snack2, Dinner, conn),
    eat_in_order(Sentence, Dinner, _, prep).

eat_in_order(Sentence, Stomach, Meal, Type) :-
    findall(lex(A1,A2,A3,A4), (member(lex(A1, A2, A3, A4), Sentence), Pred=..[Type,A4], strict_mem2(Pred, A3)), Lexs),
    (	Type = adj,
	reverse(Lexs, OrderedLexs)
    ;	OrderedLexs = Lexs
    ),
    eat_list(OrderedLexs, Stomach, Meal, Sentence).

eat_list([], Meal, Meal, _).
eat_list([H|T], Stomach, Meal, Sentence):-
    eat(H, Stomach, MealPart, Sentence),
    eat_list(T, MealPart, Meal, Sentence).

% succeed if there is nothing to eat:
eat(lex(_,_,Feat,_), Meal, Meal, _Meaning) :-
    \+ member(eat(X), Feat),
    var(X).

eat(lex(_,_,Feat, Id), Stomach, Meal, Meaning) :-
    strict_sel(eat(_), Feat, eat(Food), Rest),
    %find all constraints specified for the referent we need to find:
    findall(Formula, (strict_mem([P,Food], Rest), Formula=..[P, Food]), Constraints),
    %instantiate X with word satisfying constraints
    getFood(Food, Id, Constraints, Stomach, Meaning),
    (	member(lex(_,_,Feat,Id), Meaning),!
    ;	true
    ),
    eat(lex(_,_,Rest, Id), [Food|Stomach], Meal, Meaning).

strict_sel(M, [H|T], H, T):-
	M = H.

strict_sel(M, [H|T], X, [H|Rest]):-
	\+ M = H,
	strict_sel(M, T, X, Rest).


strict_mem([Pred,X], [H|_]):-
	H =..[Pred,Y],
	X == Y.

strict_mem([P,X], [_|T]):-
	%H =..[_, Y],
	%\+ X == Y,
	strict_mem([P,X], T).

strict_mem2(Pred, [H|_]):-
	Pred == H.

strict_mem2(Pred, [H|T]):-
	\+ Pred == H,
	strict_mem2(Pred, T).

getFeatures(lex(_, _, Feats, ID), _, Feats):-
    \+ member(same_features(ID, _), Feats).

getFeatures(lex(_, _, Feats, ID), M, TotalFeats):-
    select(same_features(ID, FoodID), Feats, TempFeats),
    nonvar(FoodID),
    member(lex(_, _, Feats2, FoodID), M),
    getFeatures(lex(_, _, Feats2, FoodID), M, Feats3),
    replaceIDFeats(ID, FoodID, Feats3, Feats4),
    append(TempFeats, Feats4, TotalFeats).

replaceIDFeats(_, _, [], []).

replaceIDFeats(ID, FoodID, [H|T], [IDFeat|Rest]):-
    H =.. [Pred, FoodID],
    IDFeat =.. [Pred, ID],
    replaceIDFeats(ID, FoodID, T, Rest).

replaceIDFeats(ID, FoodID, [H|T], Rest):-
    \+ H =.. [_, FoodID],
    replaceIDFeats(ID, FoodID, T, Rest).

getFood(X, Id, Constraints, Stomach, Meaning) :-
    (	member(before(_), Constraints),
	reverse(Meaning, OrderedM)
    ;	OrderedM = Meaning
    ),
    member(lex(_, _, Feats, FoodID), OrderedM),
    \+ Id = FoodID, %don't eat yourself.
    % don't eat something which has already been eaten: (causes problems with current lexicon)
    \+ member(FoodID, Stomach),
    getFeatures(lex(_, _, Feats, FoodID), Meaning, TotalFeats),
    select_relevant_feats(FoodID, TotalFeats, RelevantFeats),
    forall(member(C, Constraints), checkconstraint(C, RelevantFeats, Id, FoodID)),
    X = FoodID.

select_relevant_feats(_, [], []).

select_relevant_feats(ID, [H|T], [H|RelFeats]):-
	H =..[_,X],
	X == ID,
	select_relevant_feats(ID, T, RelFeats).

select_relevant_feats(ID, [H|T], RelFeats):-
	H =..[_,X],
	\+ X == ID,
	select_relevant_feats(ID, T, RelFeats).
	
checkconstraint(C, Feats, Id, FoodId) :-
    (C = before(_), FoodId < Id)
    ;
    (C = after(_), FoodId > Id)
    ;
    % words directly next to each other
    (C = next(_), FoodId =:= Id + 1)
    ;
    ( \+ C = after(_), \+ C = before(_), \+ C = next(_),
    member(C, Feats)).


sentenceFind(Meaning, [], _, Meaning, _).

sentenceFind(Meaning, [H|T], DRS, NewMeaning, Refs):-
    H = lex(_,_,Feat, _),
    \+ member(find(_), Feat),
    sentenceFind(Meaning, T, DRS, NewMeaning, Refs).
   
sentenceFind(Meaning, [H|T], DRS, NewMeaning, Refs):-
    H = lex(_Word, _OtherRefs, Feat, _Id),
    member(find(_), Feat),
    find(H, Meaning, DRS, Ref, OldRef),
    writeln(Ref),
    writeln(Refs),
    \+ strict_mem2(Ref, Refs),
    replaceId(Meaning, OldRef, Ref, TempNewMeaning),
    sentenceFind(TempNewMeaning, T, DRS, NewMeaning,[Ref|Refs]).


replaceId([], _,_,[]).

replaceId([H|T], OldId, NewId, [NewLex|Rest]):-
	H = lex(Word,Refs,Feats, Id),
	Id = OldId,
	replaceLexId(Feats, OldId, NewId, NewFeats),
	replaceRefs(Refs, OldId, NewId, NewRefs),
	NewLex = lex(Word, NewRefs, NewFeats, NewId),
	replaceId(T, OldId, NewId, Rest).

replaceId([H|T], OldId, NewId, [NewLex|Rest]):-
	H = lex(Word,Refs,Feats, Id),
	\+ Id = oldId,
	replaceLexId(Feats, OldId, NewId, NewFeats),
	replaceRefs(Refs, OldId, NewId, NewRefs),
	NewLex = lex(Word, NewRefs, NewFeats, Id),
	replaceId(T, OldId, NewId, Rest).

replaceRefs([], _, _,[]).

replaceRefs([OldId|T],OldId, NewId, [NewId|Rest]):-
	replaceRefs(T, OldId, NewId, Rest).

replaceRefs([H|T], OldId, NewId, [H|Rest]):-
	H \= OldId,
	replaceRefs(T, OldId, NewId, Rest).


% Replace the old referent by a referent that has been found
replaceLexId([], _, _,[]).
   
replaceLexId([H|T], Id, NewRef, [NewFeat|Rest]):-
    H =.. [Pred, Id],
    NewFeat =.. [Pred, NewRef],
    replaceLexId(T, Id, NewRef, Rest).
   
replaceLexId([H|T], Id, NewRef, [H|Rest]):-
    \+ H =.. [_Pred, Id],
    replaceLexId(T, Id, NewRef, Rest).

   

    
% Find a referent for one item    
% Finding words with "de", "het", and "een" is different
find(lex(Word,_, Features, Id), Meaning, DRS, Ref, X):-
	member(Word, [de, het, een]),
	getMostInnerRef(lex(Word,_, Features, Id), Meaning, X),
	member(lex(OtherWord,OtherRefs, EatenWordFeats, X),Meaning),
	find(lex(OtherWord, OtherRefs, EatenWordFeats, X), Meaning, DRS, Ref, _).
	       
find(lex(Word,_, Features, Id), Meaning, DRS, Ref, Id):-
	\+ member(Word, [de, het, een]),
	DRS = drs(_Referents, Table),
	findLastRef(Table, Ref),
	checkFeatures(lex(Word, _, Features, Id),Meaning, DRS, Ref).

find(lex(_,_,_,Id), _, _, _,Id). 

		  
getMostInnerRef(lex(_, _, Features, Id), _, Ref):-
	\+ member(eat(_), Features),
	Ref = Id.

getMostInnerRef(lex(_, _, Features, _), Meaning, Ref):-
	member(eat(X), Features),
	member(lex(A, B, C, X), Meaning),
	getMostInnerRef(lex(A,B,C,X), Meaning, Ref).

	
%Input is a DRS predicate
checkFeatures(lex(Word, _, Features, Id),Meaning, DRS, Ref):-
	\+ DRS = [_|_],
	DRS =.. [_Pred, [_|_], [H|T]],
	checkFeatures(lex(Word, _, Features, Id),Meaning, [H|T], Ref).
	
%Input is a list
checkFeatures(lex(Word, _, Features, Id),Meaning, DRS, Ref):-
	DRS = [_|_],
	checkFeatsList(lex(Word, _, Features, Id),Meaning, DRS, Ref).

checkFeatures(lex(Word, _, Features, Id),Meaning, DRS, Ref):-
	member(X, DRS),
	X =.. [_Pred, [_|_]],
	checkFeatures(lex(Word, _, Features, Id),Meaning, X, Ref).
		
checkFeatsList(lex(Word, _, _Features, _Id), _Meaning, List, Ref):-
	Pred =.. [Word, Ref],
	member(Pred, List).

checkFeatsList(lex(Word, OtherRefs, Features, Id),Meaning, List, Ref):-
	member(Pred, List),
	Pred =.. [PredWord, Ref],
	lex(PredWord, _, DRSFeats, _),
	removeIrrelevantFeats(DRSFeats, RelDRSFeats),
	getFeatures(lex(Word, OtherRefs, Features, Id), Meaning, AllFeatures),
	removeIrrelevantFeats(AllFeatures, RelFeats),
	allMember(RelDRSFeats, RelFeats).

relevantFeat(X):-
	\+ member(X, [noun(_), adj(_), prep(_), eat(_), find(_), bind(_), before(_), after(_), next(_), previous(_)]).
		  
removeIrrelevantFeats([], []).

removeIrrelevantFeats([H|T], Rest):-
	\+ relevantFeat(H),!,
	removeIrrelevantFeats(T, Rest).

removeIrrelevantFeats([H|T], [H|Rest]):-
	relevantFeat(H),
	removeIrrelevantFeats(T, Rest).
	
%Input is a predicate
findLastRef(X, Ref):-
	\+ X = [_|_],
	X =.. [_Pred|[H|T]],
	\+ H = [_|_],
	reverse([H|T], Reversed),
	member(Ref, Reversed).

%Input is a DRS predicate
findLastRef(DRS, Ref):-
	\+ DRS = [_,_],
	DRS =.. [_Pred, [_|_], [H|T]],
	reverse([H|T], Reversed),
	findLastRef(Reversed, Ref).
	
%Input is a list
findLastRef(Table, Ref):-
	Table = [_|_],
	reverse(Table, ReversedTable),
	member(X, ReversedTable),
	findLastRef(X, Ref).

    
allMember([], _).

allMember([H|T], B):-
	member(H, B),
	allMember(T, B).















% Groep 3: context model
gocontext :-
	retractall(tel(_)),
	assert(tel(1)),
	DRS = drs([], []),
	Meaning = [lex(hij, [], [find(1), pronoun(1), male(1), singular(1), animate(1)], 1),
		lex(had, [1, 3], [verb(2), pastTense(2), eat(1), eat(3), singular(1), noun(1), before(1), noun(3), after(3)], 2),
		lex(lange, [4], [adj(3), eat(4), noun(4), next(4), same_features(3, 4)], 3),
		lex(witte, [5], [adj(4), eat(5), noun(5), next(5), same_features(4, 5)], 4),
		lex(scherpe, [6], [adj(5), eat(6), noun(6), next(6), same_features(5, 6)], 5),
		lex(tanden, [], [noun(6), plural(6), inanimate(6)], 6),
		lex(en, [2, 18], [conn(7), eat(2), eat(18)], 7),
		lex(iedere, [9, 13], [univ(8), eat(9), noun(9), next(9), singular(9), same_features(8, 9), verb(13), eat(13)], 8),
		lex(avond, [], [noun(9), inanimate(9), singular(9), male(9)], 9),
%		lex(om, [8, 11], [prep(10), eat(8), before(8), noun(8), eat(11), noun(11), after(11)], 10),
%		lex(zes, [12], [det(11), eat(12), noun(12), next(12), same_features(11, 12)], 11),
%		lex(uur, [], [noun(12), neuter(12), inanimate(12)], 12),
		lex(stiet, [14, 15, 17], [verb(13), pastTense(13), eat(14), eat(15), eat(17), singular(14), animate(14), noun(15), after(15), particle(17)], 13),
		lex(hij, [], [find(14), noun(14), male(14), singular(14), animate(14)], 14),
		lex(een, [16], [det(15), bind(15), eat(16), next(16), noun(16), singular(16), same_features(15, 16)], 15),
		lex(gebrul, [], [noun(16), singular(16), neuter(16), inanimate(16)], 16),
		lex(uit, [], [particle(17)], 17) ,
		lex(waarvan, [16, 23], [prep(18), eat(10), eat(23), prep(10), verb(23)], 18),
		lex(het, [20], [det(19), find(19), eat(20), next(20), neuter(20), same_features(19, 20)], 19),
		lex(hele, [21], [adj(20), eat(21), noun(21), next(21), same_features(20, 21)], 20),
		lex(muiskleurige, [22], [adj(21), noun(22), next(22), same_features(21, 22), eat(22)], 21) ,
		lex(gebergte, [], [noun(22), neuter(22), singular(22)], 22),
		lex(sidderde, [19], [verb(23), pastTense(23), singular(19), before(19), noun(19), eat(19)], 23)],
	/*
	Meaning = [   lex(in, [14, 4], [prep(1), eat(14), eat(4), verb(14), prep(4), 
		   after(4)], 1),
		   lex(het, [3], [det(2), find(2), eat(3), next(3), neuter(3), same_features(2, 3)], 2),
		   lex(midden, [], [noun(3), neuter(3)], 3),   
		   lex(van, [2, 7], [prep(4), eat(2), eat(7), noun(2), prep(7), before(2), after(7)], 4)    ,
		   lex(het, [6], [det(5), find(5), eat(6), next(6), neuter(6),    
		   same_features(5, 6)], 5)    ,
		   lex(hartje, [], [noun(6), neuter(6)], 6)  ,
		   lex(van, [5, 10], [prep(7), eat(5), eat(10), noun(5), prep(10),
		   before(5), after(10)], 7)   ,
		   lex(het, [9], [det(8), find(8), eat(9), next(9), neuter(9),    
		   same_features(8, 9)], 8)    ,
		   lex(binnenste, [], [noun(9), neuter(9)], 9)      ,
		   lex(van, [8, 11], [prep(10), eat(8), eat(11), noun(8), noun(11),      
		   before(8), after(11)], 10)  ,
		   lex(het, [12], [det(11), find(11), eat(12), next(12), neuter(12),     
		   same_features(11, 12)], 11) ,
		   lex(muiskleurig, [13], [adj(12), eat(13), noun(13), next(13),  
		   same_features(12, 13)], 12) ,
		   lex(gebergte, [], [noun(13), neuter(13), singular(13)], 13)    ,
		   lex(woonde, [15], [verb(14), singular(14), past(14), eat(15),  
		   noun(15), animate(15)], 14) ,
		   lex(de, [16], [det(15), find(15), eat(16), noun(16), next(16), 
		   male(16), same_features(15, 16)], 15)     ,
		   lex(weerwolf, [], [noun(16), animate(16), male(16)], 16)],
	*/
	docontext(Meaning, Meaning, DRS, NewDRS),
	writeln(NewDRS).

gocontext1 :-
	M=[lex(hij, [], [find(1), noun(1), male(1), singular(1), animate(1)], 1), lex(was, [1, 4], [verb(2), pastTense(2), eat(1), eat(4), singular(1), noun(1), before(1), prep(4), after(4)], 2), lex(groot, [], [noun(3)], 3), lex(en, [3, 5], [npconj(4), eat(3), eat(5), noun(3), before(3), noun(5), after(5)], 4), lex(verschrikkelijk, [], [noun(5)], 5)],
	docontext(M,M,drs([2, 5, 8, 11, 15], [in(15, 2), midden(2), van(2, 5), hartje(5), van(5,8), binnenste(8), van(8, 11), gebergte(11), muiskleurig(11), woonde(15),weerwolf(15)]),ND),
	writeln(ND).

%bind new referents
dobind([], _, DRS, DRS).
dobind([lex(Word, Vars, Feats, Id) | Rest], M, drs(Ref, Cond), drs(NewRef, Cond)) :-
	dobind(Rest, M, drs(Ref, Cond), drs(R, Cond)),
	((member(bind(V), Feats) ; (member(find(V), Feats), var(V))) ->
		V = Id,
		%Add variable to M:
		member(lex(Word, Vars, Feats, Id), M),
		%Add new variable to Ref:
		union(R, [V], NewRef)
	;
		% ?! nonvar(Ref),
		NewRef = R).

% wrapper
docontext(Meaning, Meaning, DRS, NewDRS) :-
	dobind(Meaning, Meaning, DRS, Tmp),
	Tmp = drs(Ref, Cond),
	%handle negation
	((select(lex(_, _, C, _), Meaning, Rest), member(neg(_), C)) ->
		docontext(Rest, Rest, drs([], []), drs(NewRef, TempCond)),
		subtract(TempCond, Cond, NewCond),
		NewDRS = drs(Ref, [not(drs(NewRef, NewCond)) | Cond])
	;
		% handle sentence conjunction
		((select(lex(_, _, D, _), Meaning, _Rest), member(conn(_), D)) ->
			append(A, [lex(_,_,D,_)|B], Meaning),
			docontext(A, A, DRS, drs(NewRef1, TempCond1)),
			docontext(B, B, DRS, drs(NewRef2, TempCond2)),
			% merge DRSes
			union(NewRef1, NewRef2, NewRef3),
			union(NewRef3, Ref, NewRef),
			union(TempCond1, TempCond2, TempCond3),
			union(TempCond3, Cond, NewCond),
			NewDRS = drs(NewRef, NewCond)
		;
			% handle universal quantification
			((select(lex(_, _, E, _), Meaning, Rest), member(univ(_), E)) ->
				select(eat(A), E, ER), %variable
				select(eat(B), ER, _), %sentence
				select(lex(W,_V,_F,A), Rest, RRest),
				%one-word hack for variable:
				Pred =.. [W, A],
				DRS1 = drs([A], [Pred]),
				%AM = [lex(W,V,F,A)], %plus more words?
				%eg. iedere donkere avond
				%docontext(AM, AM, drs([],[]), DRS1),
				docontext(RRest, RRest, drs([],[]), DRS2),
				DRS2 = drs(Ref2, Cond2),
				subtract(Ref2, Ref, NRef2),
				subtract(Cond2, Cond, Cond3),
				union(Cond, [forall(DRS1, drs(NRef2, Cond3))], NewCond),
				NewDRS = drs(Ref, NewCond)
			;
				%normal sentence, stop recursing
				context(Meaning, Meaning, Tmp, NewDRS)))).

context([], _, NewDRS, NewDRS).
context([lex(Word, Vars, Feats, Id) | Rest], M, drs(Ref, Cond), Result) :-
	% add conditions to DRS
	% normal words, ie., neither a determiner or pronoun, has arguments:
	(\+ (member(det(_), Feats) ; member(npconj(_), Feats) ; member(pronoun(_), Feats) ; Vars = []) ->
		% handle NP conjunctions and copula
		(member(eat(X), Feats), member(lex(_,_,XFeats,X), M), member(npconj(X), XFeats) ->
			select(eat(A), XFeats, XRest),
			select(eat(B), XRest, _),
			(Vars = [Y, X] ->
				XVars1 = [Y, A],
				XVars2 = [Y, B]
			;
				XVars1 = [A, Y],
				XVars2 = [B, Y]),
			((deref(XVars1, M, DerefVars1),
			  deref(XVars2, M, DerefVars2)) ->
				Pred1 =.. [Word | DerefVars1],
				Pred2 =.. [Word | DerefVars2],
				union(Ref, DerefVars1, Tmp),
				union(Tmp, DerefVars2, NewRef)
			;
				%copula, verb has no meaning
				member(lex(Word1, _,_, A), M),
				member(lex(Word2, _,_, B), M),
				Pred1 =.. [Word1, Y],
				Pred2 =.. [Word2, Y],
				union(Ref, [Y], NewRef)),
			union(Cond, [Pred1, Pred2], NewCond)
		;
			%resolve word IDs to discourse referents
			(deref(Vars, M, DerefVars) ->
				Pred =.. [Word | DerefVars],
				union(Ref, DerefVars, NewRef)
			;
				%copula, verb has no meaning
				% eg. hij was groot:
				% get ref from 'hij', condition from 'groot'
				select(eat(A), Feats, XRest),
				select(eat(B), XRest, _),
				member(lex(_W,_,AF,A), M),
				member(lex(Word,_,_,B), M),
				member(bind(A), AF),
				Pred =.. [Word, A],
				union(Ref, [A], NewRef)),
			union(Cond, [Pred], NewCond)),
		context(Rest, M, drs(NewRef, NewCond), Result)
	;	%handle determiners
		((member(det(_), Feats) ; member(pronoun(_), Feats)) ->
			(member(find(F), Feats)
			;
			member(bind(F), Feats)), 
			%recurse until word which hasn't eaten (noun)
			findconditions(F, Feats, M, Preds),
			union(Cond, Preds, NewCond),
			context(Rest, M, drs(Ref, NewCond), Result)
		;
			% a word which hasn't eaten anything but is
			% eaten directly by a verb should bind a new referent
			% and be added as condition.
			((member(lex(_,_,VFeat,_), M), 
			member(eat(Id), VFeat), 
			(member(verb(_), VFeat) ; member(prep(_), VFeat))) ->
				Pred =.. [Word, Id],
				union(Cond, [Pred], NewCond),
				union(Ref, [Id], NewRef),
				context(Rest, M, drs(NewRef, NewCond), Result)
			;
				% other words without arguments are ignored:
				context(Rest, M, drs(Ref, Cond), Result)))).

% eg. de -> rode -> kat should yield [kat, rode]
findconditions(_F, Feats, _Meaning, []) :-
	\+ member(eat(_X), Feats).
findconditions(F, Feats, Meaning, [Pred | Tail]) :-
	member(eat(X), Feats),
	select(lex(AteWord, _, NFeats, X), Meaning, Rest),
	Pred =.. [AteWord, F],
	findconditions(F, NFeats, Rest, Tail).

% dereference word IDs to their original discourse referents
% (ie., word ID from when referent was introduced)
deref([], _Meaning, []).
deref([V | Vars], Meaning, [R | RVars]) :-
	deref(Vars, Meaning, RVars),
	%find word referred to:
	select(lex(_, _, Feats, V), Meaning, Rest),
	%either the discourse referent has been found:
	(member(find(R), Feats)
	;
	%or it has or will be bound:
	member(bind(R), Feats)
	;
	% implicit bind: bare nouns
	(member(lex(_,_, Feats2, _), Meaning), 
	member(eat(V), Feats2),
	member(verb(_), Feats2),
	R = V)
	;
	%recurse (determiner contains find/bind).
	(\+ member(bind(_), Feats),
	\+ member(find(_), Feats),
	((member(verb(_), Feats) 
	; member(prep(_), Feats)
	; member(npconj(_), Feats)
	; member(adv(_), Feats)) ->
		% resolve verb to one of its arguments 
		%(which argument is part of ambiguity of language...)
		member(eat(Foo), Feats)
	;
		%backwards: eg. kat -> rode -> de 
		member(lex(_,_, Feats2, Foo), Meaning), 
		member(eat(V), Feats2)),
	% prevent cycles by passing Rest, ie., without the word we just tried:
	deref([Foo], Rest, [R]))).
