TITLE	assem3.asm
COMMENT $
	Author:		Aaron Gadberry
	Submitted for:	Programming Project 2
	Submitted to:	Dr. Lee Koh
	Date:		December 4th, 2002
	Description:	This program sets up a very basic database using side by side arrays.
			There are two variables inside each record, Employe e ID Number and
			Social Security Number.  The operations that can be performed on the
			database are

			1) Initialize all records to 0 (clear database)
			2) Add record
			3) Display all records
			4) Search by EID and select record which matches
			5) Search by SSN and select record which matches
			6) Delete selected record
			7) Sort database in ascending order by EID
			8) Sort database in ascending order by SSN
			9) Quit
			
			Each of these operations are represented as menu options and call upon
			seperate procedures when selected.  The procedures are outlined in further
			detail where they appear in this document.
$

INCLUDE Irvine16.inc

		.DATA
; put your arrays and other data here
arrayEID	DWORD	100 dup (0)
arraySSN	DWORD	100 dup (0)
BPE = TYPE arrayEID
maxsize		DWORD	100
arraySize	DWORD	0
currentEID	DWORD	0
currentSSN	DWORD	0
currentRecord	DWORD	9999
searchvalue	DWORD	0
		.CODE 
Driver		PROC
		MOV	AX, @DATA 
                MOV	DS, AX 
TOP:        
		CALL	DisplayMenu 
		CALL	GetChoice
		CALL	ProcessChoice
		JMP	TOP

                exit 

Driver          ENDP 


;--------------------------------------------------------------------
; The DisplayMenu proc displays the 9 menu items from which the user
; can choose one at a time.  The options are self explanatory and can be
; seen directly below.
;--------------------------------------------------------------------
DisplayMenu	PROC USES EDX
		.DATA
menuLine1	BYTE "1. Initialize database", 0 
menuLine2	BYTE "2. Insert employee", 0 
menuLine3	BYTE "3. Display all data", 0 
menuLine4	BYTE "4. Search on EID", 0 
menuLine5	BYTE "5. Search on SSN", 0 
menuLine6	BYTE "6. Delete employee", 0 
menuLine7	BYTE "7. Sort by EID", 0 
menuLine8	BYTE "8. Sort by SSN", 0 
menuLine9	BYTE "9. Quit", 0 
		.CODE
		CALL	Crlf 
		MOV	EDX, OFFSET menuLine1
		CALL	WriteString
		CALL	Crlf 
		MOV	EDX, OFFSET menuLine2
		CALL	WriteString
		CALL	Crlf 
		MOV	EDX, OFFSET menuLine3
		CALL	WriteString
		CALL	Crlf 
		MOV	EDX, OFFSET menuLine4
		CALL	WriteString
		CALL	Crlf 
		MOV	EDX, OFFSET menuLine5
		CALL	WriteString
		CALL	Crlf 
		MOV	EDX, OFFSET menuLine6
		CALL	WriteString
		CALL	Crlf 
		MOV	EDX, OFFSET menuLine7
		CALL	WriteString
		CALL	Crlf 
		MOV	EDX, OFFSET menuLine8
		CALL	WriteString
		CALL	Crlf 
		MOV	EDX, OFFSET menuLine9
		CALL	WriteString
		CALL	Crlf
		RET
DisplayMenu	ENDP		


;--------------------------------------------------------------------
; The GetChoice proc gets and validates a choice for the main menu.
; The choice is stored in EAX.
;--------------------------------------------------------------------
GetChoice	PROC USES EDX
		.DATA
prompt		BYTE "Your choice? (1...9) ", 0 
bad_choice	BYTE "...invalid choice...try again...", 0
		.CODE
TOP:		
		CALL    Crlf
		MOV     EDX, OFFSET prompt
		CALL	WriteString
		CALL	ReadInt
		JNC	VALID_INT
INVALID_CHOICE:		
		CALL	Crlf
		MOV	EDX, OFFSET bad_choice
		CALL	WriteString
		CALL	Crlf
		JMP	TOP
VALID_INT:		
		CALL	Crlf
		CMP	EAX, 1
		JL	INVALID_CHOICE
		CMP	EAX, 9
		JG	INVALID_CHOICE
		RET
GetChoice	ENDP		


;--------------------------------------------------------------------
; The ProcessChoice proc evaluates the main menu choice given, stored
; in EAX, and determines which subproc to call based on the value.
;--------------------------------------------------------------------
ProcessChoice	PROC
		PUSHFD
CHECK1:
		CMP	EAX, 1
		JNE	CHECK2
		CALL	Init 
                JMP	DONE
CHECK2:
		CMP	EAX, 2
		JNE	CHECK3
                CALL	Insert 
                JMP	DONE
CHECK3:
		CMP	EAX, 3
		JNE	CHECK4
                CALL	Display 
                JMP	DONE
CHECK4:
		CMP	EAX, 4
		JNE	CHECK5
                CALL	FindEid 
                JMP	DONE
CHECK5:
		CMP	EAX, 5
		JNE	CHECK6
                CALL	FindSsn 
                JMP	DONE
CHECK6:
		CMP	EAX, 6
		JNE	CHECK7
                CALL	Delete 
                JMP	DONE
CHECK7:
		CMP	EAX, 7
		JNE	CHECK8
                CALL	SortEid 
                JMP	DONE
CHECK8:
		CMP	EAX, 8
		JNE	CHECK9
                CALL	SortSsn 
                JMP	DONE
CHECK9:                
                CALL	Quit 
DONE:                
                POPFD
                RET
ProcessChoice	ENDP                


;--------------------------------------------------------------------
; The Init proc determines if the arrays need to be set to zero using
; the arraySize variable.  If so, it initializes only the previously
; filled elements to zero and sets arraySize to zero.
;--------------------------------------------------------------------
Init		PROC           
		.DATA
initMsg		BYTE "Database Initialized", 0 
		.CODE
		CMP	arraySize, 0
		JE	initempty
		MOV	ECX, arraySize
		MOV	EBX, 0

resetrecord:	MOV	[arrayEID + EBX], 0
		MOV	[arraySSN + EBX], 0
		ADD	EBX, BPE
		loop	resetrecord

initempty:	MOV	arraySize, 0
		MOV	currentRecord, 9999
                MOV	EDX, OFFSET initMsg
                CALL    Crlf
                CALL	WriteString
                CALL    Crlf

                RET
Init		ENDP                


;--------------------------------------------------------------------
; The Insert proc asks for input of a new EID between 100-999 and a
; new SSN between 1000-9999.  It validates the input for being within
; the specified range first, and then double checks against the current
; records for duplicates.  If any input can not be validated the user
; is prompted for the input again.  Once the input is validated it is
; appended to the end of the current arrays, the EID in arrayEID and
; the SSN in arraySSN.
;--------------------------------------------------------------------
Insert		PROC           
		.DATA
newEID		DWORD	0
newSSN		DWORD	0
insertEIDMsg	BYTE "Please enter new EID (100-999): ", 0
insertSSNMsg	BYTE "Please enter new SSN (1000-9999): ", 0
insertThankMsg	BYTE "New Record Created", 0
		.CODE
enterEID:       MOV	EDX, OFFSET insertEIDMsg
                CALL    Crlf
                CALL	WriteString
		CALL	ReadInt
		MOV	newEID, EAX
		CMP	newEID, 999
		JA	enterEID
		CMP	newEID, 100
		JB	enterEID

		CMP	arraySize, 0
		JE	enterSSN

		MOV	ECX, arraySize
		MOV	EBX, 0
		SUB	EBX, BPE
		MOV	EDX, newEID
icompareEID:	ADD	EBX, BPE
		CMP	EDX, [arrayEID + EBX]
		JE	enterEID
		loop	icompareEID

enterSSN:       MOV	EDX, OFFSET insertSSNMsg
                CALL    Crlf
                CALL	WriteString
		CALL	ReadInt
		MOV	newSSN, EAX
		CMP	newSSN, 9999
		JA	enterSSN
		CMP	newSSN, 1000
		JB	enterSSN

		CMP	arraySize, 0
		JE	igotboth

		MOV	ECX, arraySize
		MOV	EBX, 0
		SUB	EBX, BPE
		MOV	EDX, newSSN
icompareSSN:	ADD	EBX, BPE
		CMP	EDX, [arraySSN + EBX]
		JE	enterSSN
		loop	icompareSSN

igotboth:       MOV	EDX, OFFSET insertThankMsg
                CALL    Crlf
                CALL	WriteString
                CALL    Crlf

		MOV	EAX, 0
		MOV	AL, BPE
		MUL	arraySize

		MOV	EBX, newEID
		MOV	[arrayEID + EAX], EBX
		MOV	EBX, newSSN
		MOV	[arraySSN + EAX], EBX
		INC	arraySize
                RET
Insert		ENDP                


;--------------------------------------------------------------------
; The Display proc uses the arraySize in a counting loop to output the
; current contents of the arrays successively.
;--------------------------------------------------------------------
Display		PROC           
		.DATA
displayEIDMsg	BYTE "EID: ", 0 
displaySSNMsg	BYTE " SSN: ", 0 
displayerrorMsg	BYTE "Nothing to display...", 0
		.CODE
		CMP	arraySize, 0
		JE	displayerror
		MOV	ECX, arraySize
		MOV	EBX, 0

displayrecord:	MOV	EDX, OFFSET displayEIDMsg
		CALL    Crlf
		CALL	WriteString
		MOV	EAX, [arrayEID + EBX]
		CALL	WriteInt
		MOV	EDX, OFFSET displaySSNMsg
		CALL	WriteString
		MOV	EAX, [arraySSN + EBX]
		CALL	WriteInt
		ADD	EBX, BPE
		CALL    Crlf
		loop	displayrecord
		JMP	displayend

displayerror:	MOV	EDX, OFFSET displayerrorMsg
		CALL    Crlf
		CALL	WriteString
		CALL    Crlf

displayend:     RET
Display		ENDP                


;--------------------------------------------------------------------
; The FindEid proc compares the values of arrayEID to the search value
; one by one until it has a match.  This match's record offset is loaded
; into currentrecord, and it's SSN is loaded into currentSSN.  In the case
; of no match, an appropriate error msg is displayed.
;--------------------------------------------------------------------
FindEid		PROC
		.DATA
findEidMsg	BYTE "Enter EID to search for (100-999): ", 0 
findEidyesMsg	BYTE "EID found.  Matching SSN: ", 0 
findEidnoMsg	BYTE "EID not found.", 0 
		.CODE
entersearchEID:	MOV	EDX, OFFSET findEidMsg
                CALL    Crlf
                CALL	WriteString
		CALL	ReadInt
		CALL    Crlf
		MOV	searchvalue, EAX
		CMP	searchvalue, 999
		JA	entersearchEID
		CMP	searchvalue, 100
		JB	entersearchEID

		CMP	arraySize, 0
		JE	nofoundEID

		MOV	ECX, arraySize
		MOV	EBX, 0
		SUB	EBX, BPE
		MOV	EDX, searchvalue
compareEID:	ADD	EBX, BPE
		CMP	EDX, [arrayEID + EBX]
		JE	foundEID
		loop	compareEID
		JMP	nofoundEID

nofoundEID:	MOV	EDX, OFFSET findEidnoMsg
                CALL    Crlf
                CALL	WriteString
		CALL    Crlf
		JMP	findEidend
		MOV	currentEID, 0
		MOV	currentSSN, 0
		MOV	currentRecord, 9999

foundEID:       MOV	EDX, OFFSET findEidyesMsg
		CALL    Crlf
                CALL	WriteString
		MOV	EAX, [arraySSN + EBX]
		CALL	WriteInt
                CALL    Crlf
		MOV	EAX, [arrayEID + EBX]
		MOV	currentEID, EAX
		MOV	EAX, [arraySSN + EBX]
		MOV	currentSSN, EAX
		MOV	currentRecord, EBX

findEidend:      RET
FindEid		ENDP                


;--------------------------------------------------------------------
; The FindSsn proc compares the values of arraySSN to the search value
; one by one until it has a match.  This match's record offset is loaded
; into currentrecord, and it's EID is loaded into currentEID.  In the case
; of no match, an appropriate error msg is displayed.
;--------------------------------------------------------------------
FindSsn		PROC
		.DATA
findSsnMsg	BYTE "Enter SSN to search for (1000-9999): ", 0 
findSsnyesMsg	BYTE "SSN found.  Matching SSN: ", 0 
findSsnnoMsg	BYTE "SSN not found.", 0 
		.CODE
entersearchSSN:	MOV	EDX, OFFSET findSsnMsg
                CALL    Crlf
                CALL	WriteString
		CALL	ReadInt
		CALL    Crlf
		MOV	searchvalue, EAX
		CMP	searchvalue, 9999
		JA	entersearchSSN
		CMP	searchvalue, 1000
		JB	entersearchSSN

		CMP	arraySize, 0
		JE	nofoundSSN

		MOV	ECX, arraySize
		MOV	EBX, 0
		SUB	EBX, BPE
		MOV	EDX, searchvalue
compareSSN:	ADD	EBX, BPE
		CMP	EDX, [arraySSN + EBX]
		JE	foundSSN
		loop	compareSSN
		JMP	nofoundSSN

nofoundSSN:	MOV	EDX, OFFSET findEidnoMsg
                CALL    Crlf
                CALL	WriteString
		CALL    Crlf
		JMP	findSsnend
		MOV	currentSSN, 0
		MOV	currentEID, 0
		MOV	currentRecord, 9999

foundSSN:       MOV	EDX, OFFSET findEidyesMsg
		CALL    Crlf
                CALL	WriteString
		MOV	EAX, [arrayEID + EBX]
		CALL	WriteInt
                CALL    Crlf
		MOV	EAX, [arraySSN + EBX]
		MOV	currentSSN, EAX
		MOV	EAX, [arrayEID + EBX]
		MOV	currentEID, EAX
		MOV	currentRecord, EBX

findSsnend:     RET
FindSsn		ENDP                


;--------------------------------------------------------------------
; The Delete proc is used in combination with the FindEID and FindSsn
; procs.  Once a record is selected and it's offset is in currentRecord,
; then it can be deleted by running this proc.  This proc removes the
; record by writing the element to it's right over it, and so on, until
; the last element is actually one element to the left of it's previous
; position, the last element is filled with a zero, and the arraySize
; is reduced by 1.
;--------------------------------------------------------------------
Delete		PROC
		.DATA
deleteerrorMsg	BYTE "Use search to select a record before using delete.", 0 
deleteMsg	BYTE "Record deleted...", 0 
numtoshift	DWORD	0
		.CODE
		CMP	currentrecord, 9999
		JE	nodeleterecord

deleterecord:	MOV	EBX, currentRecord
		MOV	AL, BPE
		MUL	arraySize
		SUB	EAX, BPE
		MOV	ECX, EAX

		CMP	EBX, ECX
		JE	delcleanup

delshift:	MOV	EAX, [arrayEID + EBX + BPE]
		MOV	[arrayEID + EBX], EAX
		MOV	EAX, [arraySSN + EBX + BPE]
		MOV	[arraySSN + EBX], EAX
		ADD	EBX, BPE
		CMP	EBX, ECX
		JNE	delshift

delcleanup:	MOV	[arrayEID + EBX], 0
		MOV	[arraySSN + EBX], 0
		DEC	arraySize
		MOV	currentRecord, 9999
		MOV	EDX, OFFSET deleteMsg
                CALL    Crlf
                CALL	WriteString
                CALL    Crlf
		JMP	deleteend

nodeleterecord: MOV	EDX, OFFSET deleteerrorMsg
                CALL    Crlf
                CALL	WriteString
                CALL    Crlf

deleteend:      RET
Delete		ENDP                


;--------------------------------------------------------------------
; The SortEid proc uses bubble sort in order to arrange the records in
; ascending order.  First the proc checks to see if there are enough 
; records to successfully run a sort.  If there are either zero, or one
; elements in the array then it is already sorted, and an error message
; informs the user of this.  This version of bubble sort only runs through
; the sorting algorithm the minimum necessary number of times.  It compares
; each element to the one on it's right, and if needed swaps them to
; be in ascending order.  If any records are swapped then a flag is set
; which tells the algorithm to run again.  When the procedure
; successfully makes it through without any swaps, the flag is clear and
; the arrays are sorted.
;--------------------------------------------------------------------
SortEid		PROC
		.DATA
sortEidMsg	BYTE	"Records sorted by EID.", 0 
sortEIDerrorMsg	BYTE	"The database is already sorted", 0
		.CODE

sortEIDout:     MOV     ECX, arraySize
		DEC	ECX
		CMP	ECX, 0
		JLE	sortEIDerror

            
                MOV     EBX, 0
		MOV	ESI, BPE
		MOV	EDX, 0

sortEIDin:             
                MOV     EAX, [arrayEID + EBX] 
                CMP     [arrayEID + ESI], EAX
                JG      sortEIDskip
                XCHG    EAX, [arrayEID + ESI]
                MOV     [arrayEID + EBX], EAX
                MOV     EAX, [arraySSN + EBX]
                XCHG    EAX, [arraySSN + ESI]
                MOV     [arraySSN + EBX], EAX
		MOV	EDX, 1
sortEIDskip:             
                ADD     EBX, BPE
		ADD	ESI, BPE
		DEC	ECX
                CMP	ECX, 0
		JG	sortEIDin

		CMP	EDX, 1
		JE	sortEIDout
		MOV	EDX, OFFSET sortEidMsg
                CALL    Crlf
                CALL	WriteString
                CALL    Crlf
		JMP	sortEIDdone

sortEIDerror:	MOV	EDX, OFFSET sortEIDerrorMsg
		CALL    Crlf
		CALL	WriteString
		CALL    Crlf
		
sortEIDdone:

                RET
SortEid		ENDP      

;--------------------------------------------------------------------
; The SortSsn proc uses bubble sort in order to arrange the records in
; ascending order.  First the proc checks to see if there are enough 
; records to successfully run a sort.  If there are either zero, or one
; elements in the array then it is already sorted, and an error message
; informs the user of this.  This version of bubble sort only runs through
; the sorting algorithm the minimum necessary number of times.  It compares
; each element to the one on it's right, and if needed swaps them to
; be in ascending order.  If any records are swapped then a flag is set
; which tells the algorithm to run again.  When the procedure
; successfully makes it through without any swaps, the flag is clear and
; the arrays are sorted.
;--------------------------------------------------------------------
SortSsn		PROC
		.DATA
sortSsnMsg	BYTE	"Records sorted by SSN.", 0 
sortSSNerrorMsg	BYTE	"The database is already sorted", 0
		.CODE

sortSSNout:     MOV     ECX, arraySize
		DEC	ECX
		CMP	ECX, 0
		JLE	sortSSNerror

            
                MOV     EBX, 0
		MOV	ESI, BPE
		MOV	EDX, 0

sortSSNin:             
                MOV     EAX, [arraySSN + EBX] 
                CMP     [arraySSN + ESI], EAX
                JG      sortSSNskip
                XCHG    EAX, [arraySSN + ESI]
                MOV     [arraySSN + EBX], EAX
                MOV     EAX, [arrayEID + EBX]
                XCHG    EAX, [arrayEID + ESI]
                MOV     [arrayEID + EBX], EAX
		MOV	EDX, 1
sortSSNskip:             
                ADD     EBX, BPE
		ADD	ESI, BPE
		DEC	ECX
                CMP	ECX, 0
		JG	sortSSNin

		CMP	EDX, 1
		JE	sortSSNout
		MOV	EDX, OFFSET sortSsnMsg
                CALL    Crlf
                CALL	WriteString
                CALL    Crlf
		JMP	sortSSNdone

sortSSNerror:	MOV	EDX, OFFSET sortSsnerrorMsg
		CALL    Crlf
		CALL	WriteString
		CALL    Crlf
		
sortSSNdone:

                RET
SortSsn		ENDP            

                
;--------------------------------------------------------------------
; The Quit proc displays a simple Bye message and then exits the program.
;--------------------------------------------------------------------
Quit		PROC
		.DATA
byeMsg		BYTE "Bye...", 0 
		.CODE
                MOV	EDX, OFFSET byeMsg
                CALL    Crlf
                CALL	WriteString
                CALL    Crlf
		exit
                RET
Quit		ENDP                


		END	Driver