*****************************************************************************************************
; Memory.aii 
;
;   This file contains the routines that are called when WP is running low on memory. Currently two
; routines exist to free up memory:
;
;   W_CollapseRulers 	- Compare all of the rulers and get rid of any duplicates.
;   W_ShrinkTextBlocks 	- Shrink text blocks to fit the text in them.
;
*****************************************************************************************************

	load	'macros.dump'
	include	'driver.equ'
	include	'wp.equ'
	
	import	D_Deref
	import	D_BeachBall
	
	import	W_SwitchData
	import	W_View
	import	W_Pptr
	import	W_LastP
	import	W_UseRuler
	import	W_UnUseRuler
	import	W_CurrentBlockHandle
	import	W_CurrentBlockHandle2
	import	W_DocLocked
	import	W_PHandle
	import	W_StartRuler
	
	entry	W_LockArrays
	entry	W_UnlockArrays
	entry	W_CompareRulers
	
*****************************************************************************************************
; W_CollapseRulers ( )
;
;   This routine will scan all the rulers in the current WP document and make sure that no duplicate
; rulers exist. For each document part ( body, header, and footer ) call the routine to collapse the
; rulers, then restore the original document view.

W_CollapseRulers	PROC	EXPORT

	local	SPtr:l,ParPtr:l,RulerHand:l,RulerPtr:l
	local	TestHand:l,SPars:w,DPtr:l,DPars:w,CurView:w
	begin
	
	moveword	W_View,curview
	call	W_SwitchData,in=(#W_NormalOn:w)
	jsr	DoCollapse
	call	W_SwitchData,in=(#W_HeaderOn:w)
	jsr	DoCollapse
	call	W_SwitchData,in=(#W_FooterOn:w)
	jsr	DoCollapse
	call	W_SwitchData,in=(CurView:w)
	return
;...................................................................................................;

DoCollapse
; Get paragraph array pointer for current body part whose rulers are being collapsed. Set the
; paragraph count at the first paragraph.

	movelong	W_Pptr,SPtr
	moveword	#1,SPars

; Get first ruler in document (skip page breaks which don't have rulers).

findloop	cmpw	[SPtr]:#W_pAttr,#W_PgBrk
	bne	foundrule
	addwl	#W_pBytes,SPtr
	inc	Spars
	cmpw	W_LastP,Spars
	bge	findloop
	bra	goexit
	
; Get the ruler for the first paragraph. If ruler count is same as total number of paragraphs then
; nothing exists to be collapsed - exit.

foundrule	movelong	[SPtr]:#W_pRulerHand,RulerHand
	movelong	[RulerHand],RulerPtr
	cmpw	W_LastP,[RulerPtr]
	bne	markit
goexit	brl	exit

; Mark this ruler by setting the high bit of the handle. Start comparison with ruler for second
; paragraph. Point DPtr to second paragraph in paragraph array.

markit	jsr	MarkRuler
	addword	Spars,#1,Dpars
	addlong	Sptr,#W_pBytes,Dptr

; For each unmarked ruler repeatedly get the next ruler. Compare it with the current one. If it
; is the same then use the old ruler instead and unuse the new one. 

rulerloop	jsl	D_BeachBall
	cmpw	W_LastP,Dpars
	jlt	nextruler

; Get next test handle. ( skip over any page breaks ).

	cmpw	[DPtr]:#W_pAttr,#W_PgBrk
	beq	nexttest
	
; Get handle for current paragraph. If high bit set then ruler has already been collapsed so go to
; next handle to compare. If same handle then simply mark it.

	ldy	#W_pRulerHand+2
	lda	[DPtr],y
	bmi	nexttest
	sta	TestHand+2
	moveword	[DPtr]:#W_pRulerHand,TestHand
	cmpl	TestHand,RulerHand
	bne	notsamehand
	jsr	MarkTest
	bra	nexttest

; Different ruler was found; now we will need to determine whether they are actually equivalent.

notsamehand	call	W_CompareRulers,in=(RulerHand:l,TestHand:l)
	bcs	nexttest

; Check if TestRuler was the current visable ruler if so we will need to update W_StartRuler.

	cmpl	TestHand,W_StartRuler
	bne	replaceit
	movelong	RulerHand,W_StartRuler
	
; Replace test ruler with source ruler. Mark test ruler so we won't look at it again.

replaceit	call	W_UseRuler,in=(#1:w,RulerHand:l)
	call	W_UnUseRuler,in=(#1:w,TestHand:l)
	movelong	Rulerhand,[DPtr]:#W_pRulerHand
	jsr	MarkTest
		
; Get the next unmarked ruler.

nexttest	inc	Dpars
	addwl	#W_pBytes,Dptr
	brl	rulerloop

; Scan for next ruler to be collapsed. Bump to next ruler and check if past last paragraph if so
; branch and unmark everything.

nextruler	addwl	#W_pBytes,Sptr
	inc	Spars
	cmpw	W_LastP,Spars
	blt	unmark

; Get next ruler to be checked. (skip over page breaks).

	cmpw	[SPtr]:#W_pAttr,#W_PgBrk
	beq	nextruler
	
; If ruler has already been marked then skip it; else mark the ruler and scan the remaining rulers
; for any equivalent rulers.

	ldy	#W_pRulerHand+2
	lda	[SPtr],y
	bmi	nextruler
	moveword	[SPtr]:#W_pRulerHand,RulerHand	
	brl	markit
	
; Unmark all of the rulers.

unmark	movelong	W_Pptr,Sptr
	moveword	#1,Spars
	
unmarkloop	cmpw	[SPtr]:#W_pAttr,#W_PgBrk
	beq	unmarknext
	jsr	UnmarkRuler
unmarknext	addwl	#W_pBytes,Sptr
	inc	Spars
	cmpw	W_LastP,Spars
	bge	unmarkloop
	
exit	rts
;..................................................................................................;

MarkRuler	ldy	#W_pRulerHand+2
	lda	[SPtr],y
	ora	#$8000
	ldy	#W_pRulerHand+2
	sta	[SPtr],y
	rts
;..................................................................................................;

MarkTest	ldy	#W_pRulerHand+2
	lda	[DPtr],y
	ora	#$8000
	ldy	#W_pRulerHand+2
	sta	[DPtr],y
	rts
;..................................................................................................;

UnmarkRuler	ldy	#W_pRulerHand+2
	lda	[SPtr],y
	and	#$7FFF
	sta	[SPtr],y
	rts
;..................................................................................................;

	ENDP

*****************************************************************************************************
; W_CompareRulers ( SourceRuler:long, DestRuler:long )
;
;  This routine will compare the two given rulers and return a 0 is the accumulator if they are
; equal or -1 if they are not.

W_CompareRulers	PROC	EXPORT

	input	Src:l,Dest:l
	local	Sptr:l,Dptr:l,Tabs:w
	error	Result
	begin
	
	stz	Result
	movelong	[Src],Sptr
	movelong	[Dest],Dptr

;In this series, y will contain the correct offset after the [Src] part is evaluated.

	ldy	#2
	lda	[Sptr],y		; W_or_Status
	cmp	[Dptr],y
	bne	dobne
	iny
	iny
	lda	[Sptr],y		; W_or_LeftM
	cmp	[Dptr],y
dobne	bne	@notequal
	iny
	iny
	lda	[Sptr],y		; W_or_IndentM
	cmp	[Dptr],y
	bne	@notequal
	iny
	iny
	lda	[Sptr],y		; W_or_RightM
	cmp	[Dptr],y
	bne	@notequal
	iny
	iny
	lda	[Sptr],y		; W_or_NumTabs
	cmp	[Dptr],y
	bne	@notequal
	sta	Tabs
	tax
	beq	@exit		; exit with tabs equal if both 0.
	iny
	iny			; Get to first tab

@tabloop	lda	[SPtr],y
	cmp	[DPtr],y
	bne	@notequal
	iny
	iny
	lda	[SPtr],y
	cmp	[DPtr],y
	bne	@notequal
	dec	Tabs
	beq	@exit
	iny
	iny
	bra	@tabloop
		
@notequal	dec	Result
	
@exit	return
	
	ENDP


;*************************************************************************************
;
;   W_ShrinkTextBlocks - make text blocks shrink to fit the text.
;
;*************************************************************************************

W_ShrinkTextBlocks	PROC	EXPORT

	MoveWord	W_View, >CurView

	call	W_SwitchData, in=(#W_NormalOn:w)
	jsl	DoShrink
	
	call	W_SwitchData, in=(#W_HeaderOn:w)
	jsl	DoShrink
	
	call	W_SwitchData, in=(#W_FooterOn:w)
	jsl	DoShrink
	
	call	W_SwitchData, in=(>CurView:w)
	rtl


CurView	DS.W	1

DoShrink	
	local	OldHand:l, PArrayPtr:l,TextBlockHand:l,TBPtr:l,Size:l
	local	Pars:w
	
	begin

;Get pointer to the paragraph array and the number of paragraphs.   The paragraph
;array must be locked or the memory manager must be required not to move memory
;when shrinking handles.
	MoveLong	W_Pptr, PArrayPtr
	MoveWord	W_lastP, Pars

	stz	Size+2			;Size is always <64K
	Stzl	OldHand

@ploop	MoveLong	[PArrayPtr], TextBlockHand	;Text block is first field in record
	Cmpl	TextBlockHand, OldHand
	beq	@next
	Cmpl	TextBlockHand, W_CurrentBlockHandle
	beq	@next
	Cmpl	TextBlockHand, W_CurrentBlockHandle2
	beq	@next

	MoveLong	[TextBlockHand], TBPtr
	MoveWord	[TBPtr]:#2,Size

	tool	_SetHandleSize,in=(Size:l, TextBlockHand:l)
	
	MoveLong	TextBlockHand, OldHand
	MoveWord	Size, [TBPtr]
@next	Addwl	#W_pBytes, PArrayPtr
	dec	Pars
	bne	@ploop
	
	return

	ENDP

;*****************************************************************************
;
;   W_UnlockArrays - not really.  Only unlock if we get zero in count
;
;*****************************************************************************
W_UnlockArrays PROC EXPORT

	local	CurView:w
	
	begin
	
	lda	W_DocLocked
	beq	@doit
	dec	W_DocLocked
	bne	@exit
@doit	MoveWord	W_View,CurView
	call	W_SwitchData, in=(#W_NormalOn:w)
	tool	_HUnLock, in=(W_PHandle:l)
	call	W_SwitchData, in=(#W_HeaderOn:w)
	tool	_HUnLock, in=(W_PHandle:l)
	call	W_SwitchData, in=(#W_FooterOn:w)
	tool	_HUnLock, in=(W_PHandle:l)
	
@exit	return
	
	ENDP

;******************************************************************************
;
;   W_LockArrays - Lock arrays if count is zero; increment count in any case
;
;******************************************************************************
W_LockArrays	PROC EXPORT
	
	local	CurView:w
	
	begin
	
	lda	W_DocLocked
	bne	@exit
	
	MoveWord	W_View, CurView
	
	call	W_SwitchData, in=(#W_NormalOn:w)
	rcall	D_Deref, in=(W_PHandle:ax), out=(W_Pptr:ax)
	
	call	W_SwitchData, in=(#W_HeaderOn:w)
	rcall	D_Deref, in=(W_PHandle:ax), out=(W_Pptr:ax)
	
	call	W_SwitchData, in=(#W_FooterOn:w)
	rcall	D_Deref, in=(W_PHandle:ax), out=(W_Pptr:ax)
	
	call	W_SwitchData, in=(CurView:w)

@exit	inc	W_DocLocked	
	return

	ENDP


	END