/*
* Copyright (C) 2011.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 or
* version 2 as published by the Free Software Foundation.
*
* 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.
*/
package uk.me.parabola.imgfmt.app.typ;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.CharsetEncoder;
import java.util.ArrayList;
import java.util.List;
import uk.me.parabola.imgfmt.app.ImgFileWriter;
/**
* Base routines and data used by points, lines and polygons.
*
* If fact they are all very similar, so there is very little extra in the
* subclasses apart from the write routine.
*
* @author Steve Ratcliffe
*/
public abstract class TypElement implements Comparable<TypElement> {
private int type;
private int subType;
protected final List<TypLabel> labels = new ArrayList<TypLabel>();
protected Xpm xpm;
protected int fontStyle;
protected Rgb dayFontColour;
protected Rgb nightFontColour;
protected int offset;
public void setType(int type) {
this.type = type;
}
public void setSubType(int subType) {
this.subType = subType;
}
public int getType() {
return type;
}
/**
* We sort these by type.
* Only the index needs to be sorted (probably) but we don't create the index separately.
*
* @param o The other object to compare against.
* @return The usual -1, 0, 1 for the other object being less than, equal, greater than than this.
*/
public int compareTo(TypElement o) {
int t1 = getTypeForFile();
int t2 = o.getTypeForFile();
if (t1 == t2)
return 0;
else if (t1 < t2)
return -1;
else
return 1;
}
/**
* Get the type in the format required for writing in the typ file sections.
*/
public int getTypeForFile() {
return (type << 5) | (subType & 0x1f);
}
public void addLabel(String text) {
labels.add(new TypLabel(text));
}
public void setXpm(Xpm xpm) {
this.xpm = xpm;
}
public void setFontStyle(int font) {
this.fontStyle = font;
}
public void setDayFontColor(String value) {
dayFontColour = new Rgb(value);
}
public void setNightCustomColor(String value) {
nightFontColour = new Rgb(value);
}
public abstract void write(ImgFileWriter writer, CharsetEncoder encoder);
public int getOffset() {
return offset;
}
/**
* Does this element have two colour bitmaps, with possible automatic night colours. For lines and polygons.
*
* Overridden for points and icons.
*/
public boolean simpleBitmap() {
return true;
}
/**
* Make the label block separately as we need its length before we write it out properly.
*
* @param encoder For encoding the strings as bytes.
* @return A byte buffer with position set to the length of the block.
*/
protected ByteBuffer makeLabelBlock(CharsetEncoder encoder) {
ByteBuffer out = ByteBuffer.allocate(256 * labels.size());
for (TypLabel tl : labels) {
out.put((byte) tl.getLang());
CharBuffer cb = CharBuffer.wrap(tl.getText());
try {
ByteBuffer buffer = encoder.encode(cb);
out.put(buffer);
} catch (CharacterCodingException ignore) {
String name = encoder.charset().name();
//System.out.println("cs " + name);
throw new TypLabelException(name);
}
out.put((byte) 0);
}
return out;
}
/**
* Write the label block, this is the same for all element types.
* @param encoder To properly encode the labels.
*/
protected void writeLabelBlock(ImgFileWriter writer, CharsetEncoder encoder) {
ByteBuffer out = makeLabelBlock(encoder);
int len = out.position();
// The length is encoded as a variable length integer with the length indicated by a suffix.
len = (len << 1) + 1;
int mask = ~0xff;
while ((len & mask) != 0) {
mask <<= 8;
len <<= 1;
}
// write out the length, I'm assuming that it will be 1 or 2 bytes
if (len > 0xff)
writer.putChar((char) len);
else
writer.put((byte) len);
// Prepare and write buffer
out.flip();
writer.put(out);
}
/**
* Write out extended font information, colour and size.
*
* This is the same for each element type.
*/
protected void writeExtendedFontInfo(ImgFileWriter writer) {
byte fontExt = (byte) fontStyle;
if (dayFontColour != null)
fontExt |= 0x8;
if (nightFontColour != null)
fontExt |= 0x10;
writer.put(fontExt);
if (dayFontColour != null)
dayFontColour.write(writer, (byte) 0x10);
if (nightFontColour != null)
nightFontColour.write(writer, (byte) 0x10);
}
/**
* Write out an image. The width and height are written separately, because they are not
* repeated for the night image.
*
* @param xpm Either the day or night XPM.
*/
protected void writeImage(ImgFileWriter writer, Xpm xpm) {
ColourInfo colourInfo = xpm.getColourInfo();
writer.put((byte) colourInfo.getNumberOfSColoursForCM());
writer.put((byte) colourInfo.getColourMode());
colourInfo.write(writer);
xpm.writeImage(writer);
}
}