////////////////////////////////////////////////////////////////////////////////////////////////////
// NoesisGUI - http://www.noesisengine.com
// Copyright (c) 2013 Noesis Technologies S.L. All Rights Reserved.
////////////////////////////////////////////////////////////////////////////////////////////////////


#include "MathConverter.h"
#include "ArithmeticParser.h"

#include <NsCore/ReflectionImplement.h>
#ifdef NS_HAVE_STUDIO
#include <NsCore/Category.h>
#endif

#include <math.h>


using namespace Noesis;
using namespace NoesisApp;


////////////////////////////////////////////////////////////////////////////////////////////////////
MathConverter::MathConverter(): mExpr("{0}")
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////
const char* MathConverter::GetExpression() const
{
    return mExpr.Str();
}

////////////////////////////////////////////////////////////////////////////////////////////////////
void MathConverter::SetExpression(const char* expr)
{
    mExpr = expr;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
bool MathConverter::TryConvert(BaseComponent* value, const Type*, BaseComponent* parameter,
    Ptr<BaseComponent>& result)
{
    if (!mExpr.Empty())
    {
        float input = value ? (float)atof(value->ToString().Str()) : 0.0f;
        float param = parameter ? (float)atof(parameter->ToString().Str()) : 0.0f;
        float output;

        if (Parse(mExpr.Str(), input, param, output))
        {
            result.Reset(Boxing::Box(output));
            return true;
        }
    }

    return false;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
bool MathConverter::TryConvert(ArrayRef<BaseComponent*> values, const Type*,
    BaseComponent* parameter, Ptr<BaseComponent>& result)
{
    if (!mExpr.Empty())
    {
        Vector<float, 8> inputs;
        for (uint32_t i = 0; i < values.Size(); ++i)
        {
            inputs.PushBack(values[i] ? (float)atof(values[i]->ToString().Str()) : 0.0f);
        }
        float param = parameter ? (float)atof(parameter->ToString().Str()) : 0.0f;
        float output;

        if (Parse(mExpr.Str(), inputs, param, output))
        {
            result.Reset(Boxing::Box(output));
            return true;
        }
    }

    return false;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
bool MathConverter::TryConvertBack(BaseComponent*, ArrayRef<const Type*>, BaseComponent*,
    BaseVector<Ptr<BaseComponent>>&)
{
    return false;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
NS_BEGIN_COLD_REGION

NS_IMPLEMENT_REFLECTION(MathConverter, "NoesisGUIExtensions.MathConverter")
{
#ifdef NS_HAVE_STUDIO
    NsMeta<Category>("Converters");
#endif

    NsImpl<IMultiValueConverter>();

    NsProp("Expression", &MathConverter::mExpr);
}

NS_END_COLD_REGION
