#include <RixPattern.h> 
#include <RixShadingUtils.h>
#include <RixShading.h>
#include <cstring>
    
class CutrSparky : public RixPattern {
public:
  
    CutrSparky();
    virtual ~CutrSparky() { }
    virtual int Init(RixContext &, char const *pluginpath);
    virtual RixSCParamInfo const *GetParamTable();
    virtual void Finalize(RixContext &) { }
    virtual int ComputeOutputParams(RixShadingContext const *ctx,
                                    RtInt *noutputs, 
                                    OutputSpec **outputs,
                                    RtConstPointer instanceData,
                                    RixSCParamInfo const *ignored);
    private:
        RixMessages *m_msg;
        RtFloat        m_age;
        RtFloat        m_width;
        RtFloat        m_frontblur;
        RtFloat        m_rearblur;
        RtColorRGB    m_start;
        RtColorRGB    m_end;
    };
  
CutrSparky::CutrSparky():
    m_msg(NULL),  
    m_age(0),
    m_width(0),
    m_frontblur(0),
    m_rearblur(0),
    m_start(1,1,1),
    m_end(1,1,1)
    { }
int CutrSparky::Init(RixContext &ctx, char const *pluginpath) {
    m_msg = (RixMessages*)ctx.GetRixInterface(k_RixMessages);
    return (!m_msg) ? 1 : 0;
    }
  
RixSCParamInfo const *CutrSparky::GetParamTable() {
    static RixSCParamInfo s_ptable[] = {
        // Output
        RixSCParamInfo("resultRGB", k_RixSCColor, k_RixSCOutput),
        RixSCParamInfo("resultF", k_RixSCFloat, k_RixSCOutput),
        // Input
        RixSCParamInfo("age", k_RixSCFloat),
        RixSCParamInfo("width", k_RixSCFloat),
        RixSCParamInfo("frontblur", k_RixSCFloat),
        RixSCParamInfo("rearblur", k_RixSCFloat),
        RixSCParamInfo("start", k_RixSCColor),
        RixSCParamInfo("end", k_RixSCColor),
        RixSCParamInfo() // end of table
        };
    return &s_ptable[0];
    }
  
enum paramIndex {
    k_resultRGB = 0,
    k_resultF,
    k_age,
    k_width,
    k_frontblur,
    k_rearblur,
    k_start,
    k_end
    };
    
int CutrSparky::ComputeOutputParams(RixShadingContext const *ctx,
                                RtInt *noutputs, 
                                OutputSpec **outputs,
                                RtConstPointer instanceData,
                                RixSCParamInfo const *ignored) {
    bool varying = true;
  
    // Declare a pointer for each input.
    RtFloat        const *age;
    RtFloat        const *width;
    RtFloat        const *frontblur;
    RtFloat        const *rearblur;
    RtColorRGB    const *start;
    RtColorRGB    const *end;
  
    ctx->EvalParam(k_age, -1, &age, &m_age, varying);
    ctx->EvalParam(k_width, -1, &width, &m_width, varying);
    ctx->EvalParam(k_frontblur, -1, &frontblur, &m_frontblur, varying);
    ctx->EvalParam(k_rearblur, -1, &rearblur, &m_rearblur, varying);
    ctx->EvalParam(k_start, -1, &start, &m_start, varying);
    ctx->EvalParam(k_end, -1, &end, &m_end, varying);
  
    // Allocate memory for the OutputSpec data structure.
    RixShadingContext::Allocator pool(ctx);
    OutputSpec *outSpec = pool.AllocForPattern<OutputSpec>(2);
    *outputs = outSpec;
  
    // Allocate memory for each output.
    RtColorRGB    *resultRGB = pool.AllocForPattern<RtColorRGB>(ctx->numPts);    
    RtFloat        *resultF = pool.AllocForPattern<RtFloat>(ctx->numPts);
    *noutputs = 2;
    outSpec[0].paramId = k_resultRGB;
    outSpec[0].detail = k_RixSCVarying;
    outSpec[0].value = resultRGB;
    outSpec[1].paramId = k_resultF;
    outSpec[1].detail = k_RixSCVarying;
    outSpec[1].value = resultF;
  
    // Surface parameter
    RtFloat const  *V;
    ctx->GetBuiltinVar(RixShadingContext::k_v, &V);
 
    // Assign values to each point.
    for(int i = 0; i < ctx->numPts; i++) {
        resultF[i] = RixSmoothStep(age[i] - rearblur[i], width[i] + age[i], V[i]) * 
                     (1 - RixSmoothStep(age[i], width[i] + age[i] + frontblur[i], V[i]));
        //m_msg->Info("%f\n", resultF[i]);
        resultRGB[i] = RixMix(start[i], end[i], resultF[i]);
        } 
    return 0;
    }
  
RIX_PATTERNCREATE {
    return new CutrSparky();
    }
RIX_PATTERNDESTROY {
    delete ((CutrSparky*)pattern);
    }