package assignment1;
import java.util.Arrays;
/**
* This is a display grid class. It helps organize and format elements into grid
* patterns for onscreen display.
* @author Jon Olson
*/
public class OlsonJGrid
{
/**
* The grid itself.
*/
protected Object[][] grid = null;
/**
* Column width information.
*/
protected int[] widths = null;
/**
* Used to signal if the row has data at all.
*/
protected boolean[] rowData = null;
/**
* Default constructor. It does nothing.
*/
public OlsonJGrid()
{
}
/**
* Initialize the grid to a specific dimension
* @param width the starting width
* @param height the starting height
*/
public OlsonJGrid( int width, int height )
{
expandSize( width, height );
}
/**
* Add a single row to the grid. This is the same as using
* {code}addColumns(1){/code}
* @return the new height
*/
public int addColumn()
{
return addColumns( 1 );
}
/**
* Add a number of columsn to the grid. This is the same as calling
* {code}expandSize(count, 0); result = getWidth();{/code}
* @param count how many columns to add
* @return the new width
* @throws java.lang.IllegalArgumentException if count is < 0
*/
public int addColumns( int count ) throws IllegalArgumentException
{
expandSize( count, 0 );
return getWidth();
}
/**
* Add a single row to the grid. This is the same as using
* {code}addRows(1){/code}
* @return the new height
*/
public int addRow()
{
return addRows( 1 );
}
/**
* Add a number of rows to the grid. This is the same as calling
* {code}expandSize(0, count); result = getHeight();{/code}
* @param count how many rows to add
* @return the new height
* @throws java.lang.IllegalArgumentException if count is < 0
*/
public int addRows( int count ) throws IllegalArgumentException
{
expandSize( 0, count );
return getHeight();
}
/**
* Retrieve the number of rows in the grid
* @return the number of rows
*/
public int getHeight()
{
if ( rowData == null )
{
return 0;
}
else
{
return rowData.length;
}
}
/**
* Retrieve the number of columns in the grid
* @return the number of columns
*/
public int getWidth()
{
if ( widths == null )
{
return 0;
}
else
{
return widths.length;
}
}
/**
* Expand the size of the grid
* @param byWidth how many columns to add
* @param byHeight how many rows to add
* @return If anything was changed. i.e. false if both parameters are zero
* and true for all positive values.
* @throws java.lang.IllegalArgumentException if either parameter is < 0
*/
public boolean expandSize( int byWidth, int byHeight ) throws IllegalArgumentException
{
if ( byWidth < 0 || byHeight < 0 )
{
throw new IllegalArgumentException( "You can only add positive numbers of columns." );
}
else if ( byWidth == 0 && byHeight == 0 )
{
// nothing needs to be done.
return false;
}
// existing measurements
int width = getWidth(), height = getHeight();
// ensure we have at least dimensions of one.
int newWidth = Math.max( width + byWidth, 1 );
int newHeight = Math.max( height + byHeight, 1 );
// initialize the new grid
Object[][] newGrid = new Object[ newHeight ][ newWidth ];
for ( Object[] row : newGrid )
{
Arrays.fill( row, null );
}
// copy over the existing values from the current grid
for ( int i = 0; i < height; ++i )
{
for ( int j = 0; j < width; ++j )
{
newGrid[i][j] = grid[i][j];
}
}
grid = newGrid;
// expand the widths array if needed
if ( width < newWidth )
{
int[] newWidths = new int[ newWidth ];
Arrays.fill( newWidths, 0 );
for ( int i = 0; i < width; ++i )
{
newWidths[i] = widths[i];
}
widths = newWidths;
}
// expand the rowData array if needed
if ( height < newHeight )
{
boolean[] newData = new boolean[ newHeight ];
Arrays.fill( newData, false );
for ( int i = 0; i < height; ++i )
{
newData[i] = rowData[i];
}
rowData = newData;
}
return true;
}
/**
* Set the value of a particular cell. If the coordinate is outside the
* current bounds of the grid, it will be expanded.
* @param x the one-based horizontal coordinate of the cell to set
* @param y the one-based vertical coordinate of the cell to set
* @param value the value to use.
*/
public void set( int x, int y, Object value )
{
if ( x <= 0 || y <= 0 )
{
throw new IllegalArgumentException( "Positive, non-zero coordinates required." );
}
int exX, exY = exX = 0;
if ( rowData == null )
{
exY = y;
}
else if ( y > getHeight() )
{
exY = y - getHeight();
}
if ( widths == null )
{
exX = x;
}
else if ( x > getWidth() )
{
exX = x - getWidth();
}
expandSize( exX, exY );
--x;
--y;
if ( (grid[y][x] == null) != (value == null) )
{
Object test;
boolean empty = true;
// check the row for emptiness
for ( int i = 0; i < grid[y].length && empty; ++i )
{
if ( i == x )
{
test = value;
}
else
{
test = grid[y][i];
}
empty = test == null;
}
rowData[y] = !empty;
int max = 0;
// check the column largest cell
for ( int i = 0; i < grid.length; ++i )
{
if ( i == y )
{
test = value;
}
else
{
test = grid[i][x];
}
if ( test != null )
{
max = Math.max( max, test.toString().length() );
}
}
widths[x] = max;
}
else if ( grid[y][x] != null && value != null )
{
widths[x] = Math.max( widths[x], value.toString().length() );
}
grid[y][x] = value;
}
/**
* Clear the value from a specified coordinate. If the coordinate is outside
* of the current grid, it will be expanded to fit.
* @param x the one-based horizontal coordinate to clear
* @param y the one-based vertical coordinate to clear
*/
public void clear( int x, int y )
{
set( x, y, null );
}
/**
* Generate a string showing the values stored in the grid.
* @return the string
*/
@Override
public String toString()
{
// if there's no data, return an empty string.
if ( getHeight() == 0 )
{
return "";
}
// set up the pieces of the edges
String left = "+-", middle = "-+-", right = "-+", span = "-";
String leftBar = "| ", middleBar = " | ", rightBar = " |";
String hiLo = "";
// calculate how many actual columns we have
int columns = 0;
for ( int width : widths )
{
if ( width > 0 )
{
++columns;
}
}
// if we found out that none of the columns had data, return an empty
// string.
if ( columns <= 0 )
{
return "";
}
// build the top/bottom border using the column count
int column = 0;
hiLo += left;
for ( int i = 0; i < widths.length; ++i )
{
for ( int j = 0; j < widths[i]; ++j )
{
hiLo += span;
}
if ( widths[i] > 0 && ++column < columns )
{
hiLo += middle;
}
}
hiLo += right;
// build the output
String out = hiLo + "\n";
for ( int i = 0; i < grid.length; ++i )
{
// don't process the row if there's isn't any row data
if ( !rowData[i] )
{
continue;
}
out += leftBar;
column = 0;
for ( int j = 0; j < grid[i].length; ++j )
{
// do we need to process this column?
if ( widths[j] <= 0 )
{
continue;
}
// what type of data do we have in this cell?
if ( grid[i][j] == null )
{
out += String.format( "%" + widths[j] + "s", " " );
}
else if ( grid[i][j] instanceof Long ||
grid[i][j] instanceof Integer ||
grid[i][j] instanceof Short ||
grid[i][j] instanceof Byte ||
grid[i][j] instanceof Float ||
grid[i][j] instanceof Double )
{
out += String.format( "%" + widths[j] + "s", grid[i][j] );
}
else
{
out += String.format( "%-" + widths[j] + "s", grid[i][j] );
}
// increase the column counter to see if we need to skip the
// middle bar
if ( ++column < columns )
{
out += middleBar;
}
}
out += rightBar + "\n";
}
out += hiLo;
return out;
}
}