% course(Name, Modul, SWS,CP,Semester).
% ap(Modul,CP,Form,Semester)

:- discontiguous ap/4, course/5.

/*
Constraints:
1. jedes Modul erstreckt sich ueber maximal 2 Semester
2. Gesamtzahl CPs=180
3. pro Semester CPs~30
4. logische Abfolge bestimmter Veranstaltungen magrula1 < magrula2, magrula1 < einfCL,...
5. Zahl der APs über die Semester gleichmaessig verteilt (6. Semester weniger APs).
6. Jede Pruefungsform sollte einmal vorkommen.
7. thematische Seminare in einem Modul muessen immer am Ende des Moduls kommen.
*/

% Modul P
course(magrula1,prop,2,2,1).
course(magrula2,prop,2,2,2).
course(logik,prop,4,4,2).
course(lingGrund,prop,4,4,1).
course(progCLPython,prop,4,4,_).
ap(prop,4,klausur,2).

% Module L1-L3
course(phonetik,l1,2,2,1).
course(mor,l2,2,2,1).
course(sem,l3,2,2,1).
course(phono,l1,2,2,2).
course(syn,l2,2,2,2).
course(pra,l3,2,2,2).
ap(l2,4,klausur,2).
ap(l3,4,klausur,2).

% Modul D
course(programmierung,d,8,10,3).
ap(d,0,klausur,3).

% Modul CL1
course(einfCL,cl1,4,8,2).
course(gramFor,cl1,4,4,_).
ap(cl1,0,klausur,2).

% Modul CL2
course(maschUeb,cl2,4,4,_).
course(corpus,cl2,2,2,_).
course(clProgR,cl2,4,4,_).
ap(cl2,4,_,_).

% Modul CL3
course(formSpr,cl3,2,2,_).
course(themSem,cl3,4,4,_).
ap(cl3,4,_,_).

% Modul CL4
course(clProgLogFunk,cl4,4,4,_).
course(compSem,cl4,4,4,_).
course(themSem,cl4,4,4,_).
ap(cl4,4,_,_).

% Modul CL5
course(parsing,cl5,2,2,_).
course(themSem,cl5,4,4,_).
ap(cl5,4,_,_).

% Modul CL6
course(vertiefungInf,cl6,8,10,_).
course(vertiefungFrei4,cl6,_,4,_).
course(vertiefungFrei6,cl6,_,6,_).
course(vertiefungFrei5,cl6,_,5,_).
course(vertiefungFrei2,cl6,_,2,_).
ap(cl6,4,_,_).

% andere
course(prakProj,prakProj,_,7,_).
course(wahl8,wahl,_,8,_).
course(wahl6,wahl,_,6,_).
course(wahl4,wahl,_,4,_).
course(ba,ba,_,12,6).

:- consult(library(clpfd)).

% Kleinstes Listenelement, CLPFD-kompatibel
minimum(Val,Xs) :-
    maplist(#=<(Val), Xs),
    member(Val,Xs).
% Groesstes Listenelement, CLPFD-kompatibel
maximum(Val,Xs) :-
    maplist(#>=(Val), Xs),
    member(Val,Xs).

% Pruefe, dass das Themenseminar am Ende des Moduls kommt
themSemIsMax(Max,task(Sem,1,_,_,themSem)) :- !, Max #= Sem.
themSemIsMax(_,_).

% Modul in Taskliste übersetzen
modul(ModI, Tasks) :-
    % Modul mit AP
    ap(ModI, APCP, _, APSem),
    bagof(task(S,1,_,CP,course(ModI:I)), X^course(I,ModI,X,CP,S), CourseL),
    Tasks = [task(APSem,1,APEnd,APCP,ap(ModI))|CourseL],
    APEnd #= APSem + 1,
    maplist(semester,Starts,Tasks),
    Starts ins 1..6,
    minimum(Min,Starts),
    maximum(Max,Starts),
    Max - Min #=< 1,
    Max #= APSem,
    maplist(themSemIsMax(Max),Tasks).
modul(ModI, Tasks) :-
    % Modul ohne AP
    course(_,ModI,_,_,_),
    \+ ap(ModI, _, _, _),
    bagof(task(S,1,_,CP,course(ModI:I)), X^course(I,ModI,X,CP,S), Tasks),
    maplist(semester,Starts,Tasks),
    Starts ins 1..6,
    minimum(Min,Starts),
    maximum(Max,Starts),
    Max - Min #=< 1,
    maplist(themSemIsMax(Max),Tasks).

% Alle Module uebersetzen und zusammenfügen
tasks(Tasks) :-
    setof(ModI, X^modul(ModI,X), Moduls),
    maplist(modul, Moduls, Taskss),
    append(Taskss, Tasks).

% Belegung finden
sched_courses :-
    tasks(Tasks),
    maplist(semester, Starts, Tasks),
    cumulative(Tasks,[limit(36)]),
    label(Starts),
    printsem(1,Tasks),
    printsem(2,Tasks),
    printsem(3,Tasks),
    printsem(4,Tasks),
    printsem(5,Tasks),
    printsem(6,Tasks).

% Hilfspraedikate für die Ausgabe
semester(Sem,task(Sem,_,_,_,_)).
getcp(task(_,_,_,CP,_),CP).
printsem(Sem,Tasks) :-
    include(semester(Sem), Tasks, TasksS),
    write("Semester "), write(Sem), write(": "),
    maplist(getcp,TasksS,CPs),
    sum(CPs, #=, CP),
    writeln(CP),
    maplist(writetask,TasksS).
writetask(task(_,_,_,_,T)) :- write("- "), writeln(T).
