/*
Copyright (C) 2001, 2006 United States Government
as represented by the Administrator of the
National Aeronautics and Space Administration.
All Rights Reserved.
*/
package gov.nasa.worldwind.geom;

import com.sun.opengl.util.*;
import gov.nasa.worldwind.*;

import javax.media.opengl.*;
import java.awt.*;
import java.nio.*;

/**
 * @author tag
 * @version $Id: Quadrilateral.java 1787 2007-05-08 17:11:30Z dcollins $
 */
public class Quadrilateral implements Renderable
{
    private LatLon southwestCorner;
    private LatLon northeastCorner;
    private double elevation;
    private Point referenceCenter;
    private DoubleBuffer vertices;
    private int antiAliasHint = GL.GL_FASTEST;
    private Color color = Color.WHITE;

    public Quadrilateral(LatLon southwestCorner, LatLon northeastCorner, double elevation)
    {
        if (southwestCorner == null || northeastCorner == null)
        {
            String msg = WorldWind.retrieveErrMsg("nullValue.PositionIsNull");
            WorldWind.logger().log(java.util.logging.Level.FINE, msg);
            throw new IllegalArgumentException(msg);
        }

        this.southwestCorner = southwestCorner;
        this.northeastCorner = northeastCorner;
        this.elevation = elevation;
    }

    public Color getColor()
    {
        return color;
    }

    public void setColor(Color color)
    {
        if (color == null)
        {
            String msg = WorldWind.retrieveErrMsg("nullValue.ColorIsNull");
            WorldWind.logger().log(java.util.logging.Level.FINE, msg);
            throw new IllegalArgumentException(msg);
        }

        this.color = color;
    }

    public int getAntiAliasHint()
    {
        return antiAliasHint;
    }

    public void setAntiAliasHint(int hint)
    {
        if (!(hint == GL.GL_DONT_CARE || hint == GL.GL_FASTEST || hint == GL.GL_NICEST))
        {
            String msg = WorldWind.retrieveErrMsg("generic.InvalidHint");
            WorldWind.logger().log(java.util.logging.Level.FINE, msg);
            throw new IllegalArgumentException(msg);
        }

        this.antiAliasHint = hint;
    }

    public void setCorners(LatLon southWest, LatLon northEast)
    {
        this.southwestCorner = southWest;
        this.northeastCorner = northEast;
        this.vertices = null;
    }

    public LatLon[] getCorners()
    {
        LatLon[] retVal = new LatLon[2];

        retVal[0] = this.southwestCorner;
        retVal[1] = this.northeastCorner;

        return retVal;
    }

    public double getElevation()
    {
        return elevation;
    }

    public void setElevation(double elevation)
    {
        this.elevation = elevation;
        this.vertices = null;
    }

    private void intializeGeometry(DrawContext dc)
    {
        DoubleBuffer verts = BufferUtil.newDoubleBuffer(12);

        Point[] p = new Point[4];

        p[0] = dc.getGlobe().computePointFromPosition(this.southwestCorner.getLatitude(),
            this.southwestCorner.getLongitude(), this.elevation);
        p[1] = dc.getGlobe().computePointFromPosition(this.southwestCorner.getLatitude(),
            this.northeastCorner.getLongitude(), this.elevation);
        p[2] = dc.getGlobe().computePointFromPosition(this.northeastCorner.getLatitude(),
            this.northeastCorner.getLongitude(), this.elevation);
        p[3] = dc.getGlobe().computePointFromPosition(this.northeastCorner.getLatitude(),
            this.southwestCorner.getLongitude(), this.elevation);

        Point refcenter = Point.midPoint(p[0], p[2]);

        for (int i = 0; i < 4; i++)
        {
            verts.put(p[i].x() - refcenter.x());
            verts.put(p[i].y() - refcenter.y());
            verts.put(p[i].z() - refcenter.z());
        }

        this.referenceCenter = refcenter;
        this.vertices = verts;
    }

    public void render(DrawContext dc)
    {
        if (dc == null)
        {
            String message = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull");
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new IllegalStateException(message);
        }

        if (this.vertices == null)
        {
            this.intializeGeometry(dc);

            if (this.vertices == null)
                return; // TODO: log a warning
        }

        GL gl = dc.getGL();

        int attrBits = GL.GL_HINT_BIT | GL.GL_CURRENT_BIT;
        if (!dc.isPickingMode())
        {
            attrBits += GL.GL_CURRENT_BIT;
            if (this.color.getAlpha() != 255)
                attrBits += GL.GL_COLOR_BUFFER_BIT;
        }

        gl.glPushAttrib(attrBits);
        gl.glPushClientAttrib(GL.GL_CLIENT_VERTEX_ARRAY_BIT);
        dc.getView().pushReferenceCenter(dc, this.referenceCenter);

        try
        {
            if (!dc.isPickingMode())
            {
                if (this.color.getAlpha() != 255)
                {
                    gl.glEnable(GL.GL_BLEND);
                    gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
                }
                dc.getGL().glColor4ub((byte) this.color.getRed(), (byte) this.color.getGreen(),
                    (byte) this.color.getBlue(), (byte) this.color.getAlpha());
            }

            gl.glHint(GL.GL_POLYGON_SMOOTH_HINT, this.antiAliasHint);
            gl.glEnableClientState(GL.GL_VERTEX_ARRAY);
            gl.glVertexPointer(3, GL.GL_DOUBLE, 0, this.vertices.rewind());
            gl.glDrawArrays(GL.GL_QUADS, 0, 4);
        }
        finally
        {
            gl.glPopClientAttrib();
            gl.glPopAttrib();
            dc.getView().popReferenceCenter(dc);
        }
    }
}
