refactoring

This commit is contained in:
Denis Molony 2016-03-08 20:39:35 +11:00
parent fd1ba9c15f
commit 2417e0aa07
3 changed files with 168 additions and 253 deletions

View File

@ -13,10 +13,9 @@ class Cell implements Comparable<Cell>
private String label;
private double value;
private String formula;
private String formulaText;
private char format = ' ';
private int width;
private char repeatingChar;
private String repeat = "";
private boolean valid;
@ -27,35 +26,31 @@ class Cell implements Comparable<Cell>
this.address = address;
}
void format (String format)
{
// /FG - general
// /FD - default
// /FI - integer
// /F$ - dollars and cents
// /FL - left justified
// /FR - right justified
// /F* - graph
if (format.startsWith ("/F"))
this.format = format.charAt (2);
else if (format.startsWith ("/-"))
{
repeatingChar = format.charAt (2);
for (int i = 0; i < 20; i++)
repeat += repeatingChar;
}
else
System.out.printf ("Unexpected format [%s]%n", format);
}
void doCommand (String command)
{
// System.out.printf ("Cell command:%s%n", command);
switch (command.charAt (0))
{
case '/':
if (command.charAt (1) == 'F') // format cell
{
// /FG - general
// /FD - default
// /FI - integer
// /F$ - dollars and cents
// /FL - left justified
// /FR - right justified
// /F* - graph
format = command.charAt (2);
if (command.length () > 3 && command.charAt (3) == '"')
label = command.substring (4);
}
else if (command.charAt (1) == '-') // repeating label
{
repeatingChar = command.charAt (2);
for (int i = 0; i < 20; i++)
repeat += repeatingChar;
}
else
System.out.println ("Unknown command: " + command);
break;
case '"':
label = command.substring (1);
break;
@ -64,7 +59,7 @@ class Cell implements Comparable<Cell>
if (command.matches ("^[0-9.]+$")) // contains only numbers or .
this.value = Float.parseFloat (command);
else
formula = command;
formulaText = command;
}
}
@ -80,19 +75,30 @@ class Cell implements Comparable<Cell>
double getValue ()
{
if (valid || formula == null)
if (valid || formulaText == null)
return value;
double result = 0.0;
double interim = 0.0;
if (formula.startsWith ("@LOOKUP("))
if (formulaText.startsWith ("@LOOKUP("))
{
Lookup lookup = new Lookup (parent, formula);
Lookup lookup = new Lookup (parent, formulaText);
return lookup.getValue ();
}
Matcher m = cellContents.matcher (formula);
System.out.printf ("Matching:[%s]%n", formulaText);
// [@IF(@ISERROR(BK24),0,BK24)]
// [@IF(D4=0,0,1)]
// [@IF(D4=0,0,B32+1)]
// [@IF(D4=0,0,1+(D3/100/D4)^D4-1*100)]
// [@SUM(C4...F4)]
// [+C4-@SUM(C5...C12)]
// [+D5/100/12]
// [.3*(B4+B7+B8+B9)]
// [+N12+(P12*(.2*K12+K9-O12))]
Matcher m = cellContents.matcher (formulaText);
while (m.find ())
{
valid = true;
@ -112,7 +118,7 @@ class Cell implements Comparable<Cell>
}
catch (NumberFormatException e)
{
System.out.printf ("NFE: %s [%s]%n", m.group (4), formula);
System.out.printf ("NFE: %s [%s]%n", m.group (4), formulaText);
}
else
{
@ -138,7 +144,7 @@ class Cell implements Comparable<Cell>
return result;
}
System.out.println ("?? " + formula);
System.out.println ("?? " + formulaText);
return value;
}
@ -149,24 +155,22 @@ class Cell implements Comparable<Cell>
return label;
if (repeatingChar > 0)
return repeat;
if (formula != null)
if (formula.length () >= 12)
return formula.substring (0, 12);
if (formulaText != null)
if (formulaText.length () >= 12)
return formulaText.substring (0, 12);
else
return formula;
return formulaText;
return value + "";
}
@Override
public String toString ()
{
String value = repeatingChar == 0 ? label == null
? formula == null ? ", Value: " + this.value : ", Formula: " + formula
: ", Label: " + label : ", Rpeat: " + repeatingChar;
String format = this.format == ' ' ? "" : ", Format: " + this.format;
// String width = this.width == 0 ? "" : ", Width: " + this.width;
// return String.format ("[Cell:%5s%s%s%s]", address, format, width, value);
return String.format ("[Cell:%5s%s%s]", address, format, value);
String value = repeatingChar == 0
? label == null ? formulaText == null ? ", Value : " + this.value
: ", Formula: " + formulaText : ", Label : " + label
: ", Repeat : " + repeatingChar;
return String.format ("[Cell:%5s %-2s%s]", address, format, value);
}
@Override

View File

@ -29,14 +29,21 @@ public class Lookup extends Function
{
// source could be a formula - @LOOKUP(.2*K8+K7,H3...H16)
source = parent.getCell (new Address (sourceText));
if (source == null)
{
System.out.println ("Null source:" + sourceText);
return 0;
}
double sourceValue = source.getValue ();
range = getRange (rangeText);
Address target = null;
for (Address address : range)
{
System.out.printf ("%s : %s%n", source, address);
// System.out.printf ("%s : %s%n", source, address);
Cell cell = parent.getCell (address);
if (cell != null && cell.getValue () > source.getValue ())
if (cell != null && cell.getValue () > sourceValue)
break;
target = address;
}

View File

@ -1,7 +1,11 @@
package com.bytezone.diskbrowser.visicalc;
import java.text.DecimalFormat;
import java.util.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -9,20 +13,23 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
public class Sheet implements Iterable<Cell>
{
private static char[] tokens = { '"', '@', '+' }; // label, function, formula/value
private static final Pattern addressPattern =
Pattern.compile ("([A-B]?[A-Z])([0-9]{1,3}):");
Pattern.compile ("([AB]?[A-Z])([0-9]{1,3}):");
// private static final Pattern functionPattern = Pattern
// .compile ("\\(([A-B]?[A-Z])([0-9]{1,3})\\.\\.\\.([A-B]?[A-Z])([0-9]{1,3})\\)?");
// private static final Pattern addressList = Pattern.compile ("\\(([^,]+(,[^,]+)*)\\)");
private final Map<Integer, Cell> sheet = new TreeMap<Integer, Cell> ();
private final Map<String, Double> functions = new HashMap<String, Double> ();
// private final Map<String, Double> functions = new HashMap<String, Double> ();
Cell currentCell = null;
char defaultFormat;
private final Map<Integer, Integer> columnWidths = new TreeMap<Integer, Integer> ();
int columnWidth = 12;
private int columnWidth = 12;
private char recalculation = ' ';
private char recalculationOrder = ' ';
// Maximum cell = BK254
@ -49,9 +56,9 @@ public class Sheet implements Iterable<Cell>
// /GF$ Global Format Currency
// /GC Global Column <width>
// /GR Global
// /GRA
// /GRA Recalculation Auto
// /GO Global
// /GOC
// /GOC Calculation Order - Columns first
// /T Titles (HVBN)
// /TH fix Horizontal Titles
@ -175,231 +182,128 @@ public class Sheet implements Iterable<Cell>
return ptr - offset;
}
private void processLine (String command)
private void processLine (String line)
{
// NB no closing bracket: [>K11:@SUM(J11...F11]
if (command.isEmpty ())
// >B10:/F$+B4+B7+B8+B9
// >F2:/FR"INCOME
if (line.isEmpty ())
{
System.out.println ("empty command");
return;
}
if (command.startsWith (">")) // GOTO cell
if (line.startsWith ("/"))
{
Matcher m = addressPattern.matcher (command);
if (m.find ())
switch (line.charAt (1))
{
Address address = new Address (m.group (1), m.group (2));
currentCell = sheet.get (address.sortValue);
int pos = command.indexOf (':'); // end of cell address
command = command.substring (pos + 1);
if (currentCell == null)
{
currentCell = new Cell (this, address);
if (!command.startsWith ("/GCC"))
sheet.put (currentCell.address.sortValue, currentCell);
}
}
else
System.out.printf ("Invalid cell address: %s%n", command);
}
if (command.startsWith ("/")) // command
{
String data = command.substring (1);
char subCommand = command.charAt (1);
switch (subCommand)
{
case 'W': // Window control
// System.out.println (" Window command: " + data);
case 'W':
System.out.printf ("Skipping [%s]%n", line);
break;
case 'G': // Global command
// System.out.println (" Global command: " + data);
try
case 'G':
switch (line.charAt (2))
{
if (data.charAt (1) == 'C')
{
if (data.charAt (2) == 'C')
{
int width = Integer.parseInt (data.substring (3));
int column = currentCell.address.column;
columnWidths.put (column, width);
}
else
columnWidth = Integer.parseInt (data.substring (2));
}
else if (data.charAt (1) == 'F')
defaultFormat = data.charAt (2);
}
catch (NumberFormatException e)
{
System.out.printf ("NFE: %s%n", data.substring (2));
case 'R':
recalculation = line.charAt (3);
break;
case 'O':
recalculationOrder = line.charAt (3);
break;
case 'P':
System.out.printf ("Skipping [%s]%n", line);
break;
case 'C':
columnWidth = Integer.parseInt (line.substring (3));
break;
}
break;
case 'T': // Set title area
// System.out.println (" Title command: " + data);
case 'X':
System.out.printf ("Skipping [%s]%n", line);
break;
case 'X': // Position cursor?
break;
default:
currentCell.doCommand (command);
System.out.printf ("Skipping [%s]%n", line);
}
return;
}
else if (command.startsWith ("@")) // function
if (!line.startsWith (">")) // GOTO cell
{
currentCell.doCommand (command);
System.out.printf ("Error [%s]%n", line);
return;
}
else if (command.startsWith ("\""))
currentCell = null;
Matcher m = addressPattern.matcher (line);
if (m.find ())
{
currentCell.doCommand (command);
}
else if (command.startsWith ("+"))
{
currentCell.doCommand (command);
}
else if (command.matches ("^[0-9.]+$")) // value
{
currentCell.doCommand (command);
}
else if (command.matches ("^[-A-Z]+$")) // label
{
currentCell.doCommand (command);
Address address = new Address (m.group (1), m.group (2));
currentCell = sheet.get (address.sortValue);
int pos = line.indexOf (':'); // end of cell address
line = line.substring (pos + 1); // remove address from line
if (currentCell == null)
{
currentCell = new Cell (this, address);
if (!line.startsWith ("/G"))
sheet.put (currentCell.address.sortValue, currentCell);
}
}
else
currentCell.doCommand (command); // formula
{
System.out.printf ("Invalid cell address: %s%n", line);
return;
}
assert currentCell != null;
if (line.startsWith ("/G")) // global column widths
{
if (line.charAt (2) == 'C' && line.charAt (3) == 'C')
{
int width = Integer.parseInt (line.substring (4));
columnWidths.put (currentCell.address.column, width);
}
else
System.out.printf ("Unknown Global:[%s]%n", line);
return;
}
// check for formatting commands before a token
String command = "";
if (line.startsWith ("/"))
{
for (char token : tokens)
{
int pos = line.indexOf (token);
if (pos > 0)
{
command = line.substring (0, pos);
line = line.substring (pos);
break;
}
}
if (line.startsWith ("/")) // no token found
{
command = line;
line = "";
}
}
if (true)
System.out.printf ("[%s][%-3s][%s]%n", currentCell.address, command, line);
if (!command.isEmpty ())
currentCell.format (command); // formatting command
if (!line.isEmpty ())
currentCell.doCommand (line); // expression
}
// private double evaluateFunction (String function)
// {
// if (functions.containsKey (function))
// return functions.get (function);
//
// // System.out.println (function);
// double result = 0;
//
// if (function.startsWith ("@IF("))
// {
// return result;
// }
//
// if (function.startsWith ("@LOOKUP("))
// {
// return result;
// }
//
// // Range range = getRange (function);
// // if (range == null)
// // return result;
//
// if (function.startsWith ("@SUM("))
// {
// // for (Address address : range)
// // result += getValue (address);
// String text = function.substring (4, function.length () - 1);
// Sum sum = new Sum (this, text);
// result = sum.getValue ();
// }
// else if (function.startsWith ("@COUNT("))
// {
// // int count = 0;
// // for (Address address : range)
// // {
// // VisicalcCell cell = getCell (address);
// // if (cell != null && cell.hasValue () && cell.getValue () != 0.0)
// // ++count;
// // }
// // result = count;
// String text = function.substring (7, function.length () - 1);
// Count count = new Count (this, text);
// result = count.getValue ();
// }
// else if (function.startsWith ("@MIN("))
// {
// // double min = Double.MAX_VALUE;
// // for (Address address : range)
// // if (min > getValue (address))
// // min = getValue (address);
// String text = function.substring (5, function.length () - 1);
// Min min = new Min (this, text);
// result = min.getValue ();
// }
// else if (function.startsWith ("@MAX("))
// {
// // double max = Double.MIN_VALUE;
// // for (Address address : range)
// // if (max < getValue (address))
// // max = getValue (address);
// // result = max;
// String text = function.substring (5, function.length () - 1);
// Max max = new Max (this, text);
// result = max.getValue ();
// }
// else
// System.out.println ("Unimplemented function: " + function);
//
// functions.put (function, result);
// return result;
// }
// Range getRange (String text)
// {
// Range range = null;
// Matcher m = functionPattern.matcher (text);
// while (m.find ())
// {
// Address fromAddress = new Address (m.group (1), m.group (2));
// Address toAddress = new Address (m.group (3), m.group (4));
// range = new Range (fromAddress, toAddress);
// }
//
// if (range != null)
// return range;
//
// m = addressList.matcher (text);
// while (m.find ())
// {
// String[] cells = m.group (1).split (",");
// range = new Range (cells);
// }
//
// if (range != null)
// return range;
//
// int pos = text.indexOf ("...");
// if (pos > 0)
// {
// String from = text.substring (0, pos);
// String to = text.substring (pos + 3);
// Address fromAddress = new Address (from);
// Address toAddress = new Address (to);
// range = new Range (fromAddress, toAddress);
// }
//
// if (range != null)
// return range;
// System.out.println ("null range : " + text);
//
// return range;
// }
// private double getValue (Address address)
// {
// Cell cell = sheet.get (address.sortValue);
// return cell == null ? 0.0 : cell.getValue ();
// }
// private double getValue (String cellName)
// {
// Address address = new Address (cellName);
// return getValue (address);
// }
Cell getCell (Address address)
{
return sheet.get (address.sortValue);