*****************************************************************************************************
* WPFileIO Routines
*
*   This file contains the WP open and save routines.
*
*****************************************************************************************************

	load 	'macros.dump'
	include 	'driver.equ'
	include 	'wp.equ'

	IMPORT	D_AlertBox
	IMPORT	D_BeachBall
	IMPORT	D_BitMapChanged
	IMPORT	D_BitMapPtr
	IMPORT	D_ClearFileChanged
	IMPORT	D_Deref
	IMPORT	D_GrowHandle
	IMPORT	D_KillFont
	IMPORT	D_MemoryError
	IMPORT	D_NeedHandle
	IMPORT	D_SystemHandle
	IMPORT	D_StringBuffer
	IMPORT	D_Read2
	IMPORT	D_Write2

	IMPORT	W_CollapseRulers
	IMPORT	W_CurDoc
	IMPORT	W_FillDateTime
	IMPORT	W_GetAddr
	IMPORT	W_GetDoc
	IMPORT	W_GetParRec
	IMPORT	W_LastP
	IMPORT	W_MakeScrollBar
	IMPORT	W_MaxP
	IMPORT	W_NewWinComin
	IMPORT	W_PHandle
	IMPORT	W_PPtr
	IMPORT	W_PutDoc
	IMPORT	W_ScrollBar
	IMPORT	W_SetFullREct
	IMPORT	D_SetRefCon
	IMPORT	W_ShowRuler
	IMPORT	W_SizeWinGlobals
	IMPORT	W_StartPar
	IMPORT	W_StartRuler
	IMPORT	W_StartWinGlobals
	IMPORT	W_SwitchData
	IMPORT	W_View
	
	IMPORT	X_DisposeWPScrap
	IMPORT	X_ReadWPScrap
	IMPORT	X_WriteThread

*****************************************************************************************************
; W_OpenDoc	( FileRef:word, WindowPtr:long )
;
;   This routine will handle reading in a word processing document with the given file reference.
; The file has already been opened by the driver and the file mark moved to the start of the document
; data. Memory or file I/O errors are returned to the driver which will handle closing the file and
; alerting the user.

W_OpenDoc	PROC	EXPORT
	;Using 	WpGlobals
	;Using 	D_IOData
	;Using 	W_SampleData
	;Using 	W_ATTRData
	;Using 	W_WPFileIOData

	EXPORT	W_FVersion
	
	input 	FileRef:w,window:l
	local 	Scrap:l,ScrapPtr:l,ScrapSize:l,OldShowRul:w
	local 	Version:w,CurView:w,RefHand:l,Ptr:l,SaveDoc:l
	local	bodyscrap:l,footerscrap:l,headerscrap:l
	error 	err
	begin 	+b

; Clear error status, save current document's data to its refcon, save the document so it can be
; restored before exiting, and make the input window the current document. Remember the old port
; on the stack and setport to new window.
	
	stz 	err
	jsl 	W_PutDoc
	movelong	W_CurDoc,SaveDoc	
	movelong 	window,W_CurDoc
	tool	_GetPort,out=(:l)
	tool	_SetPort,in=(window:l)

; Create the refcon handle that will hold this windows globals. If we get a memory err then exit.
	
	call 	D_NeedHandle,in=(#W_SizeWinGlobals:l,#attrfixed:w),out=(RefHand:l),err=err
	jcs 	exit

; Set window refcon to the handle we created.

	movelong 	[RefHand],Ptr
	call	D_SetRefCon,in=(Ptr:l,Window:l)

; Get version number from file. If error reading then exit after disposing of refcon. Check if valid
; version if not warn user and exit.

	call	D_Read2,in=(FileRef:w,!Version:l,#2:l),out=(ax:l),err=err
	jcs 	killref
	cmpw	Version,W_FVersion
	jlt	laterversion
	cmp	#1
	jeq	earlyversion

; Read in the globals for the document. If error then dispose of refcon and exit.

	call	D_Read2,in=(FileRef:w,#W_StartWinGlobals:l,#W_SizeWinGlobals:l),out=(ax:l),err=err
	jcs 	killref

; Save ruler status and view status brought in from file.

	moveword 	W_ShowRuler,OldShowRul
	moveword 	W_View,CurView

; Read in the document body, header, and footer. If any memory errors occurs dispose of the scraps
; we have read so far and the document refcon we created. 

	call	X_ReadWPScrap,in=(FileRef:w,#0:w),out=(bodyscrap:l),err=err
	jcs	killref
	call	X_ReadWPScrap,in=(FileRef:w,#0:w),out=(headerscrap:l),err=err
	jcs	killbody
	call	X_ReadWPScrap,in=(FileRef:w,#0:w),out=(footerscrap:l),err=err
	jcs	killheader	

; Successfully read in all three document parts as WP scraps. Now managle each scrap into a document
; thread and switch it into its correct globals location. Finally switch to the document part that
; was being edited when the document was saved.

	call	W_SwitchData,in=(#W_NormalOn:w)
	movelong	bodyscrap,scrap
	jsr	manglescrap
	
	call	W_SwitchData,in=(#W_HeaderOn:w)
	movelong	headerscrap,scrap
	jsr	manglescrap
	
	call	W_SwitchData,in=(#W_FooterOn:w)
	movelong	footerscrap,scrap
	jsr	manglescrap

	call	W_SwitchData,in=(CurView:w)

; Kill the current font and set clip rect to entire port rect.

	jsl 	D_KillFont
	jsl 	W_SetFullREct

; Create new scroll bar for this document window. By setting W_ScrollBar to NIL we make sure that
; a new scroll bar will be created. Call MakeScrollBar with flag set to indicate that clip rect
; is already set correctly.

	stzl 	W_ScrollBar
	call 	W_MakeScrollBar,in=(#1:w)

; Get ptr to start paragraph record use this to derive the start ruler.

	rcall	W_GetParRec,in=(W_StartPar:a),out=(ScrapPtr:ax)
	movelong 	[ScrapPtr]:#W_pRulerHand,W_StartRuler

; Get current date & time into WP string buffers. Clear the file changed status.

	jsl 	W_FillDateTime
	call 	D_ClearFileChanged,in=(window:l)
	movelong 	window,W_NewWinComin
	bra 	exit

; Handle version errors. Return -1 error to the driver to say we handled it.

laterversion	
	movelong	#LaterString,xy
	bra	doalert
earlyversion	
	movelong	#EarlyString,xy
doalert	call	D_AlertBox,in=(#OkBox:w,xy:l),out=(a:w)
	dec	err
	bra	killref

; Dispose of memory allocated for error recovery.

killheader	call	X_DisposeWPScrap,in=(headerscrap:l)
killbody	call	X_DisposeWPScrap,in=(bodyscrap:l)
killref	tool	_DisposeHandle,in=(RefHand:l)

; Restore the old port and document before returning.

exit	tool	_SetPort
	call	W_GetDoc,in=(SaveDoc:l)
	return
;...................................................................................................;

LaterString	str 	'Later version of AppleWorks GS needed to load this file.'
EarlyString	str 	'This file cannot be opened by this version of AppleWorks GS.'
W_FVersion	DC.W	2
;...................................................................................................;
*
* Mangle "scrap" into a document thread. ie remove the paragraph count word from the front of the
* scrap.

; Get paragraph count from scrap as last & max paragraphs.

manglescrap	movelong 	[Scrap],ScrapPtr
	moveword 	[ScrapPtr],W_LastP
	moveword 	W_LastP,W_MaxP

; Resize the scrap down to remove the paragraph count and turn it into a "real" wp document.
; Note: We are sizing the handle down so no memory error is possible.

	tool	_GetHandleSize,in=(Scrap:l),out=(ScrapSize:l)
	AddLong 	ScrapPtr,#2,s
	PushLong 	ScrapPtr
	SubLong 	ScrapSize,#2,ScrapSize
	PushLong 	Scrapsize
	_BlockMove
	call	D_GrowHandle,in=(ScrapSize:l,Scrap:l)

; Set scrap as current document and lock down its handle ( get its pointer ).

	movelong	Scrap,W_PHandle
	rcall	D_Deref,in=(Scrap:ax),out=(W_PPtr:ax)

; Get ruler associated with current paragraph.

	SpaceLong
	PushWord 	W_StartPar
	PushWord 	#W_pBytes
	_Multiply
	pla
	plx
	clc
	adc 	#W_pRulerHand
	tay
	movelong 	[ScrapPtr]:y,W_StartRuler
	clc
	rts
;...................................................................................................;

	ENDP

*****************************************************************************************************
; W_SaveDoc	( FileRef:word, WindowPtr:long )
;
;   This routine will handle saving a word processing document with the given file reference.
; The file has already been opened by the driver and the file mark moved to the start of the document
; data. Memory or file I/O errors are returned to the driver which will handle killing the file and
; alerting the user.

W_SaveDoc	PROC	EXPORT
	;Using WpGlobals
	;Using D_IOData
	;Using W_ATTRData
	;Using W_WPFileIOData

	input 	FileRef:w,window:l,type:w
	local 	CurView:w,Buffer:l
	local 	BufPtr:l,TextPtr:l,Pars:w,Boff:l
	local 	ParArray:l,Bsize:l,SaveDoc:l
	error 	err
	begin 	+b

; Clear error status, save current document, get globals for the document to be saved and collapse
; the rulers for the document before it goes to disk.
	
	stz 	err
	movelong	W_CurDoc,SaveDoc	
	call	W_GetDoc,in=(window:l)
	jsl	W_CollapseRulers

; Remember the current view of the document.

	moveword 	W_View,CurView

; Check type we should save document as. If Ascii save then branch.

	lda 	Type
	jne 	doascii

; Write WP version number and window globals for the document. If disk error occurs then restore old
; document and return error to the driver.

	call	D_Write2,in=(FileRef:w,#W_FVersion:l,#2:l),out=(ax:l),err=err
	jcs	exit

	call	D_Write2,in=(FileRef:w,#W_StartWinGlobals:l,#W_SizeWinGlobals:l),out=(ax:l),err=err
	jcs 	exit

; Switch in the body of the document and write out its contents. If error occurs then restore correct
; view of document and return error to the caller.

	lda	#W_NormalOn
	jsr	writethread
	jcs	restoreview
	
; Switch in the header of the document and write out its contents. If error occurs then restore 
; correct view of document and return error to the caller.

	lda	#W_HeaderOn
	jsr	writethread
	jcs	restoreview
	
; Switch in the footer of the document. Whether or not we have encountered and error we will want to
; restore the view and the old document. The error will be returned to the caller.

	lda	#W_FooterOn
	jsr	writethread
	brl	restoreview	

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

; Switch in the body of the document (no headers/footers in ASCII save).

doascii	call	W_SwitchData,in=(#W_NormalOn:w)

; Use 32k bitmap to buffer the output. Clear paragraph count. Since we are going to be using the 32k 
; buffer set the dirty flag.

	movelong	>D_BitMapPtr,Buffer
	moveword	#1,>D_BitMapChanged
	movelong	#$7FFF,Bsize
	stz 	Pars

; For all paragraphs do: 

ploop	jsl 	D_BeachBall
	lda	Pars
	cmp	W_LastP
	jge	restoreview
	
; Get pointer to paragraph text, set bufptr to start of 32k buffer and clear buffer offset.

	inc 	a
	ldx 	#7
	jsl 	W_GetAddr
	movelong 	ax,Textptr
	movelong 	Buffer,Bufptr
	stzl 	Boff

; Scan characters into buffer. Carriage will terminate the line. Handle font/style changes.

cloop	shortm
	lda 	[TextPtr]
	cmp 	#CR
	jeq 	doCR
	bge 	putchar
	cmp 	#TAB
	beq 	putchar
	cmp 	#1
	beq 	fontchange
	cmp 	#5
	blt 	stylechange
	bra 	putchar

; If font or style change then just bump the text pointer past the font/style information.

fontchange	longm
	addwl 	#3,TextPtr
	bra 	cloop

stylechange	longm
	addwl 	#2,TextPtr
	bra 	cloop

; Add character to the buffer and bump pointers. If buffer is full write it out. If error writing
; buffer then restore original document view and return error to the caller.

	LONGA 	Off
putchar	sta 	[BufPtr]
	longm
	incl 	TextPtr
	incl 	Bufptr
	incl 	Boff
	cmpl 	Boff,Bsize
	jlt 	cloop
	jsr 	writebuffer
	jcs	restoreview
	brl 	cloop

; Carriage return encountered. Add carriage return to the buffer if this is not the last paragraph.

	LONGA 	Off
doCR	sta 	[BufPtr]
	longm
	lda	Pars
	inc 	a
	cmp 	W_LastP
	bge 	nowritecr
	incl 	Boff

; Write out the buffer and increment the paragraph count. Go back for more. If error writing buffer
; then restore original document view and return error to the caller.

nowritecr	jsr 	writebuffer
	jcs	restoreview
	inc 	Pars
	brl 	ploop

; Unlock the paragraph array that we locked down and switch the original view back in before we
; exit and return the error to the caller.

restoreview	call	W_SwitchData,in=(CurView:w)
	
; Restore the old document and return to the caller.

exit	call	W_GetDoc,in=(SaveDoc:l)
	return
;...................................................................................................;

writethread	call	W_SwitchData,in=(a:w)
	movelong	W_PHandle,ParArray
	call	X_WriteThread,in=(FileRef:w,W_LastP:w,[ParArray]:l,#0:w),err=err
	rts
;...................................................................................................;

writebuffer	call	D_Write2,in=(FileRef:w,Buffer:l,Boff:l),out=(ax:l),err=err
	bcs	writeerr
	movelong	Buffer,Bufptr
	stzl 	Boff
writeerr	rts
;...................................................................................................;

	ENDP

	END

