package gpslogger;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.net.MalformedURLException;
import java.net.URL;
import java.awt.Toolkit;

public class GoogleTileCanvas extends ImageCanvas {
	static final int TILE_SIZE = 256;
	static final int FRAME_WIDTH = 308;
	static final int FRAME_HEIGHT = 210;
			
	private Graphics g;
	
	private boolean fetcherror;
	
	private int x;
	private int y;
	
	private int heading;
	
	private Toolkit tk;
	
	private Image tiles[][] = new Image[3][3];
	
	public GoogleTileCanvas() {
		//System.err.println("GoogleTileCanvas: GoogleTileCanvas: Constructor called");

		this.x = FRAME_WIDTH/2;
		this.y = FRAME_HEIGHT/2;		

		this.heading = 0;
		
		tk = Toolkit.getDefaultToolkit();
		
		fetcherror = false;
	}
	/**
	 * Overloads setImage in ImageCanvas to accept a GoogleTile object instead
	 * of an Image.  a GoogleTile object has enough information in it to infer the
	 * positions of other tiles, so a full-frame map can be constructed.  Calls repaint()
	 * before returning so image updates are always immediate.
	 * 
	 * @param centerTile a GoogleTile object to construct the map around (GPS position is always centered)
	 */
	public void setImage(GoogleTile centerTile) {
		Point centerTilePixelOffset = GoogleTileUtils.getPixelOffsetInTile(centerTile.getTileLatLong().getX(),
				centerTile.getTileLatLong().getY(), centerTile.getZoom());
		Point centerTileCoord = GoogleTileUtils.toTileXY(centerTile.getTileLatLong().getX(),
				centerTile.getTileLatLong().getY(), centerTile.getZoom());
		
		this.x = centerTilePixelOffset.x;
		this.y = centerTilePixelOffset.y;
		
		try {
			for (int i=0; i<3; i++) {
				for (int j=0; j<3; j++) {
					tiles[i][j] = tk.getImage(new URL(GoogleTileURL.url(centerTileCoord.x+(i-1),   centerTileCoord.y+(j-1),   centerTile.getZoom())));
				}
			}
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		
		this.repaint();
	}

	/**
	 * constructs the final display image out of the tiles in the buffer
	 */
	private void buildImage() {
		//System.err.println("GoogleTileCanvas: buildImage: starting");
		g = image.getGraphics();
		
		// build up our image for display here
		for (int i=0; i<3; i++) {
			for (int j=0; j<3; j++) {
				g.drawImage(tiles[i][j], TILE_SIZE*i, TILE_SIZE*j, this);
			}
		}
				
		g.dispose();
	}
	
	/**
	 * Renders and displays the image
	 */
	public void paint(Graphics gc) {
		//System.err.println("GoogleTileCanvas: paint: starting");
		
		if (image == null) {
			image = createImage(FRAME_WIDTH*3, FRAME_HEIGHT*3);
		}
		
		if ((image != null) && (fetcherror != true)) {
			buildImage();
			gc.drawImage(image, (FRAME_WIDTH/2)-x-TILE_SIZE, (FRAME_HEIGHT/2)-y-TILE_SIZE, null);
//			gc.drawString("X", FRAME_WIDTH/2, FRAME_HEIGHT/2);
			gc.setColor(java.awt.Color.red);
			gc.fillArc(FRAME_WIDTH/2 - 15, FRAME_HEIGHT/2 - 15, 30, 30, (heading + 180)-22, 44);
		}
		
		if (fetcherror == true) {
			gc.drawString("Error loading images", 0, 10);
		}
	}


	public void setHeading(int heading) {
		this.heading = heading;
		
		this.heading -= 90;
		if (this.heading < 0)
			this.heading += 360;
		
		this.heading = 360 - this.heading;
	}
	
	/** imageUpdate gets called when the status of an image we've expressed interest in
	 *  changes.  When an image is image is finished, repaint gets called to render
	 *  and display it.  This is the "poor man's" way to make sure each image has finished
	 *  loading before attempting to display.  Check out java.awt.MediaTracker for
	 *  a better way.
	 */
	public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
		
		if ((infoflags & ERROR) != 0) {
			System.err.println("GoogleTileCanvas: imageUpdate: Error loading image " + img.toString());
			fetcherror = true;
		}
		
		if ((infoflags & ALLBITS) != 0) {
			System.err.println("GoogleTileCanvas: imageUpdate: Finished loading image " + img.toString());
		}
		
		boolean done = ((infoflags & (ALLBITS | ERROR)) != 0);
		
		if (done)
			this.repaint(0);
		
		return !done;
	}	

}