/*
 * The contents of this file are subject to the terms of the Common Development
 * and Distribution License (the License). You may not use this file except in
 * compliance with the License.
 *
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
 * or http://www.netbeans.org/cddl.txt.
 * 
 * When distributing Covered Code, include this CDDL Header Notice in each file
 * and include the License file at http://www.netbeans.org/cddl.txt.
 * If applicable, add the following below the CDDL Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 * Microsystems, Inc. All Rights Reserved.
 */
package org.netbeans.swing.plaf.aqua;

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;

/**
 * A gradient paint context which paints rounded borders.
 *
 * @author Tim Boudreau
 */
public class ShapeGradientContext implements PaintContext {
    protected Color shadowColor, bgColor;
    protected Rectangle r;
    int cornerRadius = 6;
    public ShapeGradientContext(Rectangle r, Color c1, Color c2) {
        shadowColor = c1;
        bgColor = c2;
        this.r = r;
        
        r.height -= cornerRadius * 2;
        r.width -= cornerRadius * 4;
        r.x += (cornerRadius * 2) + 1;
        r.y += cornerRadius;
    }
    
    public void dispose() {}
    
    public ColorModel getColorModel() { return ColorModel.getRGBdefault(); }
    
    int shadowWidth = 21;
    
    private WritableRaster raster = null;
    int[] last = new int[] {-1,-1,-1,-1};
    
    public Raster getRaster(int x, int y, int w, int h) {
        if (this.raster != null && x == last[0] && y == last[1] && w == last[2] &&
            h == last[3]) {
            return raster;
        }
        
        last[0] = x; last[1] = y; last[2] = w; last[3] = h;
        raster =
            getColorModel().createCompatibleWritableRaster(w, h);
        
        //XXX We don't need to allocate all this memory, we're only drawing
        //into a small strip down the side 
        
//        int[] data = new int[w * h * 4];
        
        for (int j = 0; j < h; j++) {
            for (int i = 0; i < w; i++) {
                
                //OPTIMIZATION: Skip interior pixels far from the edges
                if (j < r.y + r.height - (shadowWidth + cornerRadius)) {
                    int rightStart  = w - (r.x + r.width + shadowWidth + cornerRadius);
                    if (i > (shadowWidth + cornerRadius) && w < rightStart) {
                        //Skip ahead to the right edge if we're not painting
                        //the bottom
                        i = rightStart;
                    }
                }
                
                double ratio = 1;
                Point2D.Double nearest = POINT;
                nearest.setLocation(i > r.x + r.width ? r.x + r.width : i < r.x ? r.x : i,
                    Math.min (j, y+r.y+r.height)); 
                
                //Calculate the distance to the nearest point on the nearest
                //edge
                double dist = nearest.distance (x + i, y + j) + 1;
                
                
                //Multiply in the corner radius as needed to get rounded
                //looking shadows
                dist *= dist / ((shadowWidth - x) + cornerRadius);
                
                //Fade the shadow at the top so it doesn't have a sharp upper 
                //edge
                if (j <= (cornerRadius * 2)) {
                    double factor = (double) (cornerRadius * 2) / (double) j;
                    dist *= factor;
                }

                //Get the ratio between the colors
                ratio = dist / (shadowWidth - x);

                //Normalize to 1.0 or strange things happen
                if (ratio > 1.0)
                    ratio = 1.0;
                
                //Index of pixel
//                int base = (j * w + i) * 4;
                int base = 0;
                
                data[base + 0] = (int)(shadowColor.getRed() + ratio *
                (bgColor.getRed() - shadowColor.getRed()));
                data[base + 1] = (int)(shadowColor.getGreen() + ratio *
                (bgColor.getGreen() - shadowColor.getGreen()));
                data[base + 2] = (int)(shadowColor.getBlue() + ratio *
                (bgColor.getBlue() - shadowColor.getBlue()));
                data[base + 3] = (int)(shadowColor.getAlpha() + ratio *
                (bgColor.getAlpha() - shadowColor.getAlpha()));
                
                raster.setPixels (i, j, 1, 1, data);
            }
        }
//        raster.setPixels(0, 0, w, h, data);
         
        
        return raster;
    }
    private static int[] data = new int[4];
    private static Point2D.Double POINT = new Point2D.Double();
}
