;=========================================================================================
;
;	File:	alrules.a - Eclipse rulebase for layout adjustment
;
;	Author: Rich Gartland / Taylor Millett for CLIPS integration
;
;	Date:	
;
;	$Revision: 1 $
;
;	$Header: //depot/shuksan/source/components/layout/autolayout/ALRULES.A#20 $
;
;	Copyright 1997 Adobe Systems Incorporated. All rights reserved. 
;
;=========================================================================================

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; rulebase ALRULES.A
;
; **** ECLIPSE SOURCE CODE FOR LAYOUT ADJUSTMENT RULEBASE ****
;;
; Implements layout adjustment logic for objects on a page
;
; THIS FILE IS THE SOURCE CODE USED TO CREATE ALRULES.BIN, WHICH
; IS LOADED BY SHUKSAN INTO THE ECLIPSE KNOWLEDGE BASE SYSTEM WHEN
; LAYOUT ADJUSTMENT IS PERFORMED.

; ALRULES.BIN IS CREATED USING THE ECLIPSE TOOLKIT

; Notes on the toolkit:  The toolkit's console application is used
;	to create the binary file ("Rulebase:Layout Adjustment Rules.bin").
;	There exist Mac and Win versions of the tool, and these create
;	platform-specific binary files.  Thus, once a new version of this
;	alrules.a file is made, the tool must be run on each platform to
;	create the platform-specific binary file.  Furthermore, for each
;	platform, the Rulebase folder exists in both the Debug and Release
;	folders.  This means the tool must be used to create the binary file
;	for both locations, or made once and copied (there is no difference
;	between the debug and release; the files are identical).
;
;	The commands that I use to load the source file and save the binary
;	file, while in the toolkit, are (Win version here; Mac uses colons):
;	(load "c:\\dragontail\\source\\components\\layout\\autolayout\\alrules.a")
;	(bsave "c:\\dragontail\\build\\win\\debug\\rulebase\\Layout Adjustment Rules.bin")
;	(bsave "c:\\dragontail\\build\\win\\release\\rulebase\\Layout Adjustment Rules.bin")
;
;	The parentheses above are required, but the leading semicolons simply mark
;	comments in this file you're reading.
;
;	The load command loads the source file into memory, while the bsave command
;	saves a binary version of the file to the destination file.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; this status field tells PM we're completely done running -- set in 'done' task
;(defrelation status (?s))

(deftemplate status
(slot s (default 0)))

;
; MAJOR TASKS FOR THIS RULEBASE
;
; While rulebases aren't really supposed to be thought of as sequential in 
; nature, it helps to make sure certain things do happen in order.  For this,
; we use the 'task' relation to keep track of where we are.  See the deffacts
; below called 'internal_facts' to see the major tasks for this rulebase.  
; When the 'done' task is reached, the next_task rule sets the 'status' relation
; to 1, meaning we're finished running this rulebase.  Also note that the 
; next_task rule uses salience to make sure it only activates if no other 
; available rules for this task can fire -- this avoids switching tasks too early.
;
; The actual behavior of this rule is to eliminate the front task from the
; list each time it fires.  Rules that require a certain task to be 'current'
; will thus check the first item in the task list to see if it matches their
; required task.
;
;(defrelation task ($?steps))
(defrule next_task
	(declare (salience -2))
	?t <- (task ?curr $?rest)
	=>
	(retract ?t)
	(assert (task $?rest))
	(if (eq ?curr done)
		then 	(assert (status (s 1))))
	)

;
; MINOR TASKS -- PARTITIONS OF WORK WITHIN A MAJOR TASK
;
; Several tasks are further broken down into subtasks, using a similar
; scheme as for tasks.
;
;(defrelation make_framework_subtask ($?steps))
(defrule next_make_framework_subtask
	(declare (salience -1))
	(task make_framework $?)
	?mfs <- (make_framework_subtask ?curr $?rest)
	=>
	(retract ?mfs)
	(assert (make_framework_subtask $?rest)))

;(defrelation framework_class ($?steps))
(defrule next_framework_class
	(declare (salience -1))
	(task fit_objects $?)
	?fc <- (framework_class ?curr $?rest)
	=>
	(retract ?fc)
	(assert (framework_class $?rest)))

;(defrelation rebuild_framework_subtask ($?steps))
(defrule next_rebuild_framework_subtask
	(declare (salience -1))
	(task rebuild_framework $?)
	?rfs <- (rebuild_framework_subtask ?curr $?rest)
	=>
	(retract ?rfs)
	(assert (rebuild_framework_subtask $?rest)))

;(defrelation find_guide_neighbors_subtask ($?steps))
(defrule next_find_guide_neighbors_subtask
	(declare (salience -1))
	(task find_guide_neighbors $?)
	?rfs <- (find_guide_neighbors_subtask ?curr $?rest)
	=>
	(retract ?rfs)
	(assert (find_guide_neighbors_subtask $?rest)))

;
; preferences for running the rules
;	   (defaults are not really used since InDesign always sends complete prefs template)
(deftemplate prefs
	(slot stretchGraphics (default 0))
	(slot moveGuides (default 1))
	(slot stickyGuides (default 1))
	(slot ignoreGuides (default 0))
	(slot loosenLocks (default 0))
	(slot attachTBBmarginsonly (default 0))
	(slot autosnapzone (default 40))
)

;
; TEMPLATES
;

; A 'member' is a part of the page framework, like a column edge or a guide.
; We label framework members by their CLASS.
; Choices for xxx_member class are COLUMNS, GUIDES, MARGINS, PAGERECT, DUMMY
; We subdivide a CLASS by TYPE.

; Choices for hor_member type are TOPMARGIN, BOTTOMMARGIN, HORGUIDE, LEFTPAGE, RIGHTPAGE
; We keep a state for members, as follows:
;      states for xxx_member: 0=original position, 1=moved when framework rebuilt

; When facts regarding things like columns, etc., are sent down, the make_framework
; task's job is to create xxx_member facts.  This abstraction is useful in doing
; the analysis of various types of members as a group.

(deftemplate hor_member
	(slot type)
	(slot y)
	(slot number)
	(slot side)
	(slot class)
	(slot state (default 0)))

; Choices for ver_member type are LEFTMARGIN, RIGHTMARGIN, VERGUIDE, COLLEFT, COLRIGHT, 
;								TOPPAGE, BOTTOMPAGE
(deftemplate ver_member
	(slot type)
	(slot x)
	(slot number)
	(slot side)
	(slot class)
	(slot state (default 0)))
;
; The following are raw data established by data sent down by the application.
; The make_framework task turns these into members.
; NOTE: For each template, the _new denotes the 'after' state -- that is,
; the values after the change instigated by the user.  For instance, the
; columninfo has column information before a change to the columns, while the
; columninfo_new has this information related to after that change is made.
;
; Also note that many templates have slots that are not set by the data
; sent from the app, but instead are established by rule firings.
;

(deftemplate columninfo
	(slot numcolumns)
	(slot gutter)
	(slot columndifference (default UNSURE))
	(slot numcolumns_old (default 0))
	(slot state (default 0))
	(slot side)
	(slot horizdir (default 0))
	(slot dirchange (default SAME)))

(deftemplate columninfo_new
	(slot numcolumns)
	(slot gutter)
	(slot side)
	(slot horizdir (default 0)))

; in following 2 templates, 'left' and 'right' really
; 'top' and 'bottom' in cases where columninfo:horizdir is true
; That is, 'horizdir' relates to Japanese-style horizontally-running
; columns (this is a bit backwards if you're thinking of J text as
; vertically oriented -- here we are considering the column orientation,
; not the lines of text).

(deftemplate textcolumn
	(slot left)
	(slot right)
	(slot colnumber)
	(slot state (default 0))
	(slot side))

(deftemplate textcolumn_new
	(slot left)
	(slot right)
	(slot colnumber)
	(slot side))

(deftemplate horguide
	(slot y)
	(slot relpos)
	(slot original_location (default 1))
	(slot horguidenumber)
	(slot side)
	(slot locked)
	(slot top_neighbor_distance)
	(slot top_neighbor_class)
	(slot top_neighbor_type)
	(slot top_neighbor_number (default -1))
	(slot bottom_neighbor_distance)
	(slot bottom_neighbor_class)
	(slot bottom_neighbor_type)
	(slot bottom_neighbor_number (default -1))
	)

(deftemplate verguide
	(slot x)
	(slot relpos)
	(slot original_location (default 1))
	(slot verguidenumber)
	(slot side)
	(slot locked)
	(slot debug (default 0.0))
	(slot left_neighbor_distance)
	(slot left_neighbor_class)
	(slot left_neighbor_type)
	(slot left_neighbor_number (default -1))
	(slot right_neighbor_distance (default 0))
	(slot right_neighbor_class)
	(slot right_neighbor_type)
	(slot right_neighbor_number (default -1))
	)

(deftemplate pagerect
	(slot left)
	(slot right)
	(slot top)
	(slot bottom)
	(slot width)
	(slot height)
	(slot width_old)
	(slot height_old)
	(slot left_old)
	(slot right_old)
	(slot top_old)
	(slot bottom_old)
	(slot state (default 0))
	(slot side (default -1)))

(deftemplate pagerect_new
	(slot left)
	(slot right)
	(slot top)
	(slot bottom)
	(slot side))

(deftemplate spread
	(slot pages (default 0))
	(slot width (default 0))
	(slot height (default 0))
	(slot width_old (default 0))
	(slot height_old (default 0))
	(slot left (default 0))
	(slot right (default 0))
	(slot top (default 0))
	(slot bottom (default 0))
	(slot left_old)
	(slot right_old)
	(slot top_old)
	(slot bottom_old)
	(slot state (default 0))
	(slot onepgside (default 2)))

(deftemplate pasteboard
	(slot left)
	(slot right)
	(slot top)
	(slot bottom))

(deftemplate margins
	(slot left)
	(slot right)
	(slot top)
	(slot bottom)
	(slot state (default 0))
	(slot side))

(deftemplate margins_new
	(slot left)
	(slot right)
	(slot top)
	(slot bottom)
	(slot side))

; The 'item' is a pageitem.  
(deftemplate item
	(slot id)
	(slot left)
	(slot right)
	(slot top)
	(slot bottom)
	(slot width_orig)
	(slot height_orig)
	(slot toptype (default -1))
	(slot bottype (default -1))
	(slot side (default 0))
	(slot segtype)
	(slot aspectratio (default nil))
	(slot badaspectratio (default -1))
	(slot original_topbottom (default true))
	(slot original_leftright (default true))
	(slot left_aligns_to (default none))
	(slot left_aligns_obj_num (default 0))
	(slot right_aligns_to (default none))
	(slot right_aligns_obj_num (default 0))
	(slot top_aligns_to (default none))
	(slot top_aligns_obj_num (default 0))
	(slot bottom_aligns_to (default none))
	(slot bottom_aligns_obj_num (default 0))
	(slot left_aligns_side (default 1))
	(slot right_aligns_side (default 1))
	(slot top_aligns_side (default 1))
	(slot bottom_aligns_side (default 1))
	(slot lost (default -1))
	(slot dangling (default 0))
	(slot debug (default (float -1.0))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(deffacts internal_facts
	(task 
		do_setup 
		make_framework
		find_guide_neighbors 
		fit_objects 
		change_page_info
		handle_direction_change 
		rebuild_framework 
		relocate_objects 
		flag_problems 
		fix_problems 
		done
	)
	(make_framework_subtask 
		do_columns
		do_offpage_guides 
		do_guides
		remove_some_guides 
		do_margins 
		do_pagerect
		setup_bleeds
		do_bleeds
	)
	(rebuild_framework_subtask 
		do_pagerect 
		do_guides_matching_columns 
		do_columns 
		do_guides_matching_margins 
		do_margins 
		do_guides
		do_bleeds
	)
	(find_guide_neighbors_subtask
		set_defaults
		find_closest
		figure_relpos
	)

	; keeping track of classes (higher order than types) or xxx_members
	(framework_class COLUMNS GUIDES MARGINS PAGERECT BLEEDS DUMMY)
	; dummy ver_members and hor_members to help the relocate_object rule
	(ver_member (type none) (number 0) (side 0) (x 0) (class DUMMY))
	(hor_member (type none) (number 0) (side 0) (y 0) (class DUMMY))
	(ver_member (type none) (number 0) (side 1) (x 0) (class DUMMY))
	(hor_member (type none) (number 0) (side 1) (y 0) (class DUMMY))
	(ver_member (type none) (number 0) (side -1) (x 0) (class DUMMY))
	(hor_member (type none) (number 0) (side -1) (y 0) (class DUMMY))
	(spread (pages 0) (left 0) (right 0) (top 0) (bottom 0))
	)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RULES FOR THE do_setup TASK
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; RULE FOR CREATING CALCULATED VALUES IN PAGERECT
(defrule complete_pagerect
	(task do_setup $?)
	?pr <- (pagerect (left ?l) (right ?r) (top ?t) (bottom ?b) (side ?s) (state 0))
	?spr <- (spread (pages ?pgs) (left ?sprl) (right ?sprr))
	=>
	(bind ?minx ?sprl)
	(bind ?maxx ?sprr)
	; if the page's left is less than minx, bind it to minx; same idea for right
	(if (< ?l ?minx)
	 then
		(bind ?minx ?l)
	)
	(if (> ?r ?maxx)
	 then
	 	(bind ?maxx ?r)
	)
	; note: 'onepgside' keeps track of which side the page is -- for 2-page spreads
	; it's pretty obvious what sides we have, but for 1-page spreads we need to know
	; what side we're working with (for bleeds)
	(modify ?spr (pages =(+ ?pgs 1)) (left ?minx) (right ?maxx) (top ?t) (bottom ?b) 
		(onepgside ?s))
	(modify ?pr (width =(- ?r ?l)) (height =(- ?b ?t)) 
		(width_old =(- ?r ?l)) (height_old =(- ?b ?t)) (state 1)
		(left_old ?l) (right_old ?r) (top_old ?t) (bottom_old ?b)))

; RULE FOR CAUSING GUIDES TO BE IGNORED WHEN FITTING OBJECTS
(defrule ignore_guides
	(task do_setup $?)
	(prefs (ignoreGuides 1))
	?fc <- (framework_class $?stuff GUIDES $?morestuff)
	=>
	(retract ?fc)
	(assert (framework_class $?stuff $?morestuff)))

; object (segment) types from pagemake.h (not all used by InDesign -- typically
; several of the ID types may be mapped to a single value, since we really
; don't need to distinguish between all these types of objects).  See rule
; 'condense_graphics' below for how this is done here.
;
; S_NULL          0               /* null */
; S_TEXT          1               /* text */
; S_OLE           2               /* OLE object */
; S_LINE          3               /* line */
; S_BOX           4               /* box */
; S_OVAL          5               /* oval */
; S_BITMAP        6               /* bitmap */
; S_SCANNED       7               /* scanned image. obsolete. */
; S_PICT          8               /* environment-dependent picture */
; S_MACPICT       9               /* Mac Pict*/
; S_METAFILE      10              /* windows metafile */
; S_PSCRIPT       11              /* postscript picture */
; S_PATH			12				/* polygon tool */
; skip 13 - not a lucky number to use - RESERVED 
; S_GROUP         14              /* collection of aldus segments */
; S_ENHMETAFILE	15				/* enhanced metafile */


; RULE FOR CONDENSING PLACED GRAPHICS AND GROUP OBJECT TYPES INTO ONE TYPE (6)
(defrule condense_graphics
	(task do_setup $?)
	?obj <- (item (segtype ?segtype&7|8|9|10|11|14|15))
	=>
	(modify ?obj (segtype 6)))

; RULE FOR CALCULATING THE ASPECT RATIO OF AN OBJECT
(defrule calc_aspect_ratio
	(task do_setup $?)
	?obj <- (item (left ?l) (right ?r) (top ?t) (bottom ?b) (aspectratio ?ar&nil))
	=>
	(bind ?w (- ?r ?l))
	(bind ?h (- ?b ?t))
	(if (eq ?h 0)
	 then	(bind ?newratio 0.0)
	 else	(bind ?newratio (/ (float ?w) ?h))
	)
	(modify ?obj (aspectratio ?newratio) (width_orig ?w) (height_orig ?h)))

; RULE FOR FORCING THE 'STICKYGUIDES' slot OF PREFS TEMPLATE TO TRUE
(defrule force_stickyguides_true
	(task do_setup $?)
	?pr <- (prefs (stickyGuides 0))
	=>
	(modify ?pr (stickyGuides 1)))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RULES FOR THE make_framework TASK
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; RULES FOR MAKING MEMBERS FROM BLEEDING OBJECTS (hanging off the page)
(defrule make_left_bleed_member
	(task make_framework $?)
	(make_framework_subtask do_bleeds $?)
	(spread (pages ?pgs) (left ?sprl) (onepgside ?ops))
	(item (left ?objl&:(< ?objl ?sprl)))
	(not
		(ver_member (type LBLEED) (x ?objl)) 
	)
	=>
	(if (> ?pgs 1)
	 then
	 	(bind ?side 0)
	 else
	 	(bind ?side ?ops)
	)
	(assert (ver_member (type LBLEED) (x ?objl) (number =(gensym)) 
		(state 0) (side ?side) (class BLEEDS))))

(defrule make_right_bleed_member
	(task make_framework $?)
	(make_framework_subtask do_bleeds $?)
	(spread (right ?sprr) (pages ?pgs) (onepgside ?ops))
	(item (right ?objr&:(> ?objr ?sprr)))
	(not
		(ver_member (type RBLEED) (x ?objr)) 
	)
	=>
	(if (> ?pgs 1)
	 then
	 	(bind ?side (- ?pgs 1))
	 else
	 	(bind ?side ?ops)
	)
	(assert (ver_member (type RBLEED) (x ?objr) (number =(gensym)) 
		(state 0) (side ?side) (class BLEEDS))))

(defrule make_top_bleed_member
	(task make_framework $?)
	(make_framework_subtask do_bleeds $?)
	(spread (pages ?pgs) (onepgside ?ops))
	(pagerect (top ?pgt) (side ?pageside))
	?it <- (item (top ?objt&:(< ?objt ?pgt)) (side ?pageside))
	(not
		(hor_member (type TBLEED) (y ?objt) (side ?pageside)) 
	)
	=>
	(if (> ?pgs 1)
	 then
	 	(bind ?side ?pageside)
	 else
	 	(bind ?side ?ops)
	 )
	(assert (hor_member (type TBLEED) (y ?objt) (number =(gensym)) 
		(state 0) (side ?side) (class BLEEDS))))

(defrule make_bottom_bleed_member
	(task make_framework $?)
	(make_framework_subtask do_bleeds $?)
	(spread (pages ?pgs) (onepgside ?ops))
	(pagerect (bottom ?pgb) (side ?pageside))
	?it <- (item (bottom ?objb&:(> ?objb ?pgb)) (side ?pageside))
	(not
		(hor_member (type BBLEED) (y ?objb) (side ?pageside)) 
	)
	=>
	(if (> ?pgs 1)
	 then
	 	(bind ?side ?pageside)
	 else
	 	(bind ?side ?ops)
	)
	(assert (hor_member (type BBLEED) (y ?objb) (number =(gensym)) 
		(state 0) (side ?side) (class BLEEDS)))
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; RULES FOR MAKING MEMBERS FROM GUIDES COMPLETELY OFF THE SPREAD
(defrule make_left_offpage_guide_member
	(task make_framework $?)
	(make_framework_subtask do_offpage_guides $?)
	(spread (left ?sprl))
	(verguide (x ?x&:(< ?x ?sprl)) (verguidenumber ?vgn))
	(not
		(ver_member (type OFFPAGELVERGUIDE) (number ?vgn)) 
	)
	=>
	(assert (ver_member (type OFFPAGELVERGUIDE) (x ?x) (number ?vgn) 
		(state 0) (side -1) (class GUIDES))))

(defrule make_right_offpage_guide_member
	(task make_framework $?)
	(make_framework_subtask do_offpage_guides $?)
	(spread (right ?sprr))
	(verguide (x ?x&:(> ?x ?sprr)) (verguidenumber ?vgn))
	(not
		(ver_member (type OFFPAGERVERGUIDE) (number ?vgn)) 
	)
	=>
	(assert (ver_member (type OFFPAGERVERGUIDE) (x ?x) (number ?vgn) 
		(state 0) (side -1) (class GUIDES))))

(defrule make_top_offpage_guide_member
	(task make_framework $?)
	(make_framework_subtask do_offpage_guides $?)
	(spread (top ?sprt))
	(horguide (y ?y&:(< ?y ?sprt)) (horguidenumber ?hgn))
	(not
		(hor_member (type OFFPAGETHORGUIDE) (number ?hgn)) 
	)
	=>
	(assert (hor_member (type OFFPAGETHORGUIDE) (y ?y) (number ?hgn) 
		(state 0) (side -1) (class GUIDES))))

(defrule make_bottom_offpage_guide_member
	(task make_framework $?)
	(make_framework_subtask do_offpage_guides $?)
	(spread (bottom ?sprb))
	(horguide (y ?y&:(> ?y ?sprb)) (horguidenumber ?hgn))
	(not
		(hor_member (type OFFPAGEBHORGUIDE) (number ?hgn)) 
	)
	=>
	(assert (hor_member (type OFFPAGEBHORGUIDE) (y ?y) (number ?hgn) 
		(state 0) (side -1) (class GUIDES))))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; RULES FOR MAKING MEMBERS FROM COLUMN DATA
(defrule make_ver_members_from_column
	(task make_framework $?)
	(make_framework_subtask do_columns $?)
	(columninfo (horizdir 0) (side ?s))
	(textcolumn (left ?l) (right ?r) (colnumber ?cnum) (side ?s))
	(not
		(ver_member (type COLLEFT) (number ?cnum) (side ?s)) 
	)
	=>
	(assert (ver_member (type COLLEFT) (x ?l) (number ?cnum) (side ?s) (class COLUMNS)))
	(assert (ver_member (type COLRIGHT) (x ?r) (number ?cnum) (side ?s) (class COLUMNS))))

(defrule make_hor_members_from_column
	(task make_framework $?)
	(make_framework_subtask do_columns $?)
	(columninfo (horizdir 1) (side ?s))
	(textcolumn (left ?l) (right ?r) (colnumber ?cnum) (side ?s))
	(not
		(hor_member (type COLTOP) (number ?cnum) (side ?s)) 
	)
	=>
	(assert (hor_member (type COLTOP) (y ?l) (number ?cnum) (side ?s) (class COLUMNS)))
	(assert (hor_member (type COLBOTTOM) (y ?r) (number ?cnum) (side ?s) (class COLUMNS))))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; RULES FOR MAKING MEMBERS FROM GUIDE DATA
(defrule make_member_from_horguide
	(task make_framework $?)
	(make_framework_subtask do_guides $?)
	?hg <- (horguide (y ?y) (horguidenumber ?hgn) (side ?s))
	(not
		(hor_member (type HORGUIDE) (number ?hgn))
	)
	(pagerect (top ?t) (bottom ?b) (height ?h) (state 1) (side ?s) )
	=>
	; make duplicate hor_members for guides, so top/bottom matching on side works
	(assert (hor_member (type HORGUIDE) (y ?y) (number ?hgn) (side ?s) (class GUIDES)))
;	(assert (hor_member (type HORGUIDE) (y ?y) (number ?hgn) (side 1) (class GUIDES)))
	(modify ?hg (relpos =(/ (float (- ?y ?t)) ?h)) (original_location 1)))

(defrule make_member_from_pasteboard_horguide
	(task make_framework $?)
	(make_framework_subtask do_guides $?)
	?hg <- (horguide (y ?y) (horguidenumber ?hgn) (side -1))
	(not
		(hor_member (type HORGUIDE) (number ?hgn))
	)
	; in following, skip off-page horguides
	(pagerect (top ?t&:(>= ?y ?t)) (bottom ?b&:(<= ?y ?b)) (height ?h) (state 1) )
;	(pagerect (top ?t) (bottom ?b) (height ?h) (state 1) )
	=>
	(assert (hor_member (type HORGUIDE) (y ?y) (number ?hgn) (side -1) (class GUIDES)))
	(modify ?hg (relpos =(/ (float (- ?y ?t)) ?h)) (original_location 1)))

(defrule make_member_from_pasteboard_verguide
	(task make_framework $?)
	(make_framework_subtask do_guides $?)
	?vg <- (verguide (x ?x) (verguidenumber ?vgn) (side -1))
	(not
		(ver_member (type VERGUIDE) (number ?vgn))
	)
	; in following, skip off-page verguides
	(pagerect (left ?l&:(>= ?x ?l)) (right ?r&:(<= ?x ?r)) (width ?w) (state 1) (side ?s) )
;	(pagerect (left ?l) (right ?r) (width ?w) (state 1) )
	=>
	(assert (ver_member (type VERGUIDE) (x ?x) (number ?vgn) (side ?s) (class GUIDES)))
	(modify ?vg (relpos =(/ (float (- ?x ?l)) ?w)) (original_location 1) (side ?s)))


(defrule make_member_from_verguide
	(task make_framework $?)
	(make_framework_subtask do_guides $?)
	?vg <- (verguide (x ?x) (verguidenumber ?vgn) (side ?s))
	(not
		(ver_member (type VERGUIDE) (number ?vgn))
	)
	(pagerect (left ?l&:(>= ?x ?l)) (right ?r&:(<= ?x ?r)) (width ?w) (side ?s) (state 1))
	=>
	(assert (ver_member (type VERGUIDE) (x ?x) (number ?vgn) (side ?s) (class GUIDES)))
	(modify ?vg (relpos =(/ (float (- ?x ?l)) ?w)) (original_location 1)))

;;;;;;;;;;;;;;;;;;;;;;;;
; rules to toss guides that end up off-page if they haven't been
; allowed to move and the page size will change out from under them
;
(defrule toss_ver_guides_if_off_page
	(task make_framework $?)
	(make_framework_subtask remove_some_guides $?)
	(prefs (moveGuides 0))
	(pagerect_new (left ?l) (right ?r) (side ?s))
	?vg <- (verguide (x ?x))
	?vm <- (ver_member (type VERGUIDE) (x ?x) (side ?s))
	=>
	(if (or (< ?x ?l) (> ?x ?r))
		then
			(retract ?vg)
			(retract ?vm)
	))
	
(defrule toss_hor_guides_if_off_1_page
	(task make_framework $?)
	(make_framework_subtask remove_some_guides $?)
	(prefs (moveGuides 0))
;	(spread (pages 1) (onepgside ?s))
	(pagerect_new (top ?t) (bottom ?b) (side ?s))
	?hg <- (horguide (y ?y))
	?hm <- (hor_member (type HORGUIDE) (y ?y) (side ?s))
	=>
	(if (or (< ?y ?t) (> ?y ?b))
		then
			(retract ?hg)
			(retract ?hm)
	))

;(defrule toss_hor_guides_if_off_2_pages
;	(task make_framework $?)
;	(make_framework_subtask remove_some_guides $?)
;	(prefs (moveGuides 0))
;	(spread (pages 2))
;	(pagerect_new (top ?t) (bottom ?b))
;	?hg <- (horguide (y ?y))
;	?hm1 <- (hor_member (type HORGUIDE) (y ?y) (side 0))
;	?hm2 <- (hor_member (type HORGUIDE) (y ?y) (side 1))
;	=>
;	(if (or (< ?y ?t) (> ?y ?b))
;		then
;			(retract ?hg)
;			(retract ?hm1)
;			(retract ?hm2)
;	))
;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; RULES FOR MAKING MEMBERS FROM MARGIN DATA
(defrule make_members_from_margins
	(task make_framework $?)
	(make_framework_subtask do_margins $?)
	(margins (left ?l) (right ?r) (top ?t) (bottom ?b) (side ?s))
	(not
		(ver_member (type LEFTMARGIN) (side ?s))
	)
	=>
	(assert (ver_member (type LEFTMARGIN) (x ?l) (number 0) (side ?s) (class MARGINS)))
	(assert (ver_member (type RIGHTMARGIN) (x ?r) (number 0) (side ?s) (class MARGINS)))
	(assert (hor_member (type TOPMARGIN) (y ?t) (number 0) (side ?s) (class MARGINS)))
	(assert (hor_member (type BOTTOMMARGIN) (y ?b) (number 0) (side ?s) (class MARGINS))))

; RULES FOR MAKING MEMBERS FROM PAGERECT DATA
(defrule make_members_from_pagerect
	(task make_framework $?)
	(make_framework_subtask do_pagerect $?)
	(pagerect (left ?l) (right ?r) (top ?t) (bottom ?b) (side ?s))
	(not
		(ver_member (type LEFTPAGE) (side ?s))
	)
	=>
	(assert (ver_member (type LEFTPAGE) (x ?l) (number 0) (side ?s) (class PAGERECT)))
	(assert (ver_member (type RIGHTPAGE) (x ?r) (number 0) (side ?s) (class PAGERECT)))
	(assert (hor_member (type TOPPAGE) (y ?t) (number 0) (side ?s) (class PAGERECT)))
	(assert (hor_member (type BOTTOMPAGE) (y ?b) (number 0) (side ?s) (class PAGERECT))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RULES FOR THE find_guide_neighbors TASK
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; RULES FOR DETERMINING THE NEAREST NEIGHBORS FOR GUIDES
; This way we can treat guides relative to whether they're in a
; column or a margin or whatever.
;

(defrule set_neighbor_defaults_vertical
	(task find_guide_neighbors $?)
	(find_guide_neighbors_subtask set_defaults $?)
	?vg <- (verguide (left_neighbor_number -1) (x ?x) (side ?s&~-1))
	(pagerect (side ?s) (left ?l) (right ?r))
	=>
	(modify ?vg (left_neighbor_number 0) (right_neighbor_number 0)
		(left_neighbor_distance =(- ?x ?l)) (right_neighbor_distance =(- ?r ?x))
		(left_neighbor_class PAGERECT) (right_neighbor_class PAGERECT)
		(left_neighbor_type LEFTPAGE) (right_neighbor_type RIGHTPAGE)))

(defrule set_neighbor_defaults_horizontal
	(task find_guide_neighbors $?)
	(find_guide_neighbors_subtask set_defaults $?)
	?hg <- (horguide (top_neighbor_number -1) (y ?y) (side ?s&~-1))
	(pagerect (side ?s) (top ?t) (bottom ?b))
	=>
	(modify ?hg (top_neighbor_number 0) (bottom_neighbor_number 0)
		(top_neighbor_distance =(- ?y ?t)) (bottom_neighbor_distance =(- ?b ?y))
		(top_neighbor_class PAGERECT) (bottom_neighbor_class PAGERECT)
		(top_neighbor_type TOPPAGE) (bottom_neighbor_type BOTTOMPAGE)))

(defrule find_nearer_neighbor_left
	(task find_guide_neighbors $?)
	(find_guide_neighbors_subtask find_closest $?)
	?vg <- (verguide (x ?gx) (left_neighbor_number ?nn&~-1) (left_neighbor_distance ?nd)
		(side ?s) (right_neighbor_distance ?nd2))
	(ver_member (class ?c&MARGINS|COLUMNS) (type ?t) (side ?s) 
		(x ?mx&:(and (< ?mx ?gx) (< (- ?gx ?mx) ?nd))) (number ?mn))
	=>
	(bind ?newdist (- ?gx ?mx))
	(modify ?vg (left_neighbor_number ?mn) (left_neighbor_class ?c) (left_neighbor_type ?t)
		(left_neighbor_distance ?newdist) (relpos =(/ ?newdist (+ ?newdist ?nd2)))))

(defrule give_margin_priority_as_left_neighbor
	(task find_guide_neighbors $?)
	(find_guide_neighbors_subtask find_closest $?)
	?vg <- (verguide (x ?gx) (left_neighbor_number ?nn&~-1) (left_neighbor_distance ?nd)
		(left_neighbor_class COLUMNS) (side ?s))
	(ver_member (class MARGINS) (type ?t) (side ?s) 
		(x ?mx&:(eq (- ?gx ?mx) ?nd)) (number ?mn))
	=>
	(modify ?vg (left_neighbor_number ?mn) (left_neighbor_class MARGINS) (left_neighbor_type ?t)))

(defrule find_nearer_neighbor_right
	(task find_guide_neighbors $?)
	(find_guide_neighbors_subtask find_closest $?)
	?vg <- (verguide (x ?gx) (right_neighbor_number ?nn&~-1) (right_neighbor_distance ?nd)
		(side ?s) (left_neighbor_distance ?nd2))
	(ver_member (class ?c&MARGINS|COLUMNS) (type ?t) (side ?s) 
		(x ?mx&:(and (> ?mx ?gx) (< (- ?mx ?gx) ?nd))) (number ?mn))
	=>
	(bind ?newdist (- ?mx ?gx))
	(modify ?vg (right_neighbor_number ?mn) (right_neighbor_class ?c) (right_neighbor_type ?t)
		(right_neighbor_distance ?newdist) 
		(relpos =(/ ?nd2 (+ ?newdist ?nd2)))
		))

(defrule give_column_priority_as_right_neighbor
	(task find_guide_neighbors $?)
	(find_guide_neighbors_subtask find_closest $?)
	?vg <- (verguide (x ?gx) (right_neighbor_number ?nn&~-1) (right_neighbor_distance ?nd)
		(right_neighbor_class MARGINS) (side ?s))
	(ver_member (class COLUMNS) (type ?t) (side ?s) 
		(x ?mx&:(eq (- ?mx ?gx) ?nd)) (number ?mn))
	=>
	(modify ?vg (right_neighbor_number ?mn) (right_neighbor_class COLUMNS) (right_neighbor_type ?t)))

(defrule find_nearer_neighbor_top
	(task find_guide_neighbors $?)
	(find_guide_neighbors_subtask find_closest $?)
	?hg <- (horguide (y ?gy) (top_neighbor_number ?nn&~-1) (top_neighbor_distance ?nd)
		(side ?s) (bottom_neighbor_distance ?nd2))
	(hor_member (class ?c&MARGINS|COLUMNS) (type ?t) (side ?s) 
		(y ?my&:(and (< ?my ?gy) (< (- ?gy ?my) ?nd))) (number ?mn))
	=>
	(bind ?newdist (- ?gy ?my))
	(modify ?hg (top_neighbor_number ?mn) (top_neighbor_class ?c) (top_neighbor_type ?t)
		(top_neighbor_distance ?newdist) (relpos =(/ ?newdist (+ ?newdist ?nd2)))))

(defrule find_nearer_neighbor_bottom
	(task find_guide_neighbors $?)
	(find_guide_neighbors_subtask find_closest $?)
	?hg <- (horguide (y ?gy) (bottom_neighbor_number ?nn&~-1) (bottom_neighbor_distance ?nd)
		(side ?s) (top_neighbor_distance ?nd2))
	(hor_member (class ?c&MARGINS|COLUMNS) (type ?t) (side ?s) 
		(y ?my&:(and (> ?my ?gy) (< (- ?my ?gy) ?nd))) (number ?mn))
	=>
	(bind ?newdist (- ?my ?gy))
	(modify ?hg (bottom_neighbor_number ?mn) (bottom_neighbor_class ?c) (bottom_neighbor_type ?t)
		(bottom_neighbor_distance ?newdist) 
		(relpos =(/ ?nd2 (+ ?newdist ?nd2)))
		))

(defrule give_margin_priority_as_bottom_neighbor
	(task find_guide_neighbors $?)
	(find_guide_neighbors_subtask find_closest $?)
	?hg <- (horguide (y ?gy) (top_neighbor_number ?nn&~-1) (top_neighbor_distance ?nd)
		(top_neighbor_class COLUMNS) (side ?s))
	(hor_member (class MARGINS) (type ?t) (side ?s) 
		(y ?my&:(eq (- ?gy ?my) ?nd)) (number ?mn))
	=>
	(modify ?hg (top_neighbor_number ?mn) (top_neighbor_class MARGINS) (top_neighbor_type ?t)))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RULES FOR THE fit_objects TASK
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RULES FOR FITTING OBJECT EDGES TO FRAMEWORK MEMBERS
; Determine which parts of objects align to which framework members.
;

; simple rule for determining which side an object is on (left-most page it occupies)
(defrule simple_page_occupancy
	(task make_framework $?)
	(make_framework_subtask setup_bleeds $?)
	?o <- (item (left ?l) (right ?r) (side ?s))
	(pagerect (left ?pl&:(> (/ (+ ?l ?r) 2.0) ?pl)) (side ?ps&:(> ?ps ?s)))
	=>
	(modify ?o (side ?ps))
	)
	
; experimental rules for altering the priority of columns and margins in some cases
(defrule special_fit_right_rightmargin
	(task fit_objects $?)
	(framework_class MARGINS $?)
	(margins (right ?x1) (side ?s))
	(prefs (autosnapzone ?asz))								;added for bug
	?o <- (item (right ?x2) (right_aligns_to COLRIGHT) (right_aligns_obj_num ?rn)
		(left_aligns_to ?lt) (left_aligns_obj_num ?ln) (left_aligns_side ?s))
	=>
	(if (<= (abs (- ?x1 ?x2)) ?asz)
	 then
	(if (not (and (eq ?rn ?ln) (eq ?lt COLLEFT)))
		then
			(modify ?o (right_aligns_to RIGHTMARGIN) (right_aligns_obj_num 0))
	)))

(defrule special_fit_bottom_bottommargin
	(task fit_objects $?)
	(framework_class MARGINS $?)
	(margins (bottom ?y1) (side ?s))
	(columninfo (horizdir 1) (side ?s))
	(prefs (autosnapzone ?asz))								;added for bug
	?o <- (item (bottom ?y2) (bottom_aligns_to COLBOTTOM) (bottom_aligns_obj_num ?bn)
		(top_aligns_to ?tt) (top_aligns_obj_num ?tn) (left_aligns_side ?s) )
	=>
	(if (<= (abs (- ?y1 ?y2)) ?asz)
	 then
	(if (not (and (eq ?bn ?tn) (eq ?tt COLTOP)))
		then
			(modify ?o (bottom_aligns_to BOTTOMMARGIN) (bottom_aligns_obj_num 0))
	)))

; let margin win if left side of object aligns with right margin and right side of column
(defrule special_fit_left_rightmargin
	(task fit_objects $?)
	(framework_class MARGINS $?)
	(margins (right ?x1))
	?o <- (item (left ?x2) (left_aligns_to COLRIGHT))
	(prefs (autosnapzone ?asz))								;added for bug
	=>
	(if (<= (abs (- ?x1 ?x2)) ?asz)
	 then
	(modify ?o (left_aligns_to RIGHTMARGIN) (left_aligns_obj_num 0))
	))

(defrule special_fit_top_bottommargin
	(task fit_objects $?)
	(framework_class MARGINS $?)
	(margins (bottom ?y1) (side ?s))
	(columninfo (horizdir 1) (side ?s))
	?o <- (item (top ?y2) (top_aligns_to COLBOTTOM))
	(prefs (autosnapzone ?asz))								;added for bug
	=>
	(if (<= (abs (- ?y1 ?y2)) ?asz)
	 then
	(modify ?o (top_aligns_to BOTTOMMARGIN) (top_aligns_obj_num 0))
	))

; standard object-fitting rules	
(defrule fit_left
	(task fit_objects $?)
	(framework_class ?fc $?)
	?o <- (item (left ?x1) (left_aligns_to none))
	(ver_member (type ?t&~none&~RIGHTPAGE) (x ?x2) (number ?n) (side ?s) (class ?fc))
	(prefs (autosnapzone ?asz)) 
	=>
	(if (<= (abs (- ?x1 ?x2)) ?asz)
	 then
		(modify ?o (left_aligns_to ?t) (left_aligns_obj_num ?n) (left_aligns_side ?s))
	))

(defrule fit_right
	(task fit_objects $?)
	(framework_class ?fc $?)
	?o <- (item (right ?x1) (right_aligns_to none))
	(ver_member (type ?t&~none&~LEFTPAGE) (x ?x2) (number ?n) (side ?s) (class ?fc))
	(prefs (autosnapzone ?asz)) 
	=>
	(if (<= (abs (- ?x1 ?x2)) ?asz)
	 then
		(modify ?o (right_aligns_to ?t) (right_aligns_obj_num ?n) (right_aligns_side ?s))
	)) 

(defrule fit_top_to_pasteboard_guide
	(task fit_objects $?)
	(framework_class ?fc $?)
	?o <- (item (top ?y1) (top_aligns_to none))
	; note: side==-1 means it's a pasteboard guide
	(hor_member (type ?t&~none) (y ?y2) (number ?n) (side -1) (class ?fc))
	(prefs (autosnapzone ?asz)) 
	=>
	(if (<= (abs (- ?y1 ?y2)) ?asz)
	 then
		(modify ?o (top_aligns_to ?t) (top_aligns_obj_num ?n) (top_aligns_side -1))
	)) 

(defrule fit_bottom_to_pasteboard_guide
	(task fit_objects $?)
	(framework_class ?fc $?)
	?o <- (item (bottom ?y1) (bottom_aligns_to none))
	(hor_member (type ?t&~none) (y ?y2) (number ?n) (side -1) (class ?fc))
	(prefs (autosnapzone ?asz)) 
;	(spread (pages ?pgs))
	=>
	(if (<= (abs (- ?y1 ?y2)) ?asz)
	 then
		(modify ?o (bottom_aligns_to ?t) (bottom_aligns_obj_num ?n) (bottom_aligns_side -1))
	)) 

; todo: determine whether this rule is redundant w/ following one
(defrule fit_top_1_page_spread
	(task fit_objects $?)
	(framework_class ?fc $?)
	(spread (pages 1) (onepgside ?s))
	?o <- (item (top ?y1) (top_aligns_to none))
	(hor_member (type ?t&~none) (y ?y2) (number ?n) (side ?s) (class ?fc))
	(prefs (autosnapzone ?asz)) 
	=>
	(if (<= (abs (- ?y1 ?y2)) ?asz)
	 then
		(modify ?o (top_aligns_to ?t) (top_aligns_obj_num ?n) (top_aligns_side ?s))
	)) 

(defrule fit_top_2_page_spread
	(task fit_objects $?)
	(framework_class ?fc $?)
	(spread (pages ?pgs&~1))
	?o <- (item (top ?y1) (left ?l) (right ?r) (top_aligns_to none))
	(hor_member (type ?t&~none) (y ?y2) (number ?n) (side ?s) (class ?fc))
	(pagerect (left ?prl&:(< ?prl ?r)) (right ?prr&:(> ?prr ?l)) (side ?s))
	(prefs (autosnapzone ?asz)) 
	=>
	(if (<= (abs (- ?y1 ?y2)) ?asz)
	 then
		(modify ?o (top_aligns_to ?t) (top_aligns_obj_num ?n) (top_aligns_side ?s))
	)) 

(defrule fit_bottom_1_page_spread
	(task fit_objects $?)
	(framework_class ?fc $?)
	(spread (pages 1))	; (onepgside ?s))
	(pagerect (side ?s))
	?o <- (item (bottom ?y1) (bottom_aligns_to none) (side ?s))
	(hor_member (type ?t&~none) (y ?y2) (number ?n) (side ?s) (class ?fc))
	(prefs (autosnapzone ?asz)) 
	=>
	(if (<= (abs (- ?y1 ?y2)) ?asz)
		then (modify ?o (bottom_aligns_to ?t) (bottom_aligns_obj_num ?n) (bottom_aligns_side ?s)) 
	))

(defrule fit_bottom_2_page_spread
	(task fit_objects $?)
	(framework_class ?fc $?)
	(spread (pages ?pgs&~1))
	(prefs (autosnapzone ?asz)) 
	(hor_member (type ?t&~none) (y ?y2) (number ?n) (side ?s) (class ?fc))
	?o <- (item (bottom ?y1&:(> ?asz (abs (- ?y1 ?y2)))) (bottom_aligns_to none) (side ?s))
;	(pagerect (left ?prl&:(< ?prl ?r)) (right ?prr&:(> ?prr ?l)) (bottom ?prb&:(>= ?prb ?y1)) (side ?s))
	(pagerect  (side ?s))	; (bottom ?prb&:(< ?prb ?y1)) (side ?s))
	=>
		(modify ?o (bottom_aligns_to ?t) (bottom_aligns_obj_num ?n) (bottom_aligns_side ?s)) 
	)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RULES FOR THE change_page_info TASK
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RULE FOR ESTABLISHING NEW PAGE INFORMATION

(defrule new_pagerect_info
	(task change_page_info $?)
	?pr <- (pagerect (width ?ow) (height ?oh) (state 1) (side ?s))
	?npr <- (pagerect_new (left ?l) (right ?r) (top ?t) (bottom ?b) (side ?s))
	?spr <- (spread (width ?sw) (height ?sh) (width_old ?swo) (height_old ?sho))
	=>
	(bind ?w (- ?r ?l))
	(bind ?h (- ?b ?t))
	(modify ?pr (left ?l) (right ?r) (top ?t) (bottom ?b)
				(width ?w) (height ?h) 
				(width_old ?ow) (height_old ?oh) (state 2))
	(modify ?spr (width =(+ ?sw ?w)) (height ?h) 
				 (width_old =(+ ?swo ?ow)) (height_old ?oh)))

(defrule new_1_page_spread_info
	(task change_page_info $?)
	?spr <- (spread (pages 1) (state 0) (left ?lo) (right ?ro) (top ?to) (bottom ?bo))
	(pagerect (left ?l) (right ?r) (top ?t) (bottom ?b) (state 2))
	=>
	(modify ?spr (left ?l) (right ?r) (top ?t) (bottom ?b) (state 1)
		(left_old ?lo) (right_old ?ro) (top_old ?to) (bottom_old ?bo)))

(defrule new_2_page_spread_info
	(task change_page_info $?)
	?spr <- (spread (pages ?pgs&~1) (state 0) (left ?lo) (right ?ro) (top ?to) (bottom ?bo))
	(pagerect (left ?l1) (right ?r1) (top ?t1) (bottom ?b1) (state 2) (side 0))
	(pagerect (left ?l2) (right ?r2) (top ?t2) (bottom ?b2) (state 2) (side ?s&:(eq ?pgs (+ 1 ?s))))
	=>
	(modify ?spr (left ?l1) (right ?r2) (top ?t1) (bottom ?b1) (state 1)
		(left_old ?lo) (right_old ?ro) (top_old ?to) (bottom_old ?bo)))

(defrule new_margins_info
	(task change_page_info $?)
	?m <- (margins (state 0) (side ?s))
	?nm <- (margins_new (left ?l) (right ?r) (top ?t) (bottom ?b) (side ?s))
	=>
	(modify ?m (left ?l) (right ?r) (top ?t) (bottom ?b) (state 1)))

(defrule new_column_info
	(task change_page_info $?)
	?ci <- (columninfo (numcolumns ?nc) (gutter ?g) (state 0) (side ?s) (horizdir ?hdo))
	(columninfo_new (numcolumns ?ncn) (gutter ?gn) (side ?s) (horizdir ?hdn))
	=>
	(if (> ?ncn ?nc)
		then (bind ?cd MORE)
		else (if (< ?ncn ?nc)
				then (bind ?cd FEWER)
				else (bind ?cd SAME)
			 )
	)
	(bind ?dc SAME)
	(if (neq ?hdo ?hdn)
		then (if (eq ?hdo 0)
			then (bind ?dc TOHOR)
			else (bind ?dc TOVER)
		)
	)
	(modify ?ci (numcolumns ?ncn) (gutter ?gn) (columndifference ?cd) 
		(numcolumns_old ?nc) (horizdir ?hdn) (dirchange ?dc) (state 1)))	

(defrule new_column
	(task change_page_info $?)
	?tcol <- (textcolumn (colnumber ?cn) (state 0) (side ?s))
	(textcolumn_new (colnumber ?cn) (left ?l) (right ?r) (side ?s))
	=>
	(modify ?tcol (left ?l) (right ?r) (state 1)))	

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RULES FOR THE handle_direction_change TASK
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Switching a textframe's directionality -- horizontal to vertical and v.v.
;
(defrule handle_direction_change_to_hor
	(task handle_direction_change $?)
	(columninfo (dirchange ?dc&TOHOR) (side ?s))
	?obj <- (item (left_aligns_to COLLEFT) (right_aligns_to COLRIGHT)
		(left_aligns_obj_num ?n) (right_aligns_obj_num ?n)
		(left_aligns_side ?s) (right_aligns_side ?s)
		(top_aligns_to TOPMARGIN) (bottom_aligns_to BOTTOMMARGIN)
		(top_aligns_side ?s) (bottom_aligns_side ?s))
	(textcolumn_new (side ?s) (colnumber ?n) (left ?l) (right ?r))
	=>
	(modify ?obj (left_aligns_to LEFTMARGIN) (right_aligns_to RIGHTMARGIN)
		(top_aligns_to COLTOP) (bottom_aligns_to COLBOTTOM)
		(left_aligns_obj_num 0) (right_aligns_obj_num 0)
		(top_aligns_obj_num ?n) (bottom_aligns_obj_num ?n))
	(assert (hor_member (type COLTOP) (y ?l) (number ?n) (side ?s) (class COLUMNS) (state 1)))
	(assert (hor_member (type COLBOTTOM) (y ?r) (number ?n) (side ?s) (class COLUMNS) (state 1)))
	)

(defrule handle_direction_change_to_ver
	(task handle_direction_change $?)
	(columninfo (dirchange ?dc&TOVER) (side ?s))
	?obj <- (item (top_aligns_to COLTOP) (bottom_aligns_to COLBOTTOM)
		(top_aligns_obj_num ?n) (bottom_aligns_obj_num ?n)
		(top_aligns_side ?s) (bottom_aligns_side ?s)
		(left_aligns_to LEFTMARGIN) (right_aligns_to RIGHTMARGIN)
		(left_aligns_side ?s) (right_aligns_side ?s))
	(textcolumn_new (side ?s) (colnumber ?n) (left ?l) (right ?r))
	=>
	(modify ?obj (left_aligns_to COLLEFT) (right_aligns_to COLRIGHT)
		(top_aligns_to TOPMARGIN) (bottom_aligns_to BOTTOMMARGIN)
		(left_aligns_obj_num ?n) (right_aligns_obj_num ?n)
		(top_aligns_obj_num 0) (bottom_aligns_obj_num 0))
	(assert (ver_member (type COLLEFT) (x ?l) (number ?n) (side ?s) (class COLUMNS) (state 1)))
	(assert (ver_member (type COLRIGHT) (x ?r) (number ?n) (side ?s) (class COLUMNS) (state 1)))
	)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RULES FOR THE rebuild_framework TASK
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RULES FOR REBUILDING THE FRAMEWORK AFTER CHANGING THE PAGE INFO
; We modify facts from 'new' info in xxx_new data

(defrule new_members_from_pagerect
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_pagerect $?)
	?pr <- (pagerect (left ?l) (right ?r) (top ?t) (bottom ?b) (state 2) (side ?s))
	?vml <- (ver_member (type LEFTPAGE) (side ?s))
	?vmr <- (ver_member (type RIGHTPAGE) (side ?s))
	?hmt <- (hor_member (type TOPPAGE) (side ?s))
	?hmb <- (hor_member (type BOTTOMPAGE) (side ?s))
	=>
	(modify ?pr (state 3))
	(modify ?vml (x ?l) (state 1))
	(modify ?vmr (x ?r) (state 1))
	(modify ?hmt (y ?t) (state 1))
	(modify ?hmb (y ?b) (state 1)))


; following 2 rules rely on a 1-to-1 correspondence
; between a guide and a framework member that represents it

(defrule new_verguides_page_proportional
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_guides $?)
	(prefs (moveGuides 1) (loosenLocks ?ll))
	; disallow loosenLocks==0 && guideLocked==1
	?vg <- (verguide (original_location 1) (x ?x) (relpos ?rp) (side -1) (locked ?gl&:(>= ?ll ?gl)))
	(pagerect (left_old ?l&:(>= ?x ?l)) (right_old ?r&:(<= ?x ?r)) 
		(left ?ln) (right ?rn) (state 3))
	?vm <- (ver_member (type VERGUIDE) (x ?x) (side -1) (state 0))
	=>
	(bind ?w (- ?rn ?ln))
	(bind ?val (+ ?ln (* ?rp ?w)))
	(modify ?vg (x ?val) (original_location 0))
	(modify ?vm (x ?val) (state 1)))

(defrule new_horguides_page_proportional
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_guides $?)
	(prefs (moveGuides 1) (loosenLocks ?ll))
	; disallow loosenLocks==0 && guideLocked==1
	?hg <- (horguide (original_location 1) (y ?y) (side -1) (relpos ?rp) (locked ?gl&:(>= ?ll ?gl)))
	(pagerect (top_old ?t&:(>= ?y ?t)) (bottom_old ?b&:(<= ?y ?b)) (top ?tn) (bottom ?bn) (state 3))
	?hm <- (hor_member (type HORGUIDE) (y ?y) (side -1) (state 0))
	=>
	(bind ?h (- ?bn ?tn))
	(bind ?val (+ ?tn (* ?rp ?h)))
	(modify ?hg (y ?val) (original_location 0))
	(modify ?hm (y ?val) (state 1)))


(defrule new_verguides_locally_proportional
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_guides $?)
	(prefs (moveGuides 1) (loosenLocks ?ll))
	; disallow loosenLocks==0 && guideLocked==1
	?vg <- (verguide (original_location 1) (x ?x) (relpos ?rp) (locked ?gl&:(>= ?ll ?gl))
		(left_neighbor_type ?lt) (left_neighbor_number ?ln)
		(right_neighbor_type ?rt) (right_neighbor_number ?rn) (side ?s))
	?vm <- (ver_member (type VERGUIDE) (x ?x) (side ?s) (state 0))
	(pagerect (left_old ?l&:(>= ?x ?l)) (side ?s) (right_old ?r&:(<= ?x ?r)) (state 3))
	(ver_member (x ?lx) (type ?lt) (number ?ln) (side ?s) (state 1))
	(ver_member (x ?rx) (type ?rt) (number ?rn) (side ?s) (state 1))
	=>
	(bind ?w (- ?rx ?lx))
	(bind ?val (+ ?lx (* ?rp ?w)))
	(modify ?vg (x ?val) (original_location 0) (debug 99.9))
	(modify ?vm (x ?val) (state 1)))

(defrule new_horguides_locally_proportional_1pg
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_guides $?)
	(prefs (moveGuides 1) (loosenLocks ?ll))
	; disallow loosenLocks==0 && guideLocked==1
	(pagerect (top_old ?t) (bottom_old ?b) (state 3))
	?hg <- (horguide (original_location 1) (y ?y) (side ?s) (relpos ?rp) (locked ?gl&:(>= ?ll ?gl))
		(top_neighbor_type ?tt) (top_neighbor_number ?tn)
		(bottom_neighbor_type ?bt) (bottom_neighbor_number ?bn))
	?hm <- (hor_member (type HORGUIDE) (y ?y) (side ?s) (state 0))
	(hor_member (y ?ty) (type ?tt) (number ?tn) (side ?s) (state 1))
	(hor_member (y ?by) (type ?bt) (number ?bn) (side ?s) (state 1))
	=>
	(bind ?h (- ?by ?ty))
	(bind ?val (+ ?ty (* ?rp ?h)))
	(modify ?hg (y ?val) (original_location 0))
	(modify ?hm (y ?val) (state 1)))

(defrule new_ver_guides_matching_margin_members
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_guides_matching_margins $?)
	(prefs (moveGuides 1) (stickyGuides 1) (loosenLocks ?ll))
	(margins (left ?l) (right ?r) (state 1) (side ?s))
	(ver_member (class MARGINS) (type ?type) (x ?oldx1) (state 0) (side ?s))
	?vm <- (ver_member (class GUIDES) (x ?oldx) (state 0))
	?vg <- (verguide (x ?oldx) (original_location 1) (locked ?gl&:(>= ?ll ?gl)))
	(prefs (autosnapzone ?asz&:(> ?asz (abs (- ?oldx ?oldx1))))) 
	=>
	(bind ?hit 0)
	(if (eq ?type LEFTMARGIN)
		then (bind ?xval ?l)
			 (bind ?hit 1)
		else (if (eq ?type RIGHTMARGIN)
				then (bind ?xval ?r)
					 (bind ?hit 1)
			 )
	)
	(if (eq ?hit 1)
		then
			(modify ?vm (x ?xval) (state 1))
			(modify ?vg (x ?xval) (original_location 0))
	))

(defrule new_hor_guides_matching_margin_members_1pg
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_guides_matching_margins $?)
	(prefs (moveGuides 1) (stickyGuides 1) (loosenLocks ?ll))
;	(spread (pages 1))
	(margins (top ?t) (bottom ?b) (state 1) (side ?s))
	(hor_member (class MARGINS) (type ?type) (y ?oldy1) (state 0) (side ?s))
	?hm <- (hor_member (class GUIDES) (y ?oldy) (state 0) (side ?s))
	?hg <- (horguide (y ?oldy) (original_location 1) (side ?s) (locked ?gl&:(>= ?ll ?gl)))
	(prefs (autosnapzone ?asz&:(> ?asz (abs (- ?oldy ?oldy1))))) 
	=>
	(bind ?hit 0)
	(if (eq ?type TOPMARGIN)
		then (bind ?yval ?t)
			 (bind ?hit 1)
		else (if (eq ?type BOTTOMMARGIN)
				then (bind ?yval ?b)
					 (bind ?hit 1)
			 )
	)
	(if (eq ?hit 1)
		then
			(modify ?hm (y ?yval) (state 1))
			(modify ?hg (y ?yval) (original_location 0))
	))

;(defrule new_hor_guides_matching_margin_members_2pg
;	(task rebuild_framework $?)
;	(rebuild_framework_subtask do_guides_matching_margins $?)
;	(prefs (moveGuides 1) (stickyGuides 1))
;	(spread (pages 2))
;	(margins (top ?t) (bottom ?b) (state 1) (side ?s))
;	(hor_member (class MARGINS) (type ?type) (y ?oldy1) (state 0) (side ?s))
;	?hm1 <- (hor_member (class GUIDES) (y ?oldy) (side 0) (state 0))
;	?hm2 <- (hor_member (class GUIDES) (y ?oldy) (side 1) (state 0))
;	?hg <- (horguide (y ?oldy) (original_location 1))
;	(prefs (autosnapzone ?asz&:(> ?asz (abs (- ?oldy ?oldy1))))) 
;	=>
;	(bind ?hit 0)
;	(if (eq ?type TOPMARGIN)
;		then (bind ?yval ?t)
;			 (bind ?hit 1)
;		else (if (eq ?type BOTTOMMARGIN)
;				then (bind ?yval ?b)
;					 (bind ?hit 1)
;			 )
;	)
;	(if (eq ?hit 1)
;		then
;			(modify ?hm1 (y ?yval) (state 1))
;			(modify ?hm2 (y ?yval) (state 1))
;			(modify ?hg (y ?yval) (original_location 0))
;	))

(defrule new_margin_members
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_margins $?)
	?m <- (margins (left ?l) (right ?r) (top ?t) (bottom ?b) (state 1) (side ?s))
	?vml <- (ver_member (type LEFTMARGIN) (x ?oldl) (side ?s) (state 0))
	?vmr <- (ver_member (type RIGHTMARGIN) (x ?oldr) (side ?s) (state 0))
	?vmt <- (hor_member (type TOPMARGIN) (y ?oldt) (side ?s) (state 0))
	?vmb <- (hor_member (type BOTTOMMARGIN) (y ?oldb) (side ?s) (state 0))
	=>
	(modify ?m (state 2))
	(modify ?vml (x ?l) (state 1))
	(modify ?vmr (x ?r) (state 1))
	(modify ?vmt (y ?t) (state 1))
	(modify ?vmb (y ?b) (state 1)))


(defrule new_ver_guides_matching_textcolumn_members
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_guides_matching_columns $?)
	(prefs (moveGuides 1) (stickyGuides 1) (loosenLocks ?ll))
	(columninfo (horizdir 0) (side ?s))
	(textcolumn (colnumber ?tcn) (left ?l) (right ?r) (state 1) (side ?s))
	(ver_member (class COLUMNS) (type ?type) (number ?tcn) (x ?oldx1) (state 0) (side ?s))
	?vm <- (ver_member (class GUIDES) (x ?oldx) (state 0))
	?vg <- (verguide (x ?oldx) (original_location 1) (locked ?gl&:(>= ?ll ?gl)))
	(prefs (autosnapzone ?asz&:(> ?asz (abs (- ?oldx ?oldx1))))) 
	=>
	(if (eq ?type COLLEFT)
		then (bind ?xval ?l)
		else (bind ?xval ?r)
	)
	(modify ?vm (x ?xval) (state 1))
	(modify ?vg (x ?xval) (original_location 0))
	)

(defrule new_hor_guides_matching_textcolumn_members
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_guides_matching_columns $?)
	(prefs (moveGuides 1) (stickyGuides 1) (loosenLocks ?ll))
	(columninfo (horizdir 1) (side ?s))
	(textcolumn (colnumber ?tcn) (left ?l) (right ?r) (state 1) (side ?s))
	(hor_member (class COLUMNS) (type ?type) (number ?tcn) (y ?oldy1) (state 0) (side ?s))
	?hm <- (hor_member (class GUIDES) (y ?oldy) (state 0))
	?hg <- (horguide (y ?oldy) (original_location 1) (locked ?gl&:(>= ?ll ?gl)))
	(prefs (autosnapzone ?asz&:(> ?asz (abs (- ?oldy ?oldy1))))) 
	=>
	(if (eq ?type COLTOP)
		then (bind ?yval ?l)
		else (bind ?yval ?r)
	)
	(modify ?hm (y ?yval) (state 1))
	(modify ?hg (y ?yval) (original_location 0))
	)


(defrule new_textcolumn_members
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_columns $?)
	(columninfo (horizdir 0) (side ?s))
	?tc <- (textcolumn (colnumber ?tcn) (left ?l) (right ?r) (state 1) (side ?s))
	?vml <- (ver_member (type COLLEFT) (number ?tcn) (side ?s))
	?vmr <- (ver_member (type COLRIGHT) (number ?tcn) (side ?s))
	=>
	(modify ?tc (state 2))
	(modify ?vml (x ?l) (state 1))
	(modify ?vmr (x ?r) (state 1)))

(defrule new_textcolumn_members_hor
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_columns $?)
	(columninfo (horizdir 1) (side ?s))
	?tc <- (textcolumn (colnumber ?tcn) (left ?l) (right ?r) (state 1) (side ?s))
	?hmt <- (hor_member (type COLTOP) (number ?tcn) (side ?s))
	?hmb <- (hor_member (type COLBOTTOM) (number ?tcn) (side ?s))
	=>
	(modify ?tc (state 2))
	(modify ?hmt (y ?l) (state 1))
	(modify ?hmb (y ?r) (state 1)))

(defrule new_left_bleed_members
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_bleeds $?)
	?bl <- (ver_member (type LBLEED) (state 0) (x ?x))
	(spread (left ?l) (left_old ?lo))
	(pasteboard (left ?pbl))
	=>
	(bind ?minbl (- ?pbl ?l))
	(bind ?wantbl (- ?x ?lo))
	(modify ?bl (x =(+ ?l (max ?minbl ?wantbl))) (state 1)))

(defrule new_right_bleed_members
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_bleeds $?)
	?br <- (ver_member (type RBLEED) (state 0) (x ?x))
	(spread (right ?r) (right_old ?ro))
	(pasteboard (right ?pbr))
	=>
	(bind ?maxbr (- ?pbr ?r))
	(bind ?wantbr (- ?x ?ro))
	(modify ?br (x =(+ ?r (min ?maxbr ?wantbr))) (state 1)))

(defrule new_top_bleed_members
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_bleeds $?)
	?bt <- (hor_member (type TBLEED) (state 0) (y ?y) (side ?ts))
;	(spread (top ?t) (top_old ?to))
	(pagerect (top ?t) (top_old ?to) (side ?ts))
	(pasteboard (top ?pbt))
	=>				
	(bind ?minbt -99999) ;(- ?pbt ?t))
	(bind ?wantbt (- ?y ?to))
	(modify ?bt (y =(+ ?t (max ?minbt ?wantbt))) (state 1)))

(defrule new_bottom_bleed_members
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_bleeds $?)
	?bb <- (hor_member (type BBLEED) (state 0) (y ?y) (side ?bs))
;	(spread (bottom ?b) (bottom_old ?bo))
	(pagerect (bottom ?b) (bottom_old ?bo) (side ?bs))
	(pasteboard (bottom ?pbb))
	=>
	(bind ?maxbb 99999)	;(- ?pbb ?b))
	(bind ?wantbb (- ?y ?bo))
	(modify ?bb (y =(+ ?b (min ?maxbb ?wantbb))) (state 1)))

; rules to rebuild off-page guide members
(defrule new_left_offpage_guide_members
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_guides $?)
	(prefs (loosenLocks ?ll))
	?opg <- (ver_member (type OFFPAGELVERGUIDE) (state 0) (x ?x))
	?vg <- (verguide (x ?x) (original_location 1) (locked ?gl&:(>= ?ll ?gl)))
	(spread (left ?l) (left_old ?lo))
	(pasteboard (left ?pbl))
	=>
	(bind ?minbl (- ?pbl ?l))
	(bind ?wantbl (- ?x ?lo))
	(modify ?opg (x =(+ ?l (max ?minbl ?wantbl))) (state 1))
	(modify ?vg (original_location 0) (x =(+ ?l (max ?minbl ?wantbl)))))

(defrule new_right_offpage_guide_members
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_guides $?)
	(prefs (loosenLocks ?ll))
	?opg <- (ver_member (type OFFPAGERVERGUIDE) (state 0) (x ?x))
	?vg <- (verguide (x ?x) (original_location 1) (locked ?gl&:(>= ?ll ?gl)))
	(spread (right ?r) (right_old ?ro))
	(pasteboard (right ?pbr))
	=>
	(bind ?maxbr (- ?pbr ?r))
	(bind ?wantbr (- ?x ?ro))
	(modify ?opg (x =(+ ?r (min ?maxbr ?wantbr))) (state 1))
	(modify ?vg (original_location 0) (x =(+ ?r (min ?maxbr ?wantbr)))))

(defrule new_top_offpage_guide_members
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_guides $?)
	(prefs (loosenLocks ?ll))
	?opg <- (hor_member (type OFFPAGETHORGUIDE) (state 0) (y ?y))
	?hg <- (horguide (y ?y) (original_location 1) (locked ?gl&:(>= ?ll ?gl)))
	(spread (top ?t) (top_old ?to))
	(pasteboard (top ?pbt))
	=>				
	(bind ?minbt (- ?pbt ?t))
	(bind ?wantbt (- ?y ?to))
	(modify ?opg (y =(+ ?t (max ?minbt ?wantbt))) (state 1))
	(modify ?hg (original_location 0) (y =(+ ?t (max ?minbt ?wantbt)))))

(defrule new_bottom_offpage_guide_members
	(task rebuild_framework $?)
	(rebuild_framework_subtask do_guides $?)
	(prefs (loosenLocks ?ll))
	?opg <- (hor_member (type OFFPAGEBHORGUIDE) (state 0) (y ?y))
	?hg <- (horguide (y ?y) (original_location 1) (locked ?gl&:(>= ?ll ?gl)))
	(spread (bottom ?b) (bottom_old ?bo))
	(pasteboard (bottom ?pbb))
	=>
	(bind ?maxbb (- ?pbb ?b))
	(bind ?wantbb (- ?y ?bo))
	(modify ?opg (y =(+ ?b (min ?maxbb ?wantbb))) (state 1))
	(modify ?hg (original_location 0) (y =(+ ?b (min ?maxbb ?wantbb)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RULES FOR THE relocate_objects TASK
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RULES FOR RELOCATING AN OBJECT AFTER THE FRAMEWORK HAS CHANGED
; Items previously aligned to framework members must have their
; coordinates changed, now that the framework has changed.  This is the
; crux of the rulebase's activity, though few rules are needed in this
; task.

(defrule relocate_object_leftright
	(task relocate_objects $?)
	(prefs (stretchGraphics ?sg))
	?obj <- (item (original_leftright true)
			(left ?objl) (right ?objr) 
			(left_aligns_to ?lt)
			(right_aligns_to ?rt)
			(left_aligns_obj_num ?ln)
			(right_aligns_obj_num ?rn)
			(right_aligns_side ?rs)
			(left_aligns_side ?ls)
			(segtype ?segtype)
			(side ?objs))
	(ver_member (type ?lt) (number ?ln) (x ?vm1) (side ?ls))
	(ver_member (type ?rt) (number ?rn) (x ?vm2) (side ?rs))
	(pagerect (side ?objs) (width ?psw) (width_old ?pswo) (left_old ?pglo) (left ?pgl))
	=>
	(if (neq ?lt none)
		then
			; left is aligned to the framework -- bind it to ?l
			(bind ?l ?vm1)
			; if aligned and either text or (graphic and stretching graphics OK)
			(if (and (neq ?rt none) (or (and (eq ?segtype 6) (eq ?sg 1 )) (neq ?segtype 6)))
				then
					; right is aligned to the framework -- bind it to ?r
					(bind ?r ?vm2)
				else
					; just the left is aligned to the framework
					; offset the right by the left delta (i.e., move)
					(bind ?dl (- ?vm1 ?objl))
					(bind ?r (+ ?objr ?dl))
			)
		else
			(if (neq ?rt none)
				then
					; right is aligned to the framework -- bind it to ?r
					(bind ?r ?vm2)
					; and offset the left by the right delta
					(bind ?dr (- ?vm2 ?objr))
					(bind ?l (+ ?objl ?dr))
				else
					; neither left nor right are on the framework
					; move object but keep its center proportionately located on page
					; later, here is a good place to know about in-margin-ness, etc.
					(bind ?oldcenter (- (/ (+ ?objl ?objr) 2.0) ?pglo))		; wrt left of spread
					(bind ?oldcenterrelpos (/ ?oldcenter ?pswo))
					(bind ?newcenter (* ?oldcenterrelpos ?psw))
					(bind ?halfwidth (/ (- ?objr ?objl) 2.0))
					(bind ?l (+ ?pgl (- ?newcenter ?halfwidth)))
					(bind ?r (+ ?pgl (+ ?newcenter ?halfwidth)))
;
;					(bind ?deltax (- ?newcenter ?oldcenter))
;					(bind ?l (+ ?objl ?deltax))
;					(bind ?r (+ ?objr ?deltax))

			)
	)
	(modify ?obj (left ?l) (right ?r) (original_leftright false)))

(defrule relocate_object_topbottom
	(task relocate_objects $?)
	(prefs (stretchGraphics ?sg))
	?obj <- (item (original_topbottom true)
			(top ?objt) (bottom ?objb)
			(top_aligns_to ?tt)
			(bottom_aligns_to ?bt)
			(top_aligns_obj_num ?tn)
			(bottom_aligns_obj_num ?bn)
			(top_aligns_side ?ts)
			(bottom_aligns_side ?bs)
			(segtype ?segtype)
			(side ?objs))
	(hor_member (type ?tt) (number ?tn) (y ?hm1) (side ?ts))
	(hor_member (type ?bt) (number ?bn) (y ?hm2) (side ?bs) (class ?bc))
;	(pagerect (height ?psh) (height_old ?psho) (side ?ts))
	(pagerect (side ?objs) (height ?psh) (height_old ?psho) (top_old ?opgt) (top ?pgt))
	=>
	(if (neq ?tt none)
		then
			; top is aligned to the framework -- bind it to ?t
			(bind ?t ?hm1)
			(if (and (neq ?bt none) (or (neq ?segtype 6) (and (eq ?segtype 6) (eq ?sg 1))))
				then
					; If the bottom is aligned to the framework;
					; and it's either:
					;	 a textblock, 
					; 	 or a graphic and we're allowing graphics to resize,
					; then -- bind it to ?b
					(bind ?b ?hm2)
				else
					; just the top is aligned to the framework
					; offset the bottom by the top delta (i.e., move)
					(bind ?dt (- ?hm1 ?objt))
					(bind ?b (+ ?objb ?dt))
			)
		else
			(if (neq ?bt none)
				then
					; bottom is aligned to the framework -- bind it to ?b
					(bind ?b ?hm2)
					; and offset the top by the bottom delta
					(bind ?db (- ?hm2 ?objb))
					(bind ?t (+ ?objt ?db))
				else
					; neither top nor bottom are on the framework
					; move object but keep its center proportionately located on page
					; later, here is a good place to know about in-margin-ness, etc.
					(bind ?oldcenter (- (/ (+ ?objt ?objb) 2.0) ?opgt))	  ; wrt top of page
					(bind ?oldcenterrelpos (/ ?oldcenter ?psho))
					(bind ?newcenter (* ?oldcenterrelpos ?psh))
					(bind ?halfheight (/ (- ?objb ?objt) 2.0))
					(bind ?t (+ ?pgt (- ?newcenter ?halfheight)))
					(bind ?b (+ ?pgt (+ ?newcenter ?halfheight)))
			)
	)
	(modify ?obj (top ?t) (bottom ?b) (original_topbottom false)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RULES FOR THE flag_problems TASK
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RULES for flagging problems that might arise in rearranging
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; segtype values for textblock objects:  (from Pagemaker's gr.h)
; TX_TOP_MORETX		(BYTE)0	/* top of hole, prior text exists */
; TX_TOP_EOT		(BYTE)1	/* top of hole, no prior text */
; TX_BOT_EOT		(BYTE)2	/* bottom of hole, no more text exists */
; TX_BOT_MORETX		(BYTE)3	/* bottom of non-last hole, more text exists */
; TX_BOT_OVERSET	(BYTE)4	/* bottom of last hole, more text exists */

; A textblock is "lost" if the number of columns has shrunk and it belonged to
; one of the now-defunct columns, and it isn't the only textblock for the story.
; If lost, a textblock's windowshade handle is rolled to the top to remove the 
; textblock without deleting the text. Weakness:  more than one such textblocks
; could exist on a page, and if each are deleted independently, the whole story
; might disappear.  Need a way to know that at least one textblock remains...

(defrule flag_lost_objects
	(task flag_problems $?)
	(columninfo (columndifference FEWER) (numcolumns ?nc) (side ?s) (horizdir 0) (dirchange SAME))
	?obj <- (item (lost -1) (segtype ?segtype&1) (top ?t)
					 (left_aligns_to COLLEFT) (right_aligns_to COLRIGHT)
					 (left_aligns_obj_num ?cn) (right_aligns_obj_num ?cn)
					 (right_aligns_side ?s) (toptype ?tt) (bottype ?bt))
	=>
	(if (and (> ?cn ?nc) (or (= ?tt 0) (or (= ?bt 3) (and (neq ?tt 1) (= ?bt 4)))))
		then (modify ?obj (lost 1) (bottom ?t))
		else (modify ?obj (lost 0))
	)
	)

(defrule flag_lost_objects_hor
	(task flag_problems $?)
	(columninfo (columndifference FEWER) (numcolumns ?nc) (side ?s) (horizdir 1) (dirchange SAME))
	?obj <- (item (lost -1) (segtype ?segtype&1) (right ?r)
					 (top_aligns_to COLTOP) (bottom_aligns_to COLBOTTOM)
					 (top_aligns_obj_num ?cn) (bottom_aligns_obj_num ?cn)
					 (bottom_aligns_side ?s) (toptype ?tt) (bottype ?bt))
	=>
	(if (and (> ?cn ?nc) (or (= ?tt 0) (or (= ?bt 3) (and (neq ?tt 1) (= ?bt 4)))))
		then (modify ?obj (lost 1) (left ?r))
		else (modify ?obj (lost 0))
	)
	)

(defrule flag_lost_objects_dirchange
	(task flag_problems $?)
	(columninfo (columndifference FEWER) (numcolumns ?nc) (side ?s) (horizdir 0) (dirchange TOVER))
	?obj <- (item (lost -1) (segtype ?segtype&1) (top ?t)
					 (top_aligns_to COLTOP) (bottom_aligns_to COLBOTTOM)
					 (top_aligns_obj_num ?cn) (bottom_aligns_obj_num ?cn)
					 (bottom_aligns_side ?s) (toptype ?tt) (bottype ?bt))
	=>
	(if (and (> ?cn ?nc) (or (= ?tt 0) (or (= ?bt 3) (= ?bt 4))))
		then (modify ?obj (lost 1) (bottom ?t))
		else (modify ?obj (lost 0))
	)
	)

(defrule flag_lost_objects_hor_dirchange
	(task flag_problems $?)
	(columninfo (columndifference FEWER) (numcolumns ?nc) (side ?s) (horizdir 1) (dirchange TOHOR))
	?obj <- (item (lost -1) (segtype ?segtype&1) (top ?t)
					 (left_aligns_to COLLEFT) (right_aligns_to COLRIGHT)
					 (left_aligns_obj_num ?cn) (right_aligns_obj_num ?cn)
					 (right_aligns_side ?s) (toptype ?tt) (bottype ?bt))
	=>
	(if (and (> ?cn ?nc) (or (= ?tt 0) (or (= ?bt 3) (= ?bt 4))))
		then (modify ?obj (lost 1) (bottom ?t))
		else (modify ?obj (lost 0))
	)
	)


; A textblock is "dangling" if its bottom aligned with the former right-most 
; column on the page, but new columns have been added.  Don't bother to worry
; about whether there's more text downstream, since by adding columns to the
; page, each textblock has already been narrowed, making it likely (certain?)
; that there's now overset text for this story.  PM's response to a dangling
; textblock will be to add new textblocks for the new columns.

(defrule flag_dangling_objects
	(task flag_problems $?)
	(columninfo (columndifference MORE) (numcolumns_old ?nco&~0) (side ?s) (horizdir 0))
	?obj <- (item (dangling 0) (bottom_aligns_to BOTTOMMARGIN) (segtype ?segtype&1)
					 (left_aligns_to COLLEFT) (right_aligns_to COLRIGHT)
					 (left_aligns_obj_num ?nco) (right_aligns_obj_num ?nco)
					 (left_aligns_side ?s)
			)
	(not (item (dangling 1) (left_aligns_side ?s)))
	=>
	(modify ?obj (dangling 1)))

(defrule flag_dangling_objects_hor
	(task flag_problems $?)
	(columninfo (columndifference MORE) (numcolumns_old ?nco&~0) (side ?s) (horizdir 1))
	?obj <- (item (dangling 0) (left_aligns_to LEFTMARGIN) (segtype ?segtype&1)
					 (top_aligns_to COLTOP) (bottom_aligns_to COLBOTTOM)
					 (top_aligns_obj_num ?nco) (bottom_aligns_obj_num ?nco)
					 (top_aligns_side ?s)
			)
	(not (item (dangling 1) (top_aligns_side ?s)))
	=>
	(modify ?obj (dangling 1)))


(defrule flag_aspect_ratio_problems
	(task flag_problems $?)
	(prefs (stretchGraphics 1))
	?obj <- (item (segtype 6) (badaspectratio -1)	(aspectratio ?asprat)
			(left ?l) (right ?r) (top ?t) (bottom ?b))
	=>
	(bind ?num (- ?r ?l))
	(bind ?denom (- ?b ?t))
	(if (eq ?denom 0)
	 then	(bind ?newratio 0.0)
	 else	(bind ?newratio (/ (float ?num) ?denom))
	)
	(bind ?resultval 0)
	(if (neq ?asprat ?newratio)
	 then (bind ?resultval 1)
	)
	(modify ?obj (badaspectratio ?resultval)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RULES FOR THE fix_problems TASK
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;(defrule fix_wide_textblock
;	(task fix_problems $?)
;	?obj <- (object (segtype 1)						 
;			(left ?l) (right ?r&:(> (- ?r ?l) 30240))
;			(left_aligns_to ?la) (right_aligns_to ?ra))
;	=>
;	(bind ?newl ?l)
;	(bind ?newr ?r)
;	; if left is attached or right isn't, keep left side same;
;	; otherwise, keep the right the same
;	(if (or (neq ?la none) (eq ?ra none))
;		then (bind ?newr (+ ?l 30240))
;		else (bind ?newl (- ?r 30240)))
;	(modify ?obj (left ?newl) (right ?newr)))
			 
;(defrule fix_tall_textblock
;	(task fix_problems $?)
;	?obj <- (object (segtype 1)						 
;			(top ?t) (bottom ?b&:(> (- ?b ?t) 32544))
;			(top_aligns_to ?ta) (bottom_aligns_to ?ba))
;	=>
;	(bind ?newt ?t)
;	(bind ?newb ?b)
;	; if top is attached or bottom isn't, keep top side same;
;	; otherwise, keep the bottom the same
;	(if (or (neq ?ta none) (eq ?ba none))
;		then (bind ?newb (+ ?t 32544))
;		else (bind ?newt (- ?b 32544)))
;	(modify ?obj (top ?newt) (bottom ?newb)))
			 
(defrule make_graphics_proportional
	(task fix_problems $?)
	(prefs (stretchGraphics 1))
	?obj <- (item (segtype 6)  (badaspectratio 1) (aspectratio ?asprat&~0.0)
			(left ?l) (right ?r) (top ?t) (bottom ?b)
			(left_aligns_to ?la) (right_aligns_to ?ra) 
			(top_aligns_to ?ta) (bottom_aligns_to ?ba))
	(pasteboard (top ?pbt) (bottom ?pbb))
	=>
	; calculate the ratio created when the object was relocated
	(bind ?num (- ?r ?l))
	(bind ?denom (- ?b ?t))
	(if (eq ?denom 0)
	 then	(bind ?newratio 0.0)
	 else	(bind ?newratio (/ (float ?num) ?denom))
	)
	(if (neq ?asprat ?newratio)
	 then
	 	(bind ?newl ?l) (bind ?newr ?r) (bind ?newt ?t) (bind ?newb ?b)
		(bind ?testnewheight (/ (- ?r ?l) ?asprat))
		; include a test here to keep the object on the pasteboard (height < pbheight)
		(if (and (< ?testnewheight (- ?pbb ?pbt)) (and (neq ?la none) (neq ?ra none)))
		 then
		 	; both left and right are attached, now change top or bottom or both
			(bind ?newheight (/ (- ?r ?l) ?asprat))
			; if top aligned, change bottom (what about topbleeds????)
			(if (neq ?ta none)
			 then
			 	(bind ?newb (+ ?newt ?newheight))
			 else
			 	; if bottom aligned, change top (what about bottombleeds???)
				(if (neq ?ba none)
				 then
				 	(bind ?newt (- ?newb ?newheight))
				 else
				 	; neither are aligned -- change both top and bottom
					(bind ?center (+ ?newt (/ (- ?newb ?newt) 2)))
					(bind ?newt (- ?center (/ ?newheight 2)))
					(bind ?newb (+ ?newt ?newheight))
				)
			)
		 else
		 	; both top and bottom are attached, now change left or right or both
			(bind ?newwidth (* ?asprat (float (- ?b ?t))))
			; if left aligned, change right (what about leftbleeds????)
			(if (neq ?la none)
			 then
			 	(bind ?newr (+ ?newl ?newwidth))
			 else
			 	; if right aligned, change left (what about rightbleeds???)
				(if (neq ?ra none)
				 then
				 	(bind ?newl (- ?newr ?newwidth))
				 else
				 	; neither are aligned -- change both left and right
					(bind ?center (+ ?newl (/ (- ?newr ?newl) 2)))
					(bind ?newl (- ?center (/ ?newwidth 2)))
					(bind ?newr (+ ?newl ?newwidth))
				)
			)
		)
	 	(modify ?obj (left ?newl) (right ?newr) (top ?newt) (bottom ?newb) (badaspectratio 0))
	))

; toss this rule for now -- I don't see what it's value is (and it produces bug 1619644)
;(defrule fix_hanging_textblocks
;	(task fix_problems $?)
;	(margins (bottom ?b) (side ?s))
;	?obj <- (object (dangling 0) (bottom_aligns_to none) (segtype ?segtype&1)
;					 (left_aligns_to COLLEFT) (right_aligns_to COLRIGHT)
;					 (left_aligns_obj_num ?nco) (right_aligns_obj_num ?nco)
;					 (left_aligns_side ?s) (top ?ot&:(< ?ot ?b)) (bottom ?ob&:(> ?ob ?b))
;			)
;	=>
;	(modify ?obj (bottom ?b)))

(defrule fix_zero_width_objects
	(task fix_problems $?)
	?obj <- (item	(left ?x) (right ?x) (width_orig ?wo&~0.0))
	=>
	(bind ?halfwidth (/ ?wo 2.0))
	(modify ?obj (left =(- ?x ?halfwidth)) (right =(+ ?x ?halfwidth))))  

(defrule fix_zero_height_objects
	(task fix_problems $?)
	?obj <- (item	(top ?y) (bottom ?y) (height_orig ?ho&~0.0))
	=>
	(bind ?halfheight (/ ?ho 2.0))
	(modify ?obj (top =(- ?y ?halfheight)) (bottom =(+ ?y ?halfheight))))  


