class BANK create run feature {NONE} -- Implementation store: BANK_STORE over: BOOLEAN last_error: STRING data_file: RAW_FILE data_filename: STRING = "bank.data" fd: FORMAT_DOUBLE feature {NONE} -- Initialization run do create fd.make(2, 2) create store.make(100) store.ranges.account.interest_deposit := [0.01, 0.04] store.ranges.account.interest_debit := [0.02, 0.1] store.ranges.account.creditline := [-1000.0, 0.0] store.ranges.studentaccount.interest_deposit := [0.02, 0.03] store.ranges.studentaccount.interest_debit := [0.03, 0.06] store.ranges.studentaccount.creditline := [-300.0, 0.0] store.ranges.retireeaccount.interest_deposit := [0.02, 0.03] store.ranges.retireeaccount.interest_debit := [0.03, 0.06] store.ranges.retireeaccount.creditline := [-300.0, 0.0] create last_error.make_empty create data_file.make (data_filename) if data_file.exists then data_file.open_read store ?= store.retrieved (data_file) data_file.close end session if data_file.is_creatable then data_file.open_write store.independent_store (data_file) data_file.close end end feature -- Basic operations --fail_kovariant local retiree: RETIREE student: STUDENT studentaccount: STUDENTACCOUNT account: ACCOUNT do -- studi account mit normalen studi erstellen create retiree.make("a", "b") create student.make("a", "b") create studentaccount.make (student, 0.01, 0.02, -50.0, [0.01, 0.022], [0.01, 0.02], [-100.0, -50.0]) account := studentaccount -- upcast, account erwartet PERSON -- compiler akzeptiert das folgende, weil PERSON erwartet wird -- eigtl ist es eben ein studi acc, der RETIREES nicht akzeptiert, also laufzeitfehler account.add_authorized_signer (retiree) end session do -- das auskommentieren, dann bekommt ihr eine exception wegen kovariant (das ist ein methodenaufruf): fail_kovariant from until over loop main_screen end end print_last_error do if not last_error.is_empty then print (last_error + "%N%N") last_error := "" end end print_header do clear_screen print ("**************************************%N") print ("********* BANK of FOOP *********%N") print ("**************************************%N") end clear_screen do io.put_character ((0x1B).to_character_8) io.put_string ("[2J") io.put_character ((0x1B).to_character_8) io.put_string ("[H") end main_screen do print_header print ("Operations:%N") print (" r ...list/edit global ranges%N") print (" p ...list/create/edit/delete persons%N") print (" a ...list/create/edit/delete accounts%N") print (" q ...quit%N") print ("%N") print_last_error print ("Enter a command, followed by : ") io.read_character io.next_line inspect io.last_character.lower when 'r' then ranges_screen when 'p' then persons_screen when 'a' then accounts_screen when 'q' then over := True else last_error := "Error: Unknown command '" + io.last_character.out + "'" end print ("%N%N") end ranges_screen local back: BOOLEAN do from until back loop print_header print ("Global Ranges:%N") print (" Account:%N") print_ranges(store.ranges.account) print (" Student account:%N") print_ranges(store.ranges.studentaccount) print (" Retiree account:%N") print_ranges(store.ranges.retireeaccount) print ("%N") print ("Operations:%N") print (" a ...edit account ranges%N") print (" s ...edit student account ranges%N") print (" r ...edit retiree account ranges%N") print (" b ...back%N") print ("%N") print_last_error print ("Enter a command, followed by : ") io.read_character io.next_line inspect io.last_character.lower when 'a' then edit_ranges("account", store.ranges.account) when 's' then edit_ranges("student account", store.ranges.studentaccount) when 'r' then edit_ranges("retiree account", store.ranges.retireeaccount) when 'b' then back := True else last_error := "Error: Unknown command '" + io.last_character.out + "'" end print ("%N%N") end end print_ranges(range: like {BANK_STORE}.account_range) do print (" - Interest deposit: " + print_range(range.interest_deposit) + "%N") print (" - Interest debit: " + print_range(range.interest_debit) + "%N") print (" - Creditline: " + print_range(range.creditline) + "%N") end print_range(range: like {BANK_STORE}.range): STRING_8 do Result := "[" + fd.formatted(range.min) + ", " + fd.formatted(range.max) + "]" end edit_ranges(type: STRING_8; range: like {BANK_STORE}.account_range) do print ("%N") print ("Edit " + type + " range:%N") edit_range("interest depost", range.interest_deposit) edit_range("interest debit", range.interest_debit) edit_range("creditline", range.creditline) end edit_range(type: STRING_8; range: like {BANK_STORE}.range) local back: BOOLEAN do from back := False until back loop print ("Enter " + type + " minimum [" + fd.formatted(range.min) + "]: ") io.readline if io.last_string.is_double then range.min := io.last_string.to_double back := True elseif io.last_string.is_empty then back := True else print ("Invalid value%N") end end from back := False until back loop print ("Enter " + type + " maximum [" + fd.formatted(range.max) + "]: ") io.readline if io.last_string.is_double then range.max := io.last_string.to_double back := True elseif io.last_string.is_empty then back := True else print ("Invalid value%N") end end end persons_screen local back: BOOLEAN do from until back loop print_header print ("Operations:%N") print (" l ...list persons%N") print (" c ...create person%N") print (" e ...edit person%N") print (" d ...delete person%N") print (" b ...back%N") print ("%N") print_last_error print ("Enter a command, followed by : ") io.read_character io.next_line inspect io.last_character.lower when 'l' then list_persons print ("Press to go back") io.read_line when 'c' then create_persons when 'e' then edit_person when 'd' then delete_person when 'b' then back := True else last_error := "Error: Unknown command '" + io.last_character.out + "'" end print ("%N%N") end end list_persons do print ("%N") print ("Persons: " + store.persons.count.out + "%N") from store.persons.start until store.persons.off loop print ("#" + store.persons.index.out + " " + store.persons.item.surname + ", " + store.persons.item.firstname) if attached {RETIREE} store.persons.item then print (" (RETIREE)") elseif attached {STUDENT} store.persons.item then print (" (STUDENT)") end print ("%N") store.persons.forth end print ("%N") end create_persons local back: BOOLEAN firstname: STRING surname: STRING do from until back loop print_header print ("Operations:%N") print (" p ...create person%N") print (" s ...create student%N") print (" r ...create retiree%N") print (" b ...back%N") print ("%N") print_last_error print ("Enter a command, followed by : ") io.read_character io.next_line inspect io.last_character.lower when 'p', 's', 'r' then print ("Enter surname: ") io.readline surname := io.last_string.twin print ("Enter firstname: ") io.readline firstname := io.last_string.twin inspect io.last_character.lower when 'p' then store.persons.put(create {PERSON}.make(surname, firstname)) when 's' then store.persons.put(create {STUDENT}.make(surname, firstname)) when 'r' then store.persons.put(create {RETIREE}.make(surname, firstname)) else end last_error := "Person (#" + store.persons.count.out + ") created successfully" back := True when 'b' then back := True else last_error := "Error: Unknown command '" + io.last_character.out + "'" end print ("%N%N") end rescue if not (create {EXCEPTIONS}).is_signal then last_error := "Exception: " + (create {EXCEPTIONS}).tag_name retry end end edit_person local back: BOOLEAN num: INTEGER do list_persons from until back loop print_last_error print ("Enter person id (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_integer then num := io.last_string.to_integer if store.persons.valid_index (num) then store.persons.go_i_th (num) print ("Enter surname [" + store.persons.item.surname + "]: ") io.readline if not io.last_string.is_empty then store.persons.item.surname := io.last_string.twin end print ("Enter firstname [" + store.persons.item.firstname + "]: ") io.readline if not io.last_string.is_empty then store.persons.item.firstname := io.last_string.twin end last_error := "Person (#" + num.out + ") edited successfully" back := True else last_error := "Error: Invalid person id" end elseif io.last_string.is_equal ("b") then back := True else last_error := "Error: Not a number" end end end delete_person local back: BOOLEAN do list_persons from until back loop print_last_error print ("Enter person id (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_integer then if store.persons.valid_index (io.last_string.to_integer) then store.persons.go_i_th (io.last_string.to_integer) store.persons.remove last_error := "Person (#" + io.last_string + ") removed successfully" back := True else last_error := "Error: Invalid person id" end elseif io.last_string.is_equal ("b") then back := True else last_error := "Error: Not a number" end end end accounts_screen local back: BOOLEAN done: BOOLEAN do from until back loop print_header print ("Operations:%N") print (" l ...list accounts%N") print (" c ...create account%N") print (" e ...edit account%N") print (" d ...delete account%N") print (" b ...back%N") print ("%N") print_last_error print ("Enter a command, followed by : ") io.read_character io.next_line inspect io.last_character.lower when 'l' then list_accounts from done := False until back or done loop print ("Enter account id for details (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_integer then if store.accounts.valid_index (io.last_string.to_integer) then store.accounts.go_i_th (io.last_string.to_integer) print ("%N") print ("Account #" + store.accounts.index.out + ":%N") list_account_details(store.accounts.item) print ("Press to go back") io.read_line done := True else print ("Error: Invalid account id%N%N") end elseif io.last_string.is_equal("b") then done := True else print ("Error: Not a number%N%N") end end when 'c' then create_accounts when 'e' then edit_accounts when 'd' then delete_account when 'b' then back := True else last_error := "Error: Unknown command '" + io.last_character.out + "'" end print ("%N%N") end end list_accounts local account: ACCOUNT person: PERSON do print ("%N") print ("Accounts: " + store.accounts.count.out + "%N") from store.accounts.start until store.accounts.off loop account := store.accounts.item account.get_authorized_signers.linear_representation.start person := account.get_authorized_signers.linear_representation.item print ("#" + store.accounts.index.out + " " + person.surname + ", " + person.firstname) if attached {RETIREEACCOUNT} account then print (" (RETIREE ACCOUNT)") elseif attached {STUDENTACCOUNT} account then print (" (STUDENT ACCOUNT)") end print ("%N") store.accounts.forth end print ("%N") end list_account_details(account: ACCOUNT) local person: PERSON range: like {BANK_STORE}.account_range do range := store.ranges.account if attached {RETIREEACCOUNT} account then range := store.ranges.retireeaccount elseif attached {STUDENTACCOUNT} account then range := store.ranges.studentaccount end print (" - Balance: " + fd.formatted(account.balance) + "%N") print (" - Interest deposit: " + fd.formatted(account.interest_deposit) + " " + print_range(range.interest_deposit) + "%N") print (" - Interest debit: " + fd.formatted(account.interest_debit) + " " + print_range(range.interest_debit) +"%N") print (" - Creditline: " + fd.formatted(account.creditline) + " " + print_range(range.creditline) +"%N") print (" - Minimum transfer amount: " + fd.formatted(account.transfer_minamount) +"%N") print (" - Authorized signers:%N") from account.get_authorized_signers.linear_representation.start until account.get_authorized_signers.linear_representation.off loop person := account.get_authorized_signers.linear_representation.item print (" - #" + account.get_authorized_signers.linear_representation.index.out + " " + person.surname + ", " + person.firstname) if attached {RETIREE} person then print (" (RETIREE)") elseif attached {STUDENT} person then print (" (STUDENT)") end print ("%N") account.get_authorized_signers.linear_representation.forth end print (" - Type: ") if attached {RETIREEACCOUNT} account then print ("Retiree account") elseif attached {STUDENTACCOUNT} account then print ("Student account") else print ("Account") end print ("%N%N") end create_accounts local back: BOOLEAN do from until back loop print_header print ("Operations:%N") print (" a ...create account%N") print (" s ...create student account%N") print (" r ...create retiree account%N") print (" b ...back%N") print ("%N") print_last_error print ("Enter a command, followed by : ") io.read_character io.next_line inspect io.last_character.lower when 'a' then back := create_account('a', store.ranges.account) when 's' then back := create_account('s', store.ranges.studentaccount) when 'r' then back := create_account('r', store.ranges.retireeaccount) when 'b' then back := True else last_error := "Error: Unknown command '" + io.last_character.out + "'" end print ("%N%N") end rescue if not (create {EXCEPTIONS}).is_signal then last_error := "Exception: " + (create {EXCEPTIONS}).tag_name retry end end create_account(type: CHARACTER; range: like {BANK_STORE}.account_range): BOOLEAN local back: BOOLEAN next: BOOLEAN interest_deposit: like {ACCOUNT}.interest_deposit interest_debit: like {ACCOUNT}.interest_debit creditline: like {ACCOUNT}.creditline do Result := false interest_deposit := (range.interest_deposit.min + range.interest_deposit.max) / 2 interest_debit := (range.interest_debit.min + range.interest_debit.max) / 2 creditline := (range.creditline.min + range.creditline.max) / 2 print_last_error from next := False list_persons until back or next loop print ("Enter person (authorized signer) id (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_integer then if store.persons.valid_index (io.last_string.to_integer) then store.persons.go_i_th (io.last_string.to_integer) next := True else print ("Error: Invalid person id%N%N") end elseif io.last_string.is_equal ("b") then back := True else print ("Error: Not a number%N%N") end end from next := False until back or next loop print ("Enter interest deposit " + print_range(range.interest_deposit) + " [" + fd.formatted(interest_deposit) + "] (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_empty then next := True elseif io.last_string.is_double then interest_deposit := io.last_string.to_double next := True elseif io.last_string.is_equal ("b") then back := True else print ("Error: Invalid interest deposit number%N%N") end end from next := False until back or next loop print ("Enter interest debit " + print_range(range.interest_debit) + " [" + fd.formatted(interest_debit) + "] (b ...back):") io.readline io.last_string.to_lower if io.last_string.is_empty then next := True elseif io.last_string.is_double then interest_debit := io.last_string.to_double next := True elseif io.last_string.is_equal ("b") then back := True else print ("Error: Invalid interest debit number%N%N") end end from next := False until back or next loop print ("Enter creditline " + print_range(range.creditline) + " [" + fd.formatted(creditline) + "] (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_empty then next := True elseif io.last_string.is_double then creditline := io.last_string.to_double next := True elseif io.last_string.is_equal ("b") then back := True else print ("Error: Invalid creditline number%N%N") end end if not back then inspect type when 'a' then store.accounts.put(create {ACCOUNT}.make(store.persons.item, interest_deposit, interest_debit, creditline, range.interest_deposit, range.interest_debit, range.creditline)) when 's' then store.accounts.put(create {STUDENTACCOUNT}.make(store.persons.item, interest_deposit, interest_debit, creditline, range.interest_deposit, range.interest_debit, range.creditline)) when 'r' then store.accounts.put(create {RETIREEACCOUNT}.make(store.persons.item, interest_deposit, interest_debit, creditline, range.interest_deposit, range.interest_debit, range.creditline)) else end last_error := "Account (#" + store.accounts.count.out + ") created successfully" Result := true back := True end end edit_accounts local back: BOOLEAN do list_accounts from until back loop print_last_error print ("Enter account id (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_integer then if store.accounts.valid_index (io.last_string.to_integer) then store.accounts.go_i_th (io.last_string.to_integer) edit_account(store.accounts.index, store.accounts.item) back := True else last_error := "Error: Invalid account id" end elseif io.last_string.is_equal ("b") then back := True else last_error := "Error: Not a number" end end end edit_account(index: INTEGER; account: ACCOUNT) local back: BOOLEAN do from until back loop print_header print ("Edit account #" + index.out + ":%N") list_account_details (account) print ("Operations:%N") print (" 1 ...edit interest deposit%N") print (" 2 ...edit interest debit%N") print (" 3 ...edit creditline%N") print (" 4 ...edit minimum transfer amount%N") print (" 5 ...add authorized signer%N") print (" 6 ...remove authorized signer%N") print (" 7 ...deposit%N") print (" 8 ...withdraw%N") print (" 9 ...transfer%N") print (" 0 ...advance%N") print (" b ...back%N") print ("%N") print_last_error print ("Enter a command, followed by : ") io.read_character io.next_line inspect io.last_character.lower when '1' then account.interest_deposit := edit_account_detail_double("interest deposit", account.interest_deposit) last_error := "Interest deposit changed successfully" when '2' then account.interest_debit := edit_account_detail_double("interest debit", account.interest_debit) last_error := "Interest debit changed successfully" when '3' then account.creditline := edit_account_detail_double("creditline", account.creditline) last_error := "Creditline changed successfully" when '4' then account.transfer_minamount := edit_account_detail_double("transfer miniumum amount", account.transfer_minamount) last_error := "Transfer minimum amount changed successfully" when '5' then if edit_account_add_asigner (account) then last_error := "Authorized signer added successfully" end when '6' then if edit_account_remove_asigner (account) then last_error := "Authorized signer removed successfully" end when '7' then if edit_account_deposit (account) then last_error := "Deposit successfully" end when '8' then if edit_account_withdraw (account) then last_error := "Widthdraw successfully" end when '9' then if edit_account_transfer (account) then last_error := "Transfer successfully" end when '0' then account.advance last_error := "Account advanced successfully" when 'b' then back := True else last_error := "Error: Unknown command '" + io.last_character.out + "'" end print ("%N%N") end rescue if not (create {EXCEPTIONS}).is_signal then last_error := "Exception: " + (create {EXCEPTIONS}).tag_name retry end end edit_account_detail_double(type: STRING_8; val: REAL_64): REAL_64 local back: BOOLEAN do Result := val from until back loop print ("Enter " + type + " [" + fd.formatted(val) + "]: ") io.readline if io.last_string.is_double then Result := io.last_string.to_double back := True elseif io.last_string.is_empty then back := True else print ("Error: Invalid value%N") end end end edit_account_add_asigner(account: ACCOUNT): BOOLEAN local back: BOOLEAN do Result := False from list_persons until back loop print_last_error print ("Enter person (authorized signer) id (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_integer then if store.persons.valid_index (io.last_string.to_integer) then store.persons.go_i_th(io.last_string.to_integer) account.add_authorized_signer (store.persons.item) Result := True back := True else last_error := "Error: Invalid person id" end elseif io.last_string.is_equal ("b") then back := True else last_error := "Error: Not a number" end end end edit_account_remove_asigner(account: ACCOUNT): BOOLEAN local back: BOOLEAN do Result := False from list_persons until back loop print_last_error print ("Enter person (authorized signer) id (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_integer then if store.persons.valid_index (io.last_string.to_integer) then store.persons.go_i_th(io.last_string.to_integer) account.remove_authorized_signer (store.persons.item) Result := True back := True else last_error := "Error: Invalid person id" end elseif io.last_string.is_equal ("b") then back := True else last_error := "Error: Not a number" end end end edit_account_deposit(account: ACCOUNT): BOOLEAN local back: BOOLEAN amount: like {ACCOUNT}.balance do Result := False from until back loop print_last_error if amount = 0.0 and last_error.is_empty and not back then print ("Enter deposit amount (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_double and io.last_string.to_double > 0.0 then amount := io.last_string.to_double elseif io.last_string.is_equal("b") then back := True else last_error := "Error: Invalid value" end end if last_error.is_empty and not back then list_persons print ("Enter person (authorized signer) id (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_integer then if store.persons.valid_index (io.last_string.to_integer) then store.persons.go_i_th(io.last_string.to_integer) account.deposit (amount, store.persons.item) Result := True back := True else last_error := "Error: Invalid person id" end elseif io.last_string.is_equal ("b") then back := True else last_error := "Error: Not a number" end end end end edit_account_withdraw(account: ACCOUNT): BOOLEAN local back: BOOLEAN amount: like {ACCOUNT}.balance do Result := False from until back loop print_last_error if amount = 0.0 and last_error.is_empty and not back then print ("Enter withdraw amount (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_double and io.last_string.to_double > 0.0 then amount := io.last_string.to_double elseif io.last_string.is_equal("b") then back := True else last_error := "Error: Invalid value" end end if last_error.is_empty and not back then list_persons print ("Enter person (authorized signer) id (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_integer then if store.persons.valid_index (io.last_string.to_integer) then store.persons.go_i_th(io.last_string.to_integer) account.withdraw (amount, store.persons.item) Result := True back := True else last_error := "Error: Invalid person id" end elseif io.last_string.is_equal ("b") then back := True else last_error := "Error: Not a number" end end end end edit_account_transfer(account: ACCOUNT): BOOLEAN local back: BOOLEAN amount: like {ACCOUNT}.balance signer: PERSON recipient: ACCOUNT do Result := False from until back loop print_last_error if amount = 0.0 and last_error.is_empty and not back then print ("Enter transfer amount (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_double and io.last_string.to_double > 0.0 then amount := io.last_string.to_double elseif io.last_string.is_equal("b") then back := True else last_error := "Error: Invalid value" end end print (signer) if signer = Void and last_error.is_empty and not back then list_persons print ("Enter person (authorized signer) id (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_integer then if store.persons.valid_index (io.last_string.to_integer) then store.persons.go_i_th(io.last_string.to_integer) signer := store.persons.item else last_error := "Error: Invalid person id" end elseif io.last_string.is_equal ("b") then back := True else last_error := "Error: Not a number" end end print (recipient) if recipient = Void and last_error.is_empty and not back then list_accounts print ("Enter recipient account id (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_integer then if store.accounts.valid_index (io.last_string.to_integer) then store.accounts.go_i_th(io.last_string.to_integer) recipient := store.accounts.item else last_error := "Error: Invalid account id" end elseif io.last_string.is_equal ("b") then back := True else last_error := "Error: Not a number" end end if last_error.is_empty and not back then list_persons print ("Enter person (authorized signer) id (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_integer then if store.persons.valid_index (io.last_string.to_integer) then store.persons.go_i_th(io.last_string.to_integer) account.transfer (amount, signer, recipient, store.persons.item) Result := True back := True else last_error := "Error: Invalid person id" end elseif io.last_string.is_equal ("b") then back := True else last_error := "Error: Not a number" end end end end delete_account local back: BOOLEAN do list_accounts from until back loop print_last_error print ("Enter account id (b ...back): ") io.readline io.last_string.to_lower if io.last_string.is_integer then if store.accounts.valid_index (io.last_string.to_integer) then store.accounts.go_i_th (io.last_string.to_integer) store.accounts.remove last_error := "Account (#" + io.last_string + ") removed successfully" back := True else last_error := "Error: Invalid account id" end elseif io.last_string.is_equal ("b") then back := True else last_error := "Error: Not a number" end end end end