package mulCal.history;
import static mulCal.main.util.Base10toN;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.TreeMap;
import lib.au.com.bytecode.opencsv.CSVReader;
import lib.au.com.bytecode.opencsv.CSVWriter;
import mulCal.equationParser.EvalSpecial;
import mulCal.util.KeyException;
/*
---- CSV Example ----
a, "7.23" , 7.23 , "pounds per hour"
b, "a * 8" , 57.84 , "daily wage"
c, "(b/8)/3" , 2.41 , ""
d, "GBP_USD b" , 76.93 , "daily USD"
e, "d * [days 2010/2/4 2010/2/11]" , 846.20 , "final value"
*/
public class History {
public static class HistoryItem {
public String id;
public String equation;
public BigDecimal result;
public String comment;
public HistoryItem(String id, String equation, BigDecimal result) {
this.id = id;
this.equation = equation;
this.result = result;
this.comment = "";
}
public boolean SanityCheck() {
// all not null
// id,equation not zero length
// TODO: id,equation,comment only contain valid chars (no ")
// OPTIONAL: eval(equation) == result
if (this.id == null ||
this.equation == null ||
this.result == null ||
this.comment == null ||
this.id.length() == 0 ||
this.equation.length() == 0) {
return false;
}
return true;
}
}
private static String asciiUpperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private TreeMap<String, HistoryItem> items;
private int currentID;
public History() {
this.currentID = 0;
this.items = new TreeMap<String, HistoryItem>();
}
public void Load(String fileName) throws IOException {
// e, "d * [days 2010/2/4 2010/2/11]" , 846.20 , "final value"
// TODO: if you don't want to reset then properly deal with giving the loaded items new id's.
reset();
CSVReader reader = new CSVReader(new FileReader(fileName));
try {
String [] line;
while ((line = reader.readNext()) != null) {
// nextLine[] is an array of values from the line
if (line.length != 4) {
throw new IllegalArgumentException("History.Load: Error with row insertion");
}
String id = line[0];
String equation = line[1];
BigDecimal result = new BigDecimal(line[2]);
HistoryItem row = new HistoryItem(id, equation, result);
row.comment = line[3];
if (this.InsertOK(row)) {
this.items.put(row.id, row);
}
else {
throw new IllegalArgumentException("History.Load: Error with row insertion");
}
}
} finally {
reader.close();
}
}
public void Save(String fileName) throws IOException {
CSVWriter writer = new CSVWriter(new FileWriter(fileName), ',');
try {
for (HistoryItem item : this.items.values()) {
String[] entries = new String[4];
item.SanityCheck();
entries[0] = item.id;
entries[1] = item.equation;
entries[2] = item.result.toPlainString();
entries[3] = item.comment;
writer.writeNext(entries);
}
} finally {
writer.close();
}
}
public void reset() {
this.currentID = 0;
this.items.clear();
}
public void SetComment(String id, String comment) throws KeyException {
if (this.items.containsKey(id)) {
HistoryItem item = this.items.get(id);
item.comment = comment;
this.items.put(item.id, item);
} else {
throw new KeyException("History.SetComment: Cannot find history item " + id);
}
}
public String Add(String equation, BigDecimal result) {
String id = this.NewID();
HistoryItem item = new HistoryItem(id, equation, result);
if (this.InsertOK(item)) {
this.items.put(id, item);
return id;
} else {
throw new IllegalArgumentException("History.Add: Error with row insertion");
}
}
public Collection<HistoryItem> getAll() {
return this.items.values();
}
public HistoryItem get(String id) throws KeyException {
if (this.items.containsKey(id)) {
return this.items.get(id);
} else {
throw new KeyException("History.get: Cannot find history item " + id);
}
}
public boolean ContainsID(String id) {
return this.items.containsKey(id);
}
public int size() {
return this.items.size();
}
private String NewID() {
// could check that it doesn't match any keywords
// but if we ensure functions all start in lowercase we are ok
// returns one at a time: 'A', 'B', 'C', ..., 'BA', 'BB', ..., 'ZZZZ...'
// make sure we don't match any constants
String result;
do {
result = Base10toN(this.currentID, History.asciiUpperCase);
this.currentID += 1;
} while (EvalSpecial.constants.containsKey(result));
return result;
}
private boolean InsertOK(HistoryItem row) {
if (row.SanityCheck() == false) {
return false;
}
if (this.items.containsKey(row.id)) {
return false;
}
return true;
}
public String lookupIdFromRow(int rowIndex) {
int count=0;
for (String id : items.navigableKeySet()) {
if (rowIndex == count)
return id;
count+=1;
}
throw new RuntimeException("History.lookupIdFromRow: Programmer error - key error " + rowIndex);
}
}