package com.nutiteq.components;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import com.mgmaps.utils.Tools;
import com.nutiteq.log.Log;
import com.nutiteq.maps.GeoMap;
import com.nutiteq.maps.MapTilesRequestor;
import com.nutiteq.maps.StoredMap;
import com.nutiteq.maps.StreamedMap;
import com.nutiteq.maps.UnstreamedMap;
/**
* Object containing map tile location on the map (x, y coordinates of
* upper-left corner on whole map) and image data for that tile.
*/
public class MapTile {
private final int x;
private final int y;
private final int zoom;
private final GeoMap map;
private byte[][] imageData;
private byte[][] overlayData;
private final MapTilesRequestor requestor;
private int failCount;
private int dataSize;
/**
* Not part of public API
*/
public MapTile(final int mapX, final int mapY, final int zoom, final GeoMap map,
final MapTilesRequestor screen) {
//get the pixel coordinates of upper left corner for this tile
x = mapX - mapX % map.getTileSize();
y = mapY - mapY % map.getTileSize();
this.zoom = zoom;
this.map = map;
this.requestor = screen;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZoom() {
return zoom;
}
public GeoMap getMap() {
return map;
}
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof MapTile)) {
return false;
}
final MapTile other = (MapTile) obj;
return x == other.x && y == other.y && zoom == other.zoom && map.equals(other.map);
}
public int hashCode() {
throw new RuntimeException("hashcode() has not been implemented!");
}
/**
* Not part of public API Check if the map tile is visible.
*
* @param centerPos
* the position of the center of the map
* @return true if visible, false otherwise
*/
public boolean isVisible(final MapPos centerPos, final GeoMap displayedMap,
final int screenCenterX, final int screenCenterY) {
if (map != displayedMap || zoom != centerPos.getZoom()) {
return false;
}
final int tileSize = map.getTileSize();
// get screen coords, given the center position
final int left = x - centerPos.getX() + screenCenterX;
final int top = y - centerPos.getY() + screenCenterY;
// out of screen or mode/zoom not matching?
return MapPos.checkBounds(left, top, tileSize, tileSize, screenCenterX * 2, screenCenterY * 2);
}
/**
* Not part of public API
*/
public String getIDString() {
//TODO jaanus : oh crap! resolve this mess!
return (map instanceof UnstreamedMap) ? ((UnstreamedMap) map).buildPath(x, y, zoom)
: ((StreamedMap) map).buildStreamedPath(new MapTile[] { this });
}
/**
* Not part of public API
*/
public long getSize() {
return dataSize + 100; // x, y, zoom, type, overhead
}
/**
* Not part of public API
*/
public void notifyError() {
failCount++;
setImagesData(null);
}
/**
* Not part of public API
*/
public void setImagesData(final byte[][] data) {
if (data == null || data.length == 0 || data[0].length == 0) {
failCount++;
Log.error("Could not retrieve " + getIDString());
requestor.tileRetrieved(this);
return;
}
imageData = data;
for (int i = 0; i < data.length; i++) {
dataSize += data[i].length;
}
requestor.tileRetrieved(this);
}
/**
* Not part of public API
*/
public Image getImage() {
if (imageData == null) {
return map.getMissingTileImage();
}
final String tileUrl = getIDString();
final int areaParamIndex = tileUrl.indexOf("|a=");
try {
final int tileSize = map.getTileSize();
final Image tileImage = Image.createImage(tileSize, tileSize);
final Graphics imageGraphics = tileImage.getGraphics();
for (int i = 0; i < imageData.length; i++) {
Image tmp = Image.createImage(imageData[i], 0, imageData[i].length);
if (areaParamIndex > 0) {
final String areaParam = tileUrl.substring(areaParamIndex + 3);
if ("0,0".equals(areaParam)) {
tmp = Tools.scaleImage20(tmp, 0, 0, 1);
} else if ("0,1".equals(areaParam)) {
tmp = Tools.scaleImage20(tmp, 0, tileSize / 2, 1);
} else if ("1,0".equals(areaParam)) {
tmp = Tools.scaleImage20(tmp, tileSize / 2, 0, 1);
} else {
tmp = Tools.scaleImage20(tmp, tileSize / 2, tileSize / 2, 1);
}
}
imageGraphics.drawImage(tmp, 0, 0, Graphics.TOP | Graphics.LEFT);
}
if (overlayData != null) {
for (int i = 0; i < overlayData.length; i++) {
final Image tmp = Image.createImage(overlayData[i], 0, overlayData[i].length);
imageGraphics.drawImage(tmp, 0, 0, Graphics.TOP | Graphics.LEFT);
}
}
return tileImage;
} catch (final IllegalArgumentException e) {
Log.printStackTrace(e);
Log.error(getIDString() + " error");
return null;
}
}
/**
* Not part of public API
*/
public boolean tryAgain() {
return imageData == null && !(map instanceof StoredMap) && failCount > 0 && failCount < 3;
}
public byte[] getData() {
//TODO jaanus : check this
return imageData == null ? new byte[0] : imageData[0];
}
public void setOverlayData(final byte[][] overlay) {
this.overlayData = overlay;
if (overlay == null || overlay.length == 0 || overlay[0].length == 0) {
return;
}
requestor.updateTile(this);
}
}