package xpra.swing;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;

import xpra.client.XpraWindow;
import xpra.protocol.PictureEncoding;
import xpra.protocol.packets.DrawPacket;
import xpra.swing.keyboard.KeyMap;


/**
 * @author Jakub Księżniak
 *
 */
public class XpraCanvas extends Canvas implements HierarchyListener, MouseListener, MouseMotionListener, KeyListener {
	private static final long serialVersionUID = 1L;
	
	private final XpraWindow xwnd;

	private Window window;

	public XpraCanvas(XpraWindow window) {
		this.xwnd = window;
		addHierarchyListener(this);
		addMouseListener(this);
		addMouseMotionListener(this);
		addKeyListener(this);
		setBackground(new Color(0,0,0,0));
	}
	
	public void setCustomRoot(Window wnd) {
		window = wnd;
	}

	@Override
	public void hierarchyChanged(HierarchyEvent e) {
		if((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0 && isDisplayable()) {
			createBufferStrategy(2);
			requestFocus();
		}
	}

	public void draw(DrawPacket packet) {
		try {
			BufferedImage img = ImageIO.read(new ByteArrayInputStream(packet.data));
			Graphics2D g = (Graphics2D) getBufferStrategy().getDrawGraphics();
//			g.setPaintMode();
//			g.setComposite(AlphaComposite.Src);
			g.drawImage(img, packet.x, packet.y, this);
			g.dispose();
			getBufferStrategy().show();
		} catch (IOException e) {
      throw new RuntimeException("Failed decoding image: " + packet.encoding, e);
		}
	}
	
	private Point getTruePos(int x, int y) {
		JRootPane root = SwingUtilities.getRootPane(window != null ? window : this);
		//System.err.println("root insets: " + root.getLocation());
		return new Point(x-root.getX(), y-root.getY());
	}

	@Override
	public void mouseDragged(MouseEvent e) {
		Point p = getTruePos(e.getXOnScreen(), e.getYOnScreen());
		xwnd.mouseAction(e.getButton(), true, p.x, p.y);		
	}

	@Override
	public void mouseMoved(MouseEvent e) {
		Point p = getTruePos(e.getXOnScreen(), e.getYOnScreen());
		xwnd.movePointer(p.x, p.y);
	}

	@Override
	public void mouseClicked(MouseEvent e) {
		// not used
	}

	@Override
	public void mousePressed(MouseEvent e) {
		Point p = getTruePos(e.getXOnScreen(), e.getYOnScreen());
		xwnd.mouseAction(e.getButton(), true, p.x, p.y);
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		Point p = getTruePos(e.getXOnScreen(), e.getYOnScreen());
		xwnd.mouseAction(e.getButton(), false, p.x, p.y);
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		Point p = getTruePos(e.getXOnScreen(), e.getYOnScreen());
		xwnd.movePointer(p.x, p.y);
	}

	@Override
	public void mouseExited(MouseEvent e) {
		Point p = getTruePos(e.getXOnScreen(), e.getYOnScreen());
		xwnd.movePointer(p.x, p.y);
	}

	@Override
	public void keyTyped(KeyEvent e) {
		// not used
	}

	@Override
	public void keyPressed(KeyEvent e) {
		xwnd.keyboardAction(e.getKeyCode(), KeyMap.getUnicodeName(e.getKeyCode()), true);
	}

	@Override
	public void keyReleased(KeyEvent e) {
		xwnd.keyboardAction(e.getKeyCode(), KeyMap.getUnicodeName(e.getKeyCode()), false);
	}

}