package com.bytezone.diskbrowser.visicalc; import java.text.DecimalFormat; class Cell implements Comparable, Value { private static final DecimalFormat nf = new DecimalFormat ("#####0.00"); final Address address; private final Sheet parent; private CellType cellType; private char cellFormat = ' '; private char repeatingChar; private String repeat = ""; private String label; private String expressionText; private Value value; private ValueType valueType; enum CellType { LABEL, REPEATING_CHARACTER, VALUE } public Cell (Sheet parent, Address address) { this.parent = parent; this.address = address; cellType = CellType.VALUE; // default to VALUE, formatting may change it valueType = ValueType.VALUE; } void format (String format) { // /FG - general // /FD - default // /FI - integer // /F$ - dollars and cents // /FL - left justified // /FR - right justified // /F* - graph (histogram) if (format.startsWith ("/F")) this.cellFormat = format.charAt (2); else if (format.startsWith ("/-")) { repeatingChar = format.charAt (2); for (int i = 0; i < 20; i++) repeat += repeatingChar; cellType = CellType.REPEATING_CHARACTER; } else System.out.printf ("Unexpected format [%s]%n", format); } void setValue (String command) { if (command.charAt (0) == '"') { label = command.substring (1); cellType = CellType.LABEL; } else { expressionText = command; cellType = CellType.VALUE; } // FUTURE.VC if (false) if (address.rowKey == 67) expressionText = "1000"; else if (address.rowKey == 131) expressionText = "10.5"; else if (address.rowKey == 195) expressionText = "12"; else if (address.rowKey == 259) expressionText = "8"; // IRA.VC if (false) if (address.rowKey == 66) expressionText = "10"; else if (address.rowKey == 130) expressionText = "30"; else if (address.rowKey == 194) expressionText = "65"; else if (address.rowKey == 258) expressionText = "1000"; else if (address.rowKey == 386) expressionText = "15"; // CARLOAN.VC if (false) if (address.rowKey == 67) expressionText = "9375"; else if (address.rowKey == 131) expressionText = "4500"; else if (address.rowKey == 195) expressionText = "24"; else if (address.rowKey == 259) expressionText = "11.9"; } String getText (int colWidth, char defaultFormat) { char format = cellFormat != ' ' ? cellFormat : defaultFormat; switch (cellType) { case LABEL: return justify (label, colWidth, cellFormat); case REPEATING_CHARACTER: return justify (repeat, colWidth, format); case VALUE: if (value.is (ValueType.ERROR) || value.is (ValueType.NA) || value.is (ValueType.NAN)) return justify (value.getText (), colWidth, format); Double thisValue = value.getValue (); if (format == 'I') { String integerFormat = String.format ("%%%d.0f", colWidth); return String.format (integerFormat, thisValue); } else if (format == '$') { String currencyFormat = String.format ("%%%d.%ds", colWidth, colWidth); return String.format (currencyFormat, nf.format (thisValue)); } else if (format == '*') { String graphFormat = String.format ("%%-%d.%ds", colWidth, colWidth); // this is not finished return String.format (graphFormat, "********************"); } else { // this could be improved String numberFormat = String.format ("%%%d.3f", colWidth + 4); String val = String.format (numberFormat, thisValue); while (val.endsWith ("0")) val = ' ' + val.substring (0, val.length () - 1); if (val.endsWith (".")) val = ' ' + val.substring (0, val.length () - 1); if (val.length () > colWidth) val = val.substring (val.length () - colWidth); return val; } } return getText (); } private String justify (String text, int colWidth, char format) { // right justify if (format == 'R' || format == '$' || format == 'I') { String labelFormat = String.format ("%%%d.%ds", colWidth, colWidth); return (String.format (labelFormat, text)); } // left justify String labelFormat = String.format ("%%-%d.%ds", colWidth, colWidth); return (String.format (labelFormat, text)); } @Override public double getValue () { assert cellType == CellType.VALUE; return value.getValue (); } @Override public ValueType getValueType () { return valueType; } @Override public String getText () { assert is (CellType.VALUE) : "Cell type: " + cellType; return value.getText (); } // @Override // public boolean isValue () // { // return type == CellType.VALUE; // } // // @Override // public boolean isError () // { // return value.isError (); // } // // @Override // public boolean isNotAvailable () // { // if (!isValue ()) // return true; // return value.isNotAvailable (); // } // // @Override // public boolean isNotANumber () // { // return value.isNotANumber (); // } @Override public boolean is (ValueType type) { return valueType == type; } public boolean is (CellType type) { return cellType == type; } @Override public Value calculate () { if (!is (CellType.VALUE)) { // System.out.println (value); return this; } assert is (CellType.VALUE) : "Cell type: " + cellType + " @ " + address; if (expressionText == null) { System.out.printf ("%s null expression text %n", address); value = Function.getInstance (parent, "@ERROR"); valueType = ValueType.ERROR; } else { // should use Number or Cell or Function for simple Values value = new Expression (parent, expressionText); value.calculate (); valueType = value.getValueType (); } return this; } @Override public String toString () { String contents = ""; switch (cellType) { case LABEL: contents = "Labl: " + label; break; case REPEATING_CHARACTER: contents = "Rept: " + repeatingChar; break; case VALUE: contents = "Exp : " + expressionText; break; } return String.format ("[Cell:%5s %s]", address, contents); } @Override public int compareTo (Cell o) { return address.compareTo (o.address); } }