;;;-*-Mode:lisp;package:window-maker;base:8-*-
;;; Copyright C LISP MACHINE INC., 1985.
;;;
;;;
;;;  At this point of time all the structure should be under the very first frame
;;; which is pointed to by the variable *frame*
;;; The goal is to construct the list of panes and the constraints on the organization
;;; of these panes to reflect exactly what the user has done in the graphical section
;;; of the window editor.
;;;
;;;

(defun generate-pane-specifier-section ()
  ;; this will be only for checking the case where there is no panes at the top level.
  ;; force the top level frame to have one pane.
  (or (funcall *frame* :list-of-panes-or-frames)
      (funcall *frame* :make-a-pane-to-use-for-code-generation))
  (loop for pane in (funcall *frame* ':get-panes-of-inferiors)
	as pane-specifier = (nconc (list (funcall pane ':name-of-pane)
					 (funcall pane ':type))
				   (funcall pane ':init-options))
	with pane-specifier-list = nil
	do (update-list pane-specifier-list pane-specifier)
	finally (return pane-specifier-list)))

(defun make-every-body-even (list-of-items)
  (loop for item in list-of-items
	do
	(funcall item ':set-keyword ':EVEN))
  list-of-items)

(defun sort-panes-and-frames-by-keyword (list-of-panes-or-frames)
  ;
  ;     This will consist only of searching down the list and making sure
  ;  that if a pane has the keyword :EVEN, it ends up as the last
  ;  element of the list
  ;
  (loop with list-of-items = (copylist list-of-panes-or-frames)
	for pane-or-frame in list-of-panes-or-frames
	as keyword = (funcall pane-or-frame ':keyword)
	with number-of-even = 0
	when (equal keyword ':EVEN)
	do
	(delete-element-from-list list-of-items pane-or-frame)
	(update-list list-of-items pane-or-frame)
	(setq number-of-even (1+ number-of-even))
	finally (return (if (> number-of-even 1) (make-every-body-even list-of-items)
			  (if (zerop number-of-even) (funcall (first (last list-of-items)) ':Set-keyword ':EVEN))
			  list-of-items))))


(defun group-the-items-by-subgroup (list-of-items)
  (loop for item in list-of-items
	with list-of-subgroup = nil
	with flag = (every (mapcar '(lambda (x) (equal (funcall x ':keyword) ':even)) list-of-items))
	with last-item = (first (last list-of-items))
	with subgroup-of-panes = nil
	do
	(if flag (return (ncons list-of-items))
	    (if (eq item last-item)
		(if (equal (funcall item ':keyword) ':even)
		    (if (not subgroup-of-panes) (update-list list-of-subgroup (ncons item))
		      (update-list list-of-subgroup subgroup-of-panes)
		      (update-list list-of-subgroup (ncons item)))
		  (update-list subgroup-of-panes item)
		  (update-list list-of-subgroup subgroup-of-panes))
	      (update-list subgroup-of-panes item)))
	finally (return list-of-subgroup)))


(defun build-constraint-for-subgroup (subgroup)
  (loop for item in subgroup
	with constraint-list = nil
	with old-constraint
	when (typep item 'frame)
	do
	;;
	;;   There is only one item and it is a frame. So supply the name and return its constraint list.
	;;
	(funcall item ':set-name-of-frame (gentemp 'dummy-name))
	(update-list constraint-list (generate-constraint-list-for-frame item))
	else do
	(setq old-constraint (get (funcall item :name-of-pane) 'old-constraint))
	;;
	;;   There are only panes in this subgroup
	;;
	(update-list constraint-list (append (ncons (funcall item ':name-of-pane))
					     (or old-constraint (funcall item ':get-size-keyword))))
	finally (return constraint-list)))

(defun generate-constraint-list-for-frame (&optional (frame *frame*))
  (loop with list-of-panes-or-frames-unsorted = (funcall frame ':list-of-panes-or-frames)
	with direction-of-slice = (funcall frame ':direction-of-slice)
	with direction-of-stacking = (if (equal direction-of-slice ':horizontal) ':vertical ':horizontal)
	with sorted-list-by-stacking = (sort-panes-and-frames-in-frame list-of-panes-or-frames-unsorted direction-of-slice)
	with sorted-list-by-keyword = (sort-panes-and-frames-by-keyword list-of-panes-or-frames-unsorted)
	with owner = (funcall frame ':owner)
	with old-stacking-direction = (and owner (if (equal (funcall owner ':direction-of-slice) ':horizontal)
						   ':vertical ':horizontal))
	with direction-of-owner-stacking = (or old-stacking-direction ':vertical)
	with list-of-subgroup = (group-the-items-by-subgroup sorted-list-by-keyword)
	with constraints = nil
	for subgroup in list-of-subgroup
	do
	(update-list constraints (build-constraint-for-subgroup subgroup))
	finally (return
		  (let ((list-of-names (loop with list-of-names = nil
					    for item in sorted-list-by-stacking
					    as operation = (if (typep item 'frame)
							       ':name-of-frame ':name-of-pane)
					    do
					    (update-list list-of-names (funcall item operation))
					    finally (return list-of-names)))
			constraint)
		    (setq constraint (nconc (if (equal (funcall frame ':name-of-frame) 'whole)
					       (ncons list-of-names)
					     (list (funcall frame ':name-of-frame) direction-of-stacking
						   (funcall frame ':get-size-keyword)
						   list-of-names))
					   constraints))
		    (if (equal (funcall frame ':name-of-frame) 'whole)
			(if (equal direction-of-owner-stacking direction-of-stacking)
			    constraint
			  (list (ncons (funcall frame ':name-of-frame))
				(list (append (list (funcall frame ':name-of-frame)
						    direction-of-stacking '(:EVEN))  constraint))))
		      constraint)))))


