% inshi(Width,Height,Horizontal,Vertical,L)
% Horizontal is the list of horizontal rectangles, given as 4-tuples with
% starting point coordinates, size, the number inside
% Vertical is the list of vertical rectangles (starting point is top)
% Example:
% inshi(5,5,[(1,1,1,5),(3,1,2,2),(3,2,2,4),(3,3,1,4),(4,3,2,15),(3,4,2,15),(1,5,4,120)],[(2,1,2,15),(5,1,2,12),(2,3,2,2),(5,4,2,2)],L).

extract(L,L,0,[]) :- !.
extract([X|L],L2,Width,[X|L1]) :- W is Width-1, extract(L,L2,W,L1).


% generates all_different constraints for rows
rows([],_) :- !.
rows(Vars,Width) :-
    extract(Vars,Vars1,Width,L), fd_all_different(L), rows(Vars1,Width).

extract1([],[],_,_,[]) :- !.
extract1([X|L],L1,1,W,[X|L2]) :- !,extract1(L,L1,2,W,L2).
extract1([X|L],[X|L1],W,Width,L2) :- W =< Width, !,W1 is W+1,
        extract1(L,L1,W1,Width,L2).
extract1(L,L1,W,Width,L2) :- W > Width, extract1(L,L1,1,Width,L2).

% generates all_different constraints for columns
columns([],_) :- !.
columns(Vars,Width) :-
    extract1(Vars,Vars1,1,Width,L), fd_all_different(L), W is Width-1,
    columns(Vars1,W).


% generates constraints for rectangles (vertical or horizontal depending on Mode
rectangles(_,_,[],_).
rectangles(Mode,Vars,[(X,Y,Size,Number)|L],Width) :-
            rect(Mode,Vars,X,Y,Size,Number,Width),
            rectangles(Mode,Vars,L,Width).

rect(Mode,Vars,X,Y,Size,Number,Width) :-
            getvariables(Mode,Vars,X,Y,Size,Width,LV),
            mult(LV,Number).

getvariables(_,_,_,_,0,_,[]) :- !.
getvariables(ver,Vars,X,Y,Size,Width,[E|L1]) :-
            S is Size - 1, Y1 is Y+ 1,
            element(Vars,X,Y,Width,E),
            getvariables(ver,Vars,X,Y1,S,Width,L1).
getvariables(hor,Vars,X,Y,Size,Width,[E|L1]) :-
            S is Size - 1, X1 is X+1,
            element(Vars,X,Y,Width,E),
            getvariables(hor,Vars,X1,Y,S,Width,L1).

element(L,X,Y,Width,E) :- N is (Y-1)*Width+X, nth(N,L,E).

mult(LV,Number) :- term(LV,T), T #= Number.

term([X],X).
term([X|L],X*T) :- term(L,T).

printline(L,0,L).
printline([X|L],W,L1) :- write(X),W1 is W-1,printline(L,W1,L1).

show([],_). 
show(Vars,Width) :- printline(Vars,Width,Vars1), nl, show(Vars1,Width).

inshi(Width,Height,Horizontal,Vertical,Vars) :- 
            NVars #= Width*Height, 
            length(Vars,NVars), 
            fd_domain(Vars,1,5),
            rows(Vars,Width),
	    columns(Vars,Width),
            rectangles(hor,Vars,Horizontal,Width),
            rectangles(ver,Vars,Vertical,Width),
            fd_labeling(Vars), 
            show(Vars,Width).
            
