/*
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 gov.nasa.worldwind.*;
import gov.nasa.worldwind.layers.*;

import javax.media.opengl.*;
import java.awt.*;
import java.awt.image.*;
import java.util.*;

import com.sun.opengl.util.texture.*;

/**
 * @author tag
 * @version $Id: SurfaceShape.java 1767 2007-05-07 21:36:12Z tgaskins $
 */
public abstract class SurfaceShape implements Renderable, Disposable
{
    private static final Color DEFAULT_COLOR = new Color(1f, 1f, 0f, 0.4f);
    private static final Color DEFAULT_BORDER_COLOR = new Color(1f, 1f, 0f, 0.7f);
    private static final int DEFAULT_TEXTURE_SIZE = 512;
    private static final int DEFAULT_NUM_EDGE_INTERVALS = 10;

    private TextureTile tile;
    private int textureSize = DEFAULT_TEXTURE_SIZE;
    private Paint paint;
    private Color borderColor;
    private Stroke stroke = new BasicStroke();
    private boolean drawBorder = true;
    private boolean drawInterior = true;
    private boolean antiAlias = true;
    private int numEdgeIntervals = DEFAULT_NUM_EDGE_INTERVALS;
    private ArrayList<LatLon> positions = new ArrayList<LatLon>();

    protected abstract BufferedImage drawShape(BufferedImage image);

    public SurfaceShape(Iterable<LatLon> positions, Color color, Color borderColor)
    {
        if (positions == null)
        {
            String message = WorldWind.retrieveErrMsg("nullValue.PositionsListIsNull");
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new IllegalArgumentException(message);
        }

        createTextureTiles(Sector.boundingSector(positions));
        this.paint = color != null ? color : DEFAULT_COLOR;
        this.borderColor = borderColor != null ? borderColor : DEFAULT_BORDER_COLOR;

        for (LatLon p : positions)
        {
            this.positions.add(p);
        }
    }

    private void createTextureTiles(Sector sector)
    {
        this.tile = new TextureTile(sector);
    }

    public void dispose()
    {
        if (this.tile != null)
            this.tile.dispose();
    }

    public Sector getSector()
    {
        return this.tile.getSector();
    }

    public ArrayList<LatLon> getPositions()
    {
        return positions;
    }

    private TextureTile getTextureTile()
    {
        return this.tile;
    }

    public Paint getPaint()
    {
        return paint;
    }

    public void setPaint(Paint paint)
    {
        this.paint = paint;
        this.getTextureTile().setTextureData(null);
    }

    public Color getBorderColor()
    {
        return borderColor;
    }

    public void setBorderColor(Color borderColor)
    {
        this.borderColor = borderColor;
        this.getTextureTile().setTextureData(null);
    }

    public int getTextureSize()
    {
        return textureSize;
    }

    public void setTextureSize(int textureSize)
    {
        this.textureSize = textureSize;
        this.getTextureTile().setTextureData(null);
    }

    public Stroke getStroke()
    {
        return stroke;
    }

    public void setStroke(Stroke stroke)
    {
        this.stroke = stroke;
        this.getTextureTile().setTextureData(null);
    }

    public boolean isDrawBorder()
    {
        return drawBorder;
    }

    public void setDrawBorder(boolean drawBorder)
    {
        this.drawBorder = drawBorder;
    }

    public boolean isDrawInterior()
    {
        return drawInterior;
    }

    public void setDrawInterior(boolean drawInterior)
    {
        this.drawInterior = drawInterior;
    }

    public boolean isAntiAlias()
    {
        return antiAlias;
    }

    public void setAntiAlias(boolean antiAlias)
    {
        this.antiAlias = antiAlias;
    }

    public int getNumEdgeIntervals()
    {
        return numEdgeIntervals;
    }

    public void setNumEdgeIntervals(int numEdgeIntervals)
    {
        this.numEdgeIntervals = numEdgeIntervals;
    }

    private boolean intersects(Sector sector)
    {
        return this.tile.getSector().intersects(sector);
    }

    public void render(DrawContext dc)
    {
        if (!this.intersects(dc.getVisibleSector()))
            return;

        if (this.getTextureTile().getTextureData() == null)
            this.tile.setTextureData(this.makeTextureData(this.textureSize));

        GL gl = dc.getGL();

        gl.glPushAttrib(GL.GL_COLOR_BUFFER_BIT | GL.GL_POLYGON_BIT);

        try
        {
            if (!dc.isPickingMode())
            {
                gl.glEnable(GL.GL_BLEND);
                gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
            }

            gl.glPolygonMode(GL.GL_FRONT, GL.GL_FILL);
            gl.glEnable(GL.GL_CULL_FACE);
            gl.glCullFace(GL.GL_BACK);

            dc.getSurfaceTileRenderer().renderTile(dc, this.tile);
        }
        finally
        {
            gl.glPopAttrib();
        }
    }

    private TextureData makeTextureData(int size)
    {
        BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_4BYTE_ABGR);

        TextureData td = new TextureData(GL.GL_RGBA, GL.GL_RGBA, false, this.drawShape(image));
        td.setMustFlipVertically(false);

        return td;
    }
}
