package games.strategy.util;
import java.awt.Point;
import java.awt.Polygon;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import games.strategy.debug.ClientLogger;
/**
* Utiltity to read and write files in the form of
* String -> a list of points, or string-> list of polygons.
*/
public class PointFileReaderWriter {
/** Creates a new instance of PointFileReader. */
public PointFileReaderWriter() {}
/**
* Returns a map of the form String -> Point.
*/
public static Map<String, Point> readOneToOne(final InputStream stream) throws IOException {
if (stream == null) {
return Collections.emptyMap();
}
final Map<String, Point> mapping = new HashMap<>();
try (InputStreamReader inputStreamReader = new InputStreamReader(stream);
LineNumberReader reader = new LineNumberReader(inputStreamReader)) {
String current = reader.readLine();
while (current != null) {
if (current.trim().length() != 0) {
readSingle(current, mapping);
}
current = reader.readLine();
}
} finally {
stream.close();
}
return mapping;
}
/**
* Returns a map of the form String -> Point.
*/
public static Map<String, Point> readOneToOneCenters(final InputStream stream) throws IOException {
final Map<String, Point> mapping = new HashMap<>();
try (InputStreamReader inputStreamReader = new InputStreamReader(stream);
LineNumberReader reader = new LineNumberReader(inputStreamReader)) {
String current = reader.readLine();
while (current != null) {
if (current.trim().length() != 0) {
readSingle(current, mapping);
}
current = reader.readLine();
}
} finally {
stream.close();
}
return mapping;
}
private static void readSingle(final String aLine, final Map<String, Point> mapping) throws IOException {
final StringTokenizer tokens = new StringTokenizer(aLine, "", false);
final String name = tokens.nextToken("(").trim();
if (mapping.containsKey(name)) {
throw new IOException("name found twice:" + name);
}
final int x = Integer.parseInt(tokens.nextToken("(, "));
final int y = Integer.parseInt(tokens.nextToken(",) "));
final Point p = new Point(x, y);
mapping.put(name, p);
}
public static void writeOneToOne(final OutputStream sink, final Map<String, Point> mapping) throws Exception {
final StringBuilder out = new StringBuilder();
final Iterator<String> keyIter = mapping.keySet().iterator();
while (keyIter.hasNext()) {
final String name = keyIter.next();
out.append(name).append(" ");
final Point point = mapping.get(name);
out.append(" (").append(point.x).append(",").append(point.y).append(")");
if (keyIter.hasNext()) {
out.append("\r\n");
}
}
write(out, sink);
}
public static void writeOneToManyPolygons(final OutputStream sink, final Map<String, List<Polygon>> mapping)
throws Exception {
final StringBuilder out = new StringBuilder();
final Iterator<String> keyIter = mapping.keySet().iterator();
while (keyIter.hasNext()) {
final String name = keyIter.next();
out.append(name).append(" ");
final List<Polygon> points = mapping.get(name);
final Iterator<Polygon> polygonIter = points.iterator();
while (polygonIter.hasNext()) {
out.append(" < ");
final Polygon polygon = polygonIter.next();
for (int i = 0; i < polygon.npoints; i++) {
out.append(" (").append(polygon.xpoints[i]).append(",").append(polygon.ypoints[i]).append(")");
}
out.append(" > ");
}
if (keyIter.hasNext()) {
out.append("\r\n");
}
}
write(out, sink);
}
private static void write(final StringBuilder buf, final OutputStream sink) throws IOException {
final OutputStreamWriter out = new OutputStreamWriter(sink);
out.write(buf.toString());
out.flush();
}
public static void writeOneToMany(final OutputStream sink, Map<String, Collection<Point>> mapping) throws Exception {
final StringBuilder out = new StringBuilder();
if (mapping == null) {
mapping = new HashMap<>();
}
final Iterator<String> keyIter = mapping.keySet().iterator();
while (keyIter.hasNext()) {
final String name = keyIter.next();
out.append(name).append(" ");
final Collection<Point> points = mapping.get(name);
final Iterator<Point> pointIter = points.iterator();
while (pointIter.hasNext()) {
final Point point = pointIter.next();
out.append(" (").append(point.x).append(",").append(point.y).append(")");
if (pointIter.hasNext()) {
out.append(" ");
}
}
if (keyIter.hasNext()) {
out.append("\r\n");
}
}
write(out, sink);
}
/**
* Returns a map of the form String -> Collection of points.
*/
public static Map<String, List<Point>> readOneToMany(final InputStream stream) {
if (stream == null) {
return Collections.emptyMap();
}
final HashMap<String, List<Point>> mapping = new HashMap<>();
try (InputStreamReader inputStreamReader = new InputStreamReader(stream);
LineNumberReader reader = new LineNumberReader(inputStreamReader)) {
String current = reader.readLine();
while (current != null) {
if (current.trim().length() != 0) {
readMultiple(current, mapping);
}
current = reader.readLine();
}
} catch (final IOException ioe) {
ClientLogger.logError(ioe);
System.exit(0);
} finally {
try {
stream.close();
} catch (final IOException e) {
ClientLogger.logError(e);
}
}
return mapping;
}
/**
* Returns a map of the form String -> Collection of points.
*/
public static Map<String, List<Polygon>> readOneToManyPolygons(final InputStream stream) {
final HashMap<String, List<Polygon>> mapping = new HashMap<>();
try (InputStreamReader inputStreamReader = new InputStreamReader(stream);
LineNumberReader reader = new LineNumberReader(inputStreamReader)) {
String current = reader.readLine();
while (current != null) {
if (current.trim().length() != 0) {
readMultiplePolygons(current, mapping);
}
current = reader.readLine();
}
} catch (final IOException e) {
ClientLogger.logQuietly(e);
System.exit(0);
} finally {
try {
if (stream != null) {
stream.close();
}
} catch (final IOException e) {
ClientLogger.logError(e);
}
}
return mapping;
}
private static void readMultiplePolygons(final String line, final HashMap<String, List<Polygon>> mapping)
throws IOException {
try {
// this loop is executed a lot when loading games
// so it is hand optimized
final String name = line.substring(0, line.indexOf('<')).trim();
int index = name.length();
final List<Polygon> polygons = new ArrayList<>(64);
final ArrayList<Point> points = new ArrayList<>();
final int length = line.length();
while (index < length) {
char current = line.charAt(index);
if (current == '<') {
int x = 0;
int y = 0;
int base = 0;
// inside a poly
while (true) {
current = line.charAt(++index);
switch (current) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
base *= 10;
base += current - '0';
break;
case ',':
x = base;
base = 0;
break;
case ')':
y = base;
base = 0;
points.add(new Point(x, y));
break;
default:
break;
}
if (current == '>') {
// end poly
createPolygonFromPoints(polygons, points);
points.clear();
// break from while(true)
break;
}
}
}
index++;
}
if (mapping.containsKey(name)) {
throw new IOException("name found twice:" + name);
}
mapping.put(name, polygons);
} catch (final StringIndexOutOfBoundsException e) {
throw new IllegalStateException("Invalid line:" + line, e);
}
}
private static void createPolygonFromPoints(final Collection<Polygon> polygons, final ArrayList<Point> points) {
final int[] xPoints = new int[points.size()];
final int[] yPoints = new int[points.size()];
for (int i = 0; i < points.size(); i++) {
final Point p = points.get(i);
xPoints[i] = p.x;
yPoints[i] = p.y;
}
polygons.add(new Polygon(xPoints, yPoints, xPoints.length));
}
private static void readMultiple(final String line, final HashMap<String, List<Point>> mapping) throws IOException {
final StringTokenizer tokens = new StringTokenizer(line, "");
final String name = tokens.nextToken("(").trim();
if (mapping.containsKey(name)) {
throw new IOException("name found twice:" + name);
}
final List<Point> points = new ArrayList<>();
while (tokens.hasMoreTokens()) {
final String xString = tokens.nextToken(",(), ");
if (!tokens.hasMoreTokens()) {
continue;
}
final String yString = tokens.nextToken(",() ");
final int x = Integer.parseInt(xString);
final int y = Integer.parseInt(yString);
points.add(new Point(x, y));
}
mapping.put(name, points);
}
// TODO add write methods
}