/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */


#include "SkDrawGradient.h"
#include "SkAnimateMaker.h"
#include "SkAnimatorScript.h"
#include "SkGradientShader.h"

#if SK_USE_CONDENSED_INFO == 0

const SkMemberInfo SkDrawGradient::fInfo[] = {
    SK_MEMBER_INHERITED,
    SK_MEMBER_ARRAY(offsets, Float),
    SK_MEMBER(unitMapper, String)
};

#endif

DEFINE_GET_MEMBER(SkDrawGradient);

SkDrawGradient::SkDrawGradient() {
}

SkDrawGradient::~SkDrawGradient() {
    for (int index = 0; index < fDrawColors.count(); index++)
        delete fDrawColors[index];
}

bool SkDrawGradient::addChild(SkAnimateMaker& , SkDisplayable* child) {
    SkASSERT(child);
    if (child->isColor()) {
        SkDrawColor* color = (SkDrawColor*) child;
        *fDrawColors.append() = color;
        return true;
    }
    return false;
}

int SkDrawGradient::addPrelude() {
    int count = fDrawColors.count();
    fColors.setCount(count);
    for (int index = 0; index < count; index++)
        fColors[index] = fDrawColors[index]->color;
    return count;
}

#ifdef SK_DUMP_ENABLED
void SkDrawGradient::dumpRest(SkAnimateMaker* maker) {
    dumpAttrs(maker);
    //can a gradient have no colors?
    bool closedYet = false;
    SkDisplayList::fIndent += 4;
    for (SkDrawColor** ptr = fDrawColors.begin(); ptr < fDrawColors.end(); ptr++) {
        if (closedYet == false) {
            SkDebugf(">\n");
            closedYet = true;
        }
        SkDrawColor* color = *ptr;
        color->dump(maker);
    }
    SkDisplayList::fIndent -= 4;
    dumpChildren(maker, closedYet); //dumps the matrix if it has one
}
#endif

void SkDrawGradient::onEndElement(SkAnimateMaker& maker) {
    if (offsets.count() != 0) {
        if (offsets.count() != fDrawColors.count()) {
            maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsDontMatchColors);
            return;
        }
        if (offsets[0] != 0) {
            maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustStartWithZero);
            return;
        }
        if (offsets[offsets.count()-1] != SK_Scalar1) {
            maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustEndWithOne);
            return;
        }
        for (int i = 1; i < offsets.count(); i++) {
            if (offsets[i] <= offsets[i-1]) {
                maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustIncrease);
                return;
            }
            if (offsets[i] > SK_Scalar1) {
                maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustBeNoMoreThanOne);
                return;
            }
        }
    }
    INHERITED::onEndElement(maker);
}

#if SK_USE_CONDENSED_INFO == 0

const SkMemberInfo SkDrawLinearGradient::fInfo[] = {
    SK_MEMBER_INHERITED,
    SK_MEMBER_ARRAY(points, Float),
};

#endif

DEFINE_GET_MEMBER(SkDrawLinearGradient);

SkDrawLinearGradient::SkDrawLinearGradient() {
}

void SkDrawLinearGradient::onEndElement(SkAnimateMaker& maker)
{
    if (points.count() != 4)
        maker.setErrorCode(SkDisplayXMLParserError::kGradientPointsLengthMustBeFour);
    INHERITED::onEndElement(maker);
}

#ifdef SK_DUMP_ENABLED
void SkDrawLinearGradient::dump(SkAnimateMaker* maker) {
    dumpBase(maker);
    dumpRest(maker);
    }
#endif

SkShader* SkDrawLinearGradient::getShader() {
    if (addPrelude() == 0 || points.count() != 4)
        return NULL;
    SkShader* shader = SkGradientShader::CreateLinear((SkPoint*)points.begin(),
        fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode,
        0, getMatrix());
    SkAutoTDelete<SkShader> autoDel(shader);
    (void)autoDel.detach();
    return shader;
}


#if SK_USE_CONDENSED_INFO == 0

const SkMemberInfo SkDrawRadialGradient::fInfo[] = {
    SK_MEMBER_INHERITED,
    SK_MEMBER(center, Point),
    SK_MEMBER(radius, Float)
};

#endif

DEFINE_GET_MEMBER(SkDrawRadialGradient);

SkDrawRadialGradient::SkDrawRadialGradient() : radius(0) {
    center.set(0, 0);
}

#ifdef SK_DUMP_ENABLED
void SkDrawRadialGradient::dump(SkAnimateMaker* maker) {
    dumpBase(maker);
    dumpRest(maker);
}
#endif

SkShader* SkDrawRadialGradient::getShader() {
    if (addPrelude() == 0)
        return NULL;
    SkShader* shader = SkGradientShader::CreateRadial(center,
        radius, fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode,
        0, getMatrix());
    SkAutoTDelete<SkShader> autoDel(shader);
    (void)autoDel.detach();
    return shader;
}