FDC_3P5				EQU	0	;1 if code is compiled for 3"5 drive

IFNOT FS_Minimal_System

IFNOT FDC_3P5

;********************
;*** CHANGE FACE ****
;********************
;show message to change face and wait a key
.FS_ChangeFace
	push DE
	push BC
	
	call KEY_Update
	
	ld A,(#4000) ;save current bank
	push AF
	change_bankM #C0

	;call FS_CleanLines	
	
	ld A,(current_side)
	xor 1
	add 33
	ld (change_side_str),A
	
	ld DE,#4002
	ld HL,change_str
	call FONT_DrawString
	
	xor A
	ld (ForcePlayerMove),A	;be sure player is free to move

;wait fire	
.FS_ChangeFaceWaitKey
	call KEY_Update
	call MMI
	bit 4,A
	jr z,FS_ChangeFaceWaitKey
	
	ld A,(current_side)
	xor 1
	ld (current_side),A	
	
	ld DE,#4002
	ld HL,loading_str
	call FONT_DrawString
	
	pop AF
	change_bank
	
	pop BC
	pop DE
	
	ret
.change_str
	db "INSERT SIDE "
.change_side_str
	str "A AND PRESS FIRE"
ENDIF

	
;************************
;*** EXIT FILE SYSTEM ***
;************************
;restore #4000 range

.FS_Exit
	ld A,(FS_initialized)
	or A
	ret z	;not init !
	
	call GFX_HideScreen
	
	ld A,(#4000) ;save current bank
	push AF
	
	;ld BC,#7FC0
	;out (C),C	;default bank !
	change_bankM #C0

	ld BC,#4008	;64 bytes , 8 lines
	ld HL,#8000
	ld DE,#4002
	
	;call FS_CleanLines
	

	
.FS_ExitLoop1
	push BC
	push DE
.FS_ExitLoop2
	ld A,(HL)
	ld (DE),A
	ld (HL),0	;cleanup
	inc HL
	inc DE
	djnz FS_ExitLoop2
	pop DE
	ld A,8
	add D
	ld D,A
	pop BC
	dec C
	jr nz,FS_ExitLoop1
	
	;restore bank
	pop AF
	;ld B,#7F
	;out (C),A
	change_bank
	
	xor A
	ld (FS_initialized),A	
	ret

;*************************
;*** ENTER FILE SYSTEM ***
;*************************
;setup FS screen
;use #4000 buffer 64*8 bytes for screen and transfert data to #8000

.FS_Enter
	ld A,(FS_initialized)
	or A
	ret nz	;already init !
	
	di	;be sur int are off !

	ld A,(#4000) ;save current bank
	push AF
	
	;ld BC,#7FC0
	;out (C),C	;default bank !	
	change_bankM #C0

	ld BC,#4008	;64 bytes , 8 lines
	ld HL,#4002
	ld DE,#8000
	
	call FS_CleanLines	
	
	ld HL,crtc_config_loading	;CRTC
	call GFX_SetCRTC
	
	;ld BC,#7F8C+1				;mode 1
	;out (C),C
	change_mode 1
	
	ld HL,loading_pal
	call GFX_SetColors
	
	;wait a bit to stabilize screen
	ld E,50
	call DSK_Wait
	
	ld A,1
	ld (FS_initialized),A
	
	ld DE,#4002
	ld HL,loading_str
	;ld BC,color_table_options_normal
	call FONT_DrawString ;EX
	
	;restore bank
	pop AF
	;ld B,#7F
	;out (C),A
	change_bank
	
	ret
	
.FS_CleanLines	

	
.FS_EnterLoop1
	push BC
	push HL
.FS_EnterLoop2
	ld A,(HL)
	ld (DE),A
	ld (HL),0	;cleanup
	inc HL
	inc DE
	djnz FS_EnterLoop2
	pop HL
	ld A,8
	add H
	ld H,A
	pop BC
	dec C
	jr nz,FS_EnterLoop1
	ret	
	
.loading_str
	db "NOW LOADING"
	ds 20,0
	db 0+128
	
.FS_initialized
	db 0
	
ENDIF

;************************
;*** FILE SYSTEM CODE ***
;************************


FS_LastSector		EQU #CA
FS_FirstSector		EQU #C1

;********************************
;*** Shortcuts from FDC_tools ***
;********************************
.FDCON
	call FDC_MotorOn 
	
	call FDC_DriveWaitReady
	
	ld HL,FS_Dir_Location	
	call FS_GetDir
	ret
	
.FDCOFF
	call FDC_MotorOff
	ret
	
;HL = name - DE = address
.Quick_load
	;ld HL,spr_base
	;ld DE,#4000
	
	ld (FS_LastFile),HL	;save filename

	push DE
	ld DE,FS_Dir_Location
	ex DE,HL
	call FS_GetFile
	jr nc,Quick_load_error
	

	
	push AF
	bit 1,A ; is compressed ?
	jr nz,QuickLoadFileCompressed
	
	pop AF
	pop HL
	push HL
	push AF
	jr QuickLoadFileDoLoad
	
	
.QuickLoadFileCompressed
	ld HL,FS_DeexoBuffer+2	;2 bytes for checksum

.QuickLoadFileDoLoad	
	push HL
	call FS_LoadFile
	pop HL
	
	pop AF
	pop DE
	bit 1,A
	ret z	;if not compressed , returns
	
	call deexo
	ret
.Quick_load_error
	ld SP,Quick_load_error_proc
	ret
	
.Quick_load_error_proc
	dw	FATAL_Error,Quick_load_error_name,Quick_load_name
	
.Quick_load_name
	;str "QUICK_LOAD"
.Quick_load_error_name
	;str "FILE NOT FOUND"

;*********************
;*** GET DIRECTORY ***
;*********************
;load 2 sectors of the dir at (HL)
.FS_GetDir
	push HL
	call FDC_Track0      ;go to track 0 first
	pop HL
	
	ld DE,#400	;1K
IF amsdos_version
	ld BC,#C7C8
ELSE
	ld BC,#C2C3	;track 0 sectors 2 & 3 are dir
ENDIF
	
	ld A,10	;10 tries
	ld (FS_GetDir_Error_count),A
.FS_GetDirRetry
	
	push HL
	push DE
	push BC
	
	call FDC_Read
	
	pop BC
	pop DE
	pop HL	
	
	jr nc,FS_GetDir_Error	;can not read directory

	ret
.FS_GetDir_Error
	push AF
	push DE
	push BC
	ld E,50
	call DSK_wait
	call FDC_DriveWaitReady
	pop BC
	pop DE
	pop AF
	
	ex AF,AF'
FS_GetDir_Error_count EQU $+1
	ld A,0
	dec A
	ld (FS_GetDir_Error_count),A
	or A
	jr nz,FS_GetDirRetry
	
	ld HL,FS_GetDir_name
	push HL
	ex AF,AF'
	jp FDC_FatalError
	
.FS_GetDir_name
	;str "FS_GETDIR"
	
;*******************
;*** LOAD A FILE ***
;*******************
; use FS_GetFile returns
; except HL that contains address to write

.FS_LoadFile
;break
	jp nc,FS_LoadFileError	;no file !
	; here we must check side and turn if needed for 3"

IFNOT FDC_3P5
	;save data for 3" mode
	ld (FS_LoadFile_saveA),A
	ld (FS_LoadFile_saveHL),HL
	ld (FS_LoadFile_saveDE),DE
	ld (FS_LoadFile_SaveBC),BC
ENDIF

.FS_LoadFile_Retry3p

	push DE ;bytes to read
	push HL	;load address
	push AF	;flags
	
	bit 1,A	;checksum ?
	jr z,FS_LoadFile_NoChecksumSkip
	dec HL
	dec HL	
.FS_LoadFile_NoChecksumSkip

IF FDC_3P5
	and 1
	ld (current_head),A
ELSE
	IFNOT FS_Minimal_System
		
		and 1
		push HL
		ld L,A
		ld A,(current_side)
		cp L
		call nz,FS_ChangeFace
		pop HL	
	ENDIF
ENDIF

	ld (bytes_to_read),DE
	;init cache
	call FS_InitCache
	
.FS_LoadFileLoop
	ld HL,(bytes_to_read)
	ld DE,512
	or A		;reset carry
	SBC HL,DE
	ld (bytes_to_read),HL	
	
	jr c,FS_LoadFileLoopEnd
	jr z,FS_LoadFileLoopEnd
	
	ld HL,512			;add complete sector to cache
	call FS_AddToCache
	jr FS_LoadFileLoop
	
;we reached the end of the file
.FS_LoadFileLoopEnd
	add HL,DE	;add 512 to get correct count to add
	call FS_AddToCache
	call FS_FlushCache		;do not forget to flush cache when finishing

;loaded , so now do checksum	
	pop AF
	pop HL
	pop DE
	
	bit 1,A	;checksum present ?
	ret z
	push HL
	call nz,FS_LoadFileDoChecksum	;compute checksum
	pop HL
	
	dec HL
	dec HL	;get checksum address
	;compare to file checksum
	ld A,C
	cp (HL)
	jr nz,FS_LoadFileChecksumError
	inc HL
	ld A,B
	cp (HL)
	jr nz,FS_LoadFileChecksumError	
	
	ret
.FS_LoadFileChecksumError
IF FDC_3P5
	ld SP,FS_LoadFile_ChecksumProc
	ret
ELSE	
;restore previous face
		ld A,(current_side)
		xor 1
		ld (current_side),A			

;if checksum error in 3" mode so restore entry values
FS_LoadFile_saveA	EQU $+1
		ld A,0
FS_LoadFile_saveHL	EQU $+1		
		ld HL,0
FS_LoadFile_saveDE	EQU $+1		
		ld DE,0
FS_LoadFile_saveBC	EQU $+1		
		ld BC,0	
;retry
		jr FS_LoadFile_Retry3p
ENDIF

IF FDC_3P5
.FS_LoadFile_ChecksumProc
	dw FATAL_Error,FS_Checksum_error,FS_LoadFile_name
ENDIF
	
.FS_LoadFile_name
	;str "FS_LOADFILE"
IF FDC_3P5	
.FS_Checksum_error
	;str "CHECKSUM ERROR"
ENDIF
	
.FS_LoadFileError

	jr FS_LoadFileError
		
	
.FS_LoadFileDoChecksum
	ld BC,0
	dec DE	
	dec DE	;remove checksum size
	dec DE
.FS_LoadFileDoChecksumLoop
	ld A,(HL)
	xor C
	ld C,A
	inc HL
	ld A,(HL)
	xor B
	ld B,A

	dec DE
	ld A,D
	or E
	ret z
	jr FS_LoadFileDoChecksumLoop
	


;***********************************
;*** ADD CURRENT SECTOR TO CACHE ***
;***********************************
; HL = ammount of data to add
	
.FS_AddToCache	
	ld DE, (cache_size)
	add HL,DE
	ld (cache_size),HL
	ld A,1
	ld (cache_state),A	;activate cache
	
	;increment sector
	ld A,(cache_end)
	inc A
	cp FS_LastSector+1
	jr c,FS_AddToCache_ValidSector
	
	;if end of the track , flush cache !
	call FS_FlushCache
	
	ld HL,(cache_address)
	ld DE,(cache_size)
	add HL,DE
	
	ld A,(current_track)
	ld B,A
	inc B					;next track
	ld C,FS_FirstSector	
	
	call FS_InitCache	;re-init cache
	
	ret
	
;sector is valid , add and finish	
.FS_AddToCache_ValidSector
	ld (cache_end),A
	ret
	
;*****************************
;*** LOAD SECTORS IN CACHE ***
;*****************************

.FS_FlushCache
	ld A,(cache_state)		;is cache valid ?	
	or A
	ret z

	ld A,5	;5 tries are enough
	ld (FS_FlushCacheError_count),A
.FS_FlushCacheRetry

	ld HL,(cache_address)
	ld DE,(cache_size)
	ld BC,(cache_sectors)
	call FDC_read			;read sectors
	jr nc,FS_FlushCacheError	
	ret
.FS_FlushCacheError
	push AF
	call FDC_DriveWaitReady
	call FDC_RetryTrack
	pop AF
	ex AF,AF'
FS_FlushCacheError_count	EQU $+1
	ld A,0
	dec A
	ld (FS_FlushCacheError_count),A
	or A
	jr nz,FS_FlushCacheRetry
	ld HL,FS_FlushCacheName
	push HL
	ex AF,AF'
	jp FDC_FatalError
	
.FS_FlushCacheName
	;str "FS_FLUSHCACHE"
	
;******************	
;*** INIT CACHE ***
;******************
; HL = address to write , C = sector , B = track
.FS_InitCache
	ld A,0
	ld (cache_state),A
	ld (cache_size),A
	ld (cache_size+1),A		;cache is empty

	ld (cache_address),HL
	ld A,C
	ld (cache_start),A
	ld (cache_end),A
	
	;setup track now
	ld A,(current_track)
	cp B
	ret z	;is already on good track
	
	ld A,B
	call FDC_track
	ret
	
	
	
	
;*****************************
;*** GET FILE IN DIRECTORY ***
;*****************************
; HL = directory
; DE = filename
; return carry if success
; A = flags (head) , DE = size , BC = first track,sector
.FS_GetFile
	ld C,64	;fixed ! we have 64 entries , not 32
.FS_GetFileLoopA
	ld B,11
	
	push DE
	push HL
	
.FS_GetFileLoopCompare
	ld A,(HL)
	cp #FF							;if char = #FF filename not valid
	jr z,FS_GetFileNotFound
	ld A,(DE)
	cp (HL)
	jr nz,FS_GetFileNotFound
	inc HL
	inc DE
	djnz FS_GetFileLoopCompare
	
	pop DE
	pop DE
	
	;so it is the good file
	ld A,(HL) 		;get flags
	inc HL
	ld B,(HL)		;track in B
	inc HL
	ld C,(HL)		;sector in C
	inc HL
	ld E,(HL)
	inc HL
	ld D,(HL)		;size in DE
	
	scf ;set carry
	ret	

.FS_GetFileNotFound
	djnz FS_GetFileLoopCompare
	pop HL
	ld DE,16
	add HL,DE
	pop DE
	dec C
	jr nz,FS_GetFileLoopA
	
	or A	;not found so no carry
	ret

;only needed for 3"
IFNOT FDC_3P5	
.current_side
	db 0
ENDIF
	
.cache_state
	db 0
	
	;correct order , last before !
.cache_sectors
.cache_end		;last sector the cache
	db 0
.cache_start	;first sector of the cache
	db 0
	
.cache_size
	dw 0		;data ammount in the cache
.cache_address
	dw 0		;where to write datas
	
.bytes_to_read	;files bytes to read
	dw	0
	
.FS_LastFile
	dw 0		;point to last file used
	
;low level code
read "FDC_code.asm"

;decompressor
read "deexo.asm"