Java tutorial
/* * Copyright 2012-2013 Arie Benichou * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ package components.cells; import static components.cells.Positions.Position; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import com.google.common.base.Objects; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.ImmutableSortedMap.Builder; import com.google.common.collect.MapDifference; import com.google.common.collect.MapDifference.ValueDifference; import com.google.common.collect.Maps; import com.google.common.collect.Ordering; public final class Cells<T> implements ICells<T> { public static <T> ICells<T> from(final int rows, final int columns, final T initialSymbol, final T undefinedSymbol, final Map<IPosition, T> cells, final Map<IPosition, T> cellsMutations) { return new Cells<T>(rows, columns, initialSymbol, undefinedSymbol, cells, cellsMutations); } public static <T> ICells<T> from(final int rows, final int columns, final T initialSymbol, final T undefinedSymbol, final Map<IPosition, T> cells) { return from(rows, columns, initialSymbol, undefinedSymbol, cells, new HashMap<IPosition, T>()); } public static <T> ICells<T> from(final int rows, final int columns, final T initialSymbol, final T undefinedSymbol) { return from(rows, columns, initialSymbol, undefinedSymbol, new HashMap<IPosition, T>()); } private static <T> ICells<T> from(final Cells<T> cells, final Map<IPosition, T> cellsMutations) { return from(cells.rows(), cells.columns(), cells.initialSymbol(), cells.undefinedSymbol(), cells.get(), cellsMutations); } public static <T> ICells<T> from(final Cells<T> cells) { return from(cells, new HashMap<IPosition, T>()); } private final int rows; private final int columns; private final Map<IPosition, T> cells; private final T initialSymbol; private final T undefinedSymbol; private volatile Integer hashCode = null; private static <T> Map<IPosition, T> merge(final T initialSymbol, final Map<IPosition, T> left, final Map<IPosition, T> right) { final Builder<IPosition, T> builder = new ImmutableSortedMap.Builder<IPosition, T>(Ordering.natural()); final MapDifference<IPosition, T> difference = Maps.difference(left, right); for (final Entry<IPosition, T> mutation : difference.entriesInCommon().entrySet()) if (!mutation.getValue().equals(initialSymbol)) builder.put(mutation); for (final Entry<IPosition, T> mutation : difference.entriesOnlyOnLeft().entrySet()) if (!mutation.getValue().equals(initialSymbol)) builder.put(mutation); for (final Entry<IPosition, T> mutation : difference.entriesOnlyOnRight().entrySet()) if (!mutation.getValue().equals(initialSymbol)) builder.put(mutation); for (final Entry<IPosition, ValueDifference<T>> mutation : difference.entriesDiffering().entrySet()) { final T rightValue = mutation.getValue().rightValue(); if (!rightValue.equals(initialSymbol)) builder.put(mutation.getKey(), rightValue); } return builder.build(); } private Cells(final int rows, final int columns, final T initialSymbol, final T undefinedSymbol, final Map<IPosition, T> left, final Map<IPosition, T> right) { this.rows = rows; this.columns = columns; this.initialSymbol = initialSymbol; this.undefinedSymbol = undefinedSymbol; this.cells = merge(initialSymbol, left, right); } @Override public int rows() { return this.rows; } @Override public int columns() { return this.columns; } @Override public T initialSymbol() { return this.initialSymbol; } @Override public T undefinedSymbol() { return this.undefinedSymbol; } @Override public Map<IPosition, T> get() { return this.cells; } private T getCellSymbol(final IPosition position) { final T symbol = this.cells.get(position); if (symbol != null) return symbol; return this.initialSymbol(); } private boolean isDefined(final int row, final int column) { return row > -1 && column > -1 && row < this.rows() && column < this.columns(); } @Override public T get(final IPosition position) { //if (position.isNull()) return this.undefinedSymbol(); if (this.isDefined(position.row(), position.column())) return this.getCellSymbol(position); return this.undefinedSymbol(); } @Override public T get(final int row, final int column) { final IPosition position = Position(row, column); return this.get(position); } @Override public ICells<T> apply(final Map<IPosition, T> updatedPositions) { return Cells.from(this, updatedPositions); } @Override public ICells<T> copy() { return Cells.from(this); } @Override public Map<IPosition, T> filter(final Predicate<Entry<IPosition, T>> predicate) { Preconditions.checkArgument(predicate != null); return Maps.filterEntries(this.get(), predicate); // TODO ? allow predicate on initial symbol } // TODO memoize @Override public final String toString() { return Objects.toStringHelper(this).add("rows", this.rows()).add("columns", this.columns()) .add("initial", this.initialSymbol()).add("undefined", this.undefinedSymbol()) .add("mutation", this.cells).toString(); } @Override public int hashCode() { Integer value = this.hashCode; if (value == null) synchronized (this) { if ((value = this.hashCode) == null) this.hashCode = value = this.toString().hashCode(); } return value; } @Override @SuppressWarnings("rawtypes") public boolean equals(final Object object) { if (object == null) return false; Preconditions.checkArgument(object instanceof ICells, object); if (object == this) return true; final ICells that = (ICells) object; return this.rows() == that.rows() && this.columns() == that.columns() && this.initialSymbol().equals(that.initialSymbol()) && this.undefinedSymbol().equals(that.undefinedSymbol()) && this.get().equals(that.get()); } }