// // program to simulate checkbook, sort of -- maintain list of transactions // (debits and credits) and current balance, allow some simple queries of // transactions // // each transaction will consist of an amount, "debit" or "credit", // and a line of text to identify it (e.g., "paycheck" or "rent") // // transactions can be read from a file, and saved at end // import scala.io.Source import java.io.PrintWriter import java.io.File case class Transaction(amount : Int, kind : String, descrip : String) val Prompt = """enter one of: d for debit c for credit h for transaction history s to search transactions q to quit""" if (args.length < 1) { println("need command-line argument (name of file, - for none)") sys.exit(1) } val fileName = args(0) var balance = 0 var transactions = List[Transaction]() if (fileName != "-") { getSavedInfo(fileName) } var choice = ' ' do { println("\ncurrent balance $" + balance) println(Prompt) choice = readChar choice match { case 'd' | 'c' => { getTransaction(choice) } case 'h' => { println(transactions.length + " transactions available") println("how many to display?") val count = readInt transactions.take(count).foreach(elem => printTransaction(elem)) } case 's' => { println("text to search for:") val s = readLine transactions.filter(trans => descrMatch(trans, s)). foreach(elem => printTransaction(elem)) } case 'q' => { } case _ => { println("invalid choice") } } } while (choice != 'q') println("ending balance $" + balance) println("name of file to save info?") if (fileName != "-") { println("(blank to reuse " + fileName + ")") } val fileName2 = readLine.trim saveInfo(if (fileName2 == "") fileName else fileName2) def getTransaction(choice : Char) { println("enter amount (integer)") try { val amount = readLine.trim.toInt println("enter description (line of text)") val descrip = readLine choice match { case 'd' => { debit(amount, descrip) } case 'c' => { credit(amount, descrip) } case _ => { } // FIXME should this be an error? } } catch { case e:java.lang.NumberFormatException => { println("invalid amount") } } } def debit(amt : Int, descrip : String) { balance -= amt transactions = Transaction(amt, "debit", descrip) :: transactions } def credit(amt : Int, descrip : String) { balance += amt transactions = Transaction(amt, "credit", descrip) :: transactions } def printTransaction(t : Transaction) { println(t.kind + " $" + t.amount + " (" + t.descrip + ")") } def descrMatch(trans : Transaction, searchText : String) : Boolean = { trans.descrip.contains(searchText) } def getSavedInfo(fileName : String) { try { val source = scala.io.Source.fromFile(fileName) for (line <- source.getLines) { val parts = line.split(",") if (parts.length != 3) { println("invalid input (not enough fields)") sys.exit(1) } val kind = parts(0) val amt = parts(1).trim.toInt val descrip = parts(2).trim kind match { case "debit" => debit(amt, descrip) case "credit" => credit(amt, descrip) case _ => { println("invalid input (not debit/credit)") sys.exit(1) } } } source.close() } catch { case e:java.io.FileNotFoundException => { println("could not open file: " + e.getMessage) sys.exit(1) } case e:java.io.IOException => { println("error reading file: " + e.getMessage) sys.exit(1) } case e:java.lang.NumberFormatException => { println("invalid input (not numeric): " + e.getMessage) sys.exit(1) } } } def saveInfo(fileName : String) { try { val pw = new PrintWriter(new File(fileName)) transactions.reverse.foreach(t => { pw.println(t.kind + ", " + t.amount + ", " + t.descrip) } ) pw.close() println("saved to file " + fileName) } catch { case e:java.io.IOException => { println("error saving file: " + e.getMessage) } } }