package graphicsDomain;
import sharedInterfaces.*;
import sharedDataInterfaces.*;


import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.font.*;

public class GraphicsFacade extends AbstractGraphicsFacade
{
    private GraphMetrics metrics;
    private DrawAxisTicksX drawXAxis;
    private DrawAxisTicksY drawYAxis;
    private DrawWaveform drawWaveform;
    private DrawLabels drawLabels;
    private DrawCrossHair drawCursor;
    private DrawCentredMessage drawMess;

    private GraphMouseHandler mouseHandler=new GraphMouseHandler();
    private GuiFacadeInterface guiFacade; //Prints current waveform coordinates


    public GraphicsFacade()
    {
	metrics = new GraphMetrics();
	drawXAxis = new DrawAxisTicksX();
	drawYAxis = new DrawAxisTicksY();
	drawWaveform = new DrawWaveform();
	drawLabels = new DrawLabels();
	drawCursor = new DrawCrossHair(this);
	drawMess = new DrawCentredMessage();

        addMouseListener(mouseHandler);
        addMouseMotionListener(mouseHandler);
    }

    public void initialise(GuiFacadeInterface guiFacade)
    {
        this.guiFacade = guiFacade;
    }
    public void setGraphData(GraphDataInterface data)
    {
	GraphDataInGraphics graphData = new GraphDataInGraphics(data);
	metrics.updateData(graphData);
    }

    public void resetGraphData()
    {
        metrics.setIsGraphData(false);
    }

    public void setGraphOptions(GraphOptionsInterface graphOpt)
    {
	GraphOptionsInGraphics options = new GraphOptionsInGraphics(graphOpt);
	metrics.updateOptions(options);
    }

    public void applyGraphOptions()
    {
	repaint();
    }


    public void graphPointUpdated(double x, double y, boolean inRange)
    {
        guiFacade.graphPointUpdated(x, y, inRange);
    }

    public void paintComponent(Graphics g)
    {
        // Cast the graphics object to Graph2D
        Graphics2D g2 = (Graphics2D) g;

        // Get plot size
        Dimension size = getSize();
        int xSize = size.width;
        int ySize = size.height;

	// find border size
	int borderSize;
	if (metrics.getGraphOptions().getDefaultBorder())
	{
            borderSize = calcBorderSize(g2);
	    metrics.getGraphOptions().setTickPix(4);
	}
	else
	{
	    borderSize=0;
	    metrics.getGraphOptions().setTickPix(0);
	}

	// Set graph and border size in metrics
	metrics.setXSize(xSize);
	metrics.setYSize(ySize);
	metrics.setBorderSize(borderSize);

        // Set background Color
        g2.setColor(metrics.getGraphOptions().selectColor(metrics.getGraphOptions().getGraphColor()));
        g2.fill(new Rectangle2D.Double(0,0,xSize,ySize));

        // If no data or bad data then write messages and break
	if (!metrics.getIsGraphData())
	{
	    String message = " No data";
	    if (metrics.getIsDataError())
                  message = "Unexpected data. See console message.";
	    metrics.setMessage(message);
            drawMess.draw(metrics,g2);
	    return;
	}

	drawWaveform.draw(metrics,g2);
	drawXAxis.draw(metrics,g2);
	drawYAxis.draw(metrics,g2);
	drawLabels.draw(metrics,g2);
	drawCursor.draw(metrics,g2);
    }

    public int calcBorderSize(Graphics2D g2)
    {
        /* borderSize calculation using test string "Test" */
        double border1, border2, border3,spaceFac=1.5;

        // height of top adornment: graph title
	Font titleFont=metrics.getGraphOptions().getTitleFont();
        g2.setFont(titleFont); // title font
        FontRenderContext context = g2.getFontRenderContext();
        Rectangle2D bounds = titleFont.getStringBounds("Test", context);
        double stringHeight = bounds.getHeight();
        border1= spaceFac*stringHeight;

        // height of bottom adornments: x-axis label plus x-tick-labels
	Font axisFont = metrics.getGraphOptions().getAxisFont();
        g2.setFont(metrics.getGraphOptions().getAxisFont()); // axis font
        context = g2.getFontRenderContext();
        bounds = axisFont.getStringBounds("Test", context);
        stringHeight = bounds.getHeight();
        border2= spaceFac*stringHeight;

	Font tickFont= metrics.getGraphOptions().getTickFont();
        g2.setFont(tickFont); // tick font
        context = g2.getFontRenderContext();
        bounds = tickFont.getStringBounds("Test", context);
        stringHeight = bounds.getHeight();
        border3= spaceFac*stringHeight;
        return (int) Math.max(border1, border2+border3);
    }

    /** inner class to handle mouse events */
    private class GraphMouseHandler  implements MouseListener, MouseMotionListener
    {
        private int currX=0, currY=0;
        public GraphMouseHandler()
        {
        }

        public void mousePressed(MouseEvent e)
        {
            currX = e.getX();
            currY = e.getY();
	    metrics.setCurrX(currX);
	    metrics.setCurrY(currY);
        }
        public void mouseMoved(MouseEvent e){}
        public void mouseClicked(MouseEvent e){}
        public void mouseEntered(MouseEvent e){}
        public void mouseExited(MouseEvent e){}

        public void mouseDragged(MouseEvent e)
        {
            currX = e.getX();
            currY = e.getY();
	    metrics.setCurrX(currX);
	    metrics.setCurrY(currY);
            GraphicsFacade.this.repaint();
        }
        public void mouseReleased(MouseEvent e)
        {
        }

	public int getCurrX(){ return currX;}
    }
}
