
/* Functors for defining book and dvd objects:

ITEM ::=  book(TITLE, AUTHOR)  |  dvd(TITLE)
             where TITLE and AUTHOR are atoms (single-quoted strings)

Predicates for defining library's ownership of an object
and for defining when an object is borrowed from the library:

PRED ::=  owns(KEY, ITEM)  |  borrowed(KEY, PERSON, DATE)

             where KEY is an atom that begins with  k
                   ITEM is defined above
                   PERSON is an atom
                   DATE is an int
*/

/* owns(KEY, ITEM)  defines that the library owns the ITEM and has
     labelled it with key  KEY  */
owns(k0, book('David Copperfied', 'Charles Dickens')).
owns(k1, book('Tale of Two Cities', 'Charles Dickens')).
owns(k2, book('Tale of Two Cities', 'Charles Dickens')).
owns(k3, dvd('Tale of Two Cities')).
owns(k4, book('Moby Dick', 'Herman Melville')).

/* borrowed(KEY, NAME, DUEDATE)  defines that  NAME  has borrowed the
    item whose key is KEY and with due date DUEDATE.  */
borrowed(k2, 'Homer', 44).
borrowed(k4, 'Homer', 46).
borrowed(k3, 'Lisa', 92).
borrowed(k0, 'Lisa', 92).


/* isOverdue  holds true if the  Item  borrowed by  Person  has a due date
   that is earlier than  Today.  */
isOverdue(Person, Item, Today) :- borrowed(Item, Person, DueDate), 
                                  Today > DueDate.


/* fineOf  is a "function" that calculates  HowMuch  the fine is,
     as of  Today,  for an overdue  Item.  */
fineOf(Item, Today, HowMuch) :- borrowed(Item, _, DueDate),
                                isOverdue(_, Item, Today),  
                                HowMuch is  Today - DueDate .


/* TRY THIS:  ?- findall(ItemKey, borrowed(ItemKey, 'Homer', _), Ans).  */


/* printBorrowed(Name)  prints the titles of all items borrowed by  Name */
printBorrowed(Name) :- 
               findall(Key, borrowed(Key, Name, _), KeyList),
               write('list of keys is '), write(KeyList), nl,
               printTitles(KeyList).
                  
/* printTitles(KeyList)  looks up the items named by the keys in  Keylist
   and prints the title of each item.  */
printTitles([]).
printTitles([FirstKey|Rest]) :- owns(FirstKey, Item), 
                                printTitle(Item), nl, 
                                printTitles(Rest).
printTitle(book(Title,_)) :- write(Title).
printTitle(dvd(Title)) :- write(Title).


/* sample queries:

borrowed(Key, 'Homer', _).

borrowed(Key, 'Homer', _), owns(Key, Item).

borrowed(Key, 'Homer', _), owns(Key, book(Title, _)).

isOverdue(Who, Key, 90).

fineOf(k2, 90, Bucks).

findall(Key, isOverdue(_, Key, 90), Ans).

findall((Who, Key, Title), 
          ( borrowed(Key, Who, _), 
            (owns(Key, dvd(Title)); owns(Key, book(Title, _))) 
          ), 
        AnsList).

printBorrowed('Homer').
*/


/* patterns can disassemble arguments *and* assemble answers at the same time: */

/*  getTitles(KeyList, TitleList)  holds true when each i-th Key in
    Keylist labels an Item whose title is the i-th Title in TitleList. */
getTitles([], []).    
getTitles([Key|RestKeys], [Title|RestTitles] ) :-             
               (owns(Key, book(Title, _)) ; owns(Key, dvd(Title))),
               getTitles(RestKeys, RestTitles).


/* try this query:
findall(Key, borrowed(Key, 'Homer', _), KeyList), getTitles(KeyList, T).
*/