/*******************************************************************************
 * Copyright 2012-present Pixate, Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
/**
 * Copyright (c) 2012-2013 Pixate, Inc. All rights reserved.
 */
package com.pixate.freestyle.cg.strokes;

import java.util.Arrays;

import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.Path;

import com.pixate.freestyle.cg.paints.PXPaint;
import com.pixate.freestyle.util.ObjectPool;

/**
 * A PX stroke representation.
 */
public class PXStroke implements PXStrokeRenderer {

    public enum PXStrokeType {
        CENTER,
        INNER,
        OUTER
    }

    protected PXStrokeType type;
    protected float width;
    protected PXPaint color;
    protected float[] dashArray;
    protected int dashOffset;
    protected Cap lineCap;
    protected Join lineJoin;
    protected float miterLimit;

    /**
     * Constructs a new PX stroke.
     */
    public PXStroke() {
        this.type = PXStrokeType.CENTER;
        this.width = 0.0f;
        this.dashOffset = 0;
        this.lineCap = Cap.BUTT;
        this.lineJoin = Join.MITER;
        this.miterLimit = 4.0f; // What is a reasonable default here?
    }

    public PXStroke(float width) {
        this();
        this.width = width;
    }

    /**
     * Returns a stroke {@link Paint}. Note that this method does not check into
     * the pool any Paint that may have been pulled from it. The responsibility
     * here is up to the caller.
     * 
     * @param p
     * @param useOriginal Indicate that the given {@link Paint} instance should
     *            be applied with the stroke information.
     * @return A {@link Paint} reference (a new Paint in case the useOriginal
     *         was false)
     */
    public Paint getStrokedPaint(Paint p, boolean useOriginal) {
        Paint paint = useOriginal ? p : ObjectPool.paintPool.checkOut(p);
        paint.setStyle(Style.STROKE);
        paint.setStrokeWidth(width);

        if (dashArray != null && dashArray.length > 0) {
            paint.setPathEffect(new DashPathEffect(dashArray, dashOffset));
        }

        paint.setStrokeCap(this.lineCap);
        paint.setStrokeJoin(this.lineJoin);
        paint.setStrokeMiter(this.miterLimit);
        return paint;
    }

    public boolean isOpaque() {
        return color != null && color.isOpaque();
    }

    public void applyStrokeToPath(Path path, Paint paint, Canvas context) {
        if (color != null && width > 0) {
            // stroke and possibly dash incoming path
            boolean paintCreated = false;
            if (paint == null) {
                paint = ObjectPool.paintPool.checkOut();
                paintCreated = true;
            }
            Paint p = getStrokedPaint(paint, paintCreated);
            // set up masking for inner/outer/center stroke
            if (type == PXStrokeType.INNER) {
                context.save();
                // clip to path
                context.clipPath(path);
            } else if (type == PXStrokeType.OUTER) {
                // TODO:
            }
            // else is center, so do nothing

            color.applyFillToPath(path, p, context);

            // reset environment
            if (type == PXStrokeType.INNER) {
                context.restore();
            } else if (type == PXStrokeType.OUTER) {
                // TODO: just move condition into above test
            }

            // Check the paint back into the pool. Make sure that we check in
            // only Paint instances that were pulled from the pool in this
            // method.
            if (paintCreated) {
                ObjectPool.paintPool.checkIn(paint);
            } else {
                ObjectPool.paintPool.checkIn(p);
            }
        }
    }

    /**
     * @return the type
     */
    public PXStrokeType getType() {
        return type;
    }

    /**
     * @param type the type to set
     */
    public void setType(PXStrokeType type) {
        this.type = type;
    }

    /**
     * @return the color
     */
    public PXPaint getColor() {
        return color;
    }

    /**
     * @param color the color to set
     */
    public void setColor(PXPaint color) {
        this.color = color;
    }

    /**
     * @return the width
     */
    public float getWidth() {
        return width;
    }

    /**
     * @param width the width to set
     */
    public void setWidth(float width) {
        this.width = width;
    }

    /**
     * @return the dashArray
     */
    public float[] getDashArray() {
        return dashArray;
    }

    /**
     * @param dashArray the dashArray to set
     */
    public void setDashArray(float[] dashArray) {
        this.dashArray = dashArray;
    }

    /**
     * @return the dashOffset
     */
    public int getDashOffset() {
        return dashOffset;
    }

    /**
     * @param dashOffset the dashOffset to set
     */
    public void setDashOffset(int dashOffset) {
        this.dashOffset = dashOffset;
    }

    /**
     * @return the lineCap
     */
    public Cap getLineCap() {
        return lineCap;
    }

    /**
     * @param lineCap the lineCap to set
     */
    public void setLineCap(Cap lineCap) {
        this.lineCap = lineCap;
    }

    /**
     * @return the lineJoin
     */
    public Join getLineJoin() {
        return lineJoin;
    }

    /**
     * @param lineJoin the lineJoin to set
     */
    public void setLineJoin(Join lineJoin) {
        this.lineJoin = lineJoin;
    }

    /**
     * @return the miterLimit
     */
    public float getMiterLimit() {
        return miterLimit;
    }

    /**
     * @param miterLimit the miterLimit to set
     */
    public void setMiterLimit(float miterLimit) {
        this.miterLimit = miterLimit;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof PXStroke) {
            PXStroke other = (PXStroke) o;
            // @formatter:off
			return (this.type == other.type)
					&&  (this.color == other.color)
					&&  (this.width == other.width)
					&&  Arrays.equals(this.dashArray ,other.dashArray)
					&&  (this.dashOffset == other.dashOffset)
					&&  (this.lineCap == other.lineCap)
					&&  (this.lineJoin == other.lineJoin)
					&&  (this.miterLimit == other.miterLimit);
			// @formatter:on
        }
        return false;
    }
}

@@ -3240,24 +3240,25 @@
 l && width %3E
+=
  0) %7B%0A      

Fix an issue in the PXStroke class that prevented stroke drawing when the width is zero.