#include "ArbGeomParams.h"
#include <sstream>
std::string GetArnoldTypeString( GeometryScope scope, int arnoldAPIType)
{
    std::ostringstream buffer;
    
    switch (scope)
    {
    case kUniformScope:
        buffer << "uniform";
        break;
    case kVaryingScope:
    case kVertexScope:
        buffer << "varying";
        break;
    case kFacevaryingScope:
        return ""; 
    case kConstantScope:
    default:
        buffer << "constant";
    }
    
    buffer << " ";
    
    switch ( arnoldAPIType )
    {
        case AI_TYPE_INT:
            buffer << "INT";
            break;
        case AI_TYPE_FLOAT:
            buffer << "FLOAT";
            break;
        case AI_TYPE_STRING:
            buffer << "STRING";
            break;
        case AI_TYPE_RGB:
            buffer << "RGB";
            break;
        case AI_TYPE_RGBA:
            buffer << "RGBA";
            break;
        case AI_TYPE_POINT:
            buffer << "POINT";
            break;
        case AI_TYPE_VECTOR:
            buffer << "VECTOR";
            break;
        case AI_TYPE_POINT2:
            buffer << "POINT2";
            break;
        case AI_TYPE_MATRIX:
            buffer << "MATRIX";
            break;
        default:
            
            return "";
    }
    
    
    return buffer.str();
}
template <typename T>
void AddArbitraryGeomParam( ICompoundProperty & parent,
                            const PropertyHeader &propHeader,
                            ISampleSelector &sampleSelector,
                            AtNode * primNode,
                            int arnoldAPIType)
{
    T param( parent, propHeader.getName() );
    
    if ( !param.valid() )
    {
        
        return;
    }
    
    std::string declStr = GetArnoldTypeString( param.getScope(),
            arnoldAPIType );
    if ( declStr.empty() )
    {
        return;
    }
    
    
    
    if ( param.getArrayExtent() > 1 )
    {
        return;
    }
    
    if ( !AiNodeDeclare( primNode, param.getName().c_str(), declStr.c_str() ) )
    {
        
        return;
    }
    
    if ( param.getScope() == kConstantScope ||
            param.getScope() == kUnknownScope)
    {
        
        
        
        typename T::prop_type::sample_ptr_type valueSample =
                param.getExpandedValue( sampleSelector ).getVals();
        
        switch ( arnoldAPIType )
        {
            case AI_TYPE_INT:
                AiNodeSetInt( primNode, param.getName().c_str(),
                        reinterpret_cast<const int32_t *>(
                                valueSample->get() )[0] );
                
                break;
            case AI_TYPE_FLOAT:
                AiNodeSetFlt( primNode, param.getName().c_str(),
                        reinterpret_cast<const float32_t *>(
                                valueSample->get() )[0] );
                break;
            case AI_TYPE_STRING:
                
                AiNodeSetStr( primNode, param.getName().c_str(),
                        reinterpret_cast<const std::string *>(
                                valueSample->get() )[0].c_str() );
                
                break;
            case AI_TYPE_RGB:
            {
                const float32_t * data = 
                        reinterpret_cast<const float32_t *>(
                                valueSample->get() );
                
                AiNodeSetRGB( primNode, param.getName().c_str(),
                        data[0], data[1], data[2]);
                
                break;
            }
            case AI_TYPE_RGBA:
            {
                const float32_t * data = 
                        reinterpret_cast<const float32_t *>(
                                valueSample->get() );
                
                AiNodeSetRGBA( primNode, param.getName().c_str(),
                        data[0], data[1], data[2], data[3]);
                
                break;
            }
            case AI_TYPE_POINT:
            {
                const float32_t * data = 
                        reinterpret_cast<const float32_t *>(
                                valueSample->get() );
                
                AiNodeSetPnt( primNode, param.getName().c_str(),
                        data[0], data[1], data[2]);
                
                break;
            }
            case AI_TYPE_VECTOR:
            {
                const float32_t * data = 
                        reinterpret_cast<const float32_t *>(
                                valueSample->get() );
                
                AiNodeSetVec( primNode, param.getName().c_str(),
                        data[0], data[1], data[2] );
                
                break;
            }
            case AI_TYPE_POINT2:
            {
                const float32_t * data = 
                        reinterpret_cast<const float32_t *>(
                                valueSample->get() );
                
                AiNodeSetPnt2( primNode, param.getName().c_str(),
                        data[0], data[1] );
                break;
            }
            case AI_TYPE_MATRIX:
            {
                const float32_t * data = 
                        reinterpret_cast<const float32_t *>(
                                valueSample->get() );
                
                AtMatrix m;
                for ( size_t i = 0; i < 16; ++i )
                {
                    *((&m[0][0])+i) = data[i];
                }
                AiNodeSetMatrix( primNode, param.getName().c_str(), m);
                
                
                break;
            }
            default:
                
                break;
        }
    }
    else
    {
        
        typename T::prop_type::sample_ptr_type valueSample =
                param.getExpandedValue( sampleSelector ).getVals();
        
        AiNodeSetArray( primNode, param.getName().c_str(),
                ArrayConvert( valueSample->size(), 1, arnoldAPIType,
                        (void *) valueSample->get() ) );
    }
    
    
}
void AddArbitraryStringGeomParam( ICompoundProperty & parent,
                            const PropertyHeader &propHeader,
                            ISampleSelector &sampleSelector,
                            AtNode * primNode)
{
    IStringGeomParam param( parent, propHeader.getName() );
    
    if ( !param.valid() )
    {
        
        return;
    }
    
    std::string declStr = GetArnoldTypeString( param.getScope(),
            AI_TYPE_STRING );
    if ( declStr.empty() )
    {
        return;
    }
    
    
    
    if ( param.getArrayExtent() > 1 )
    {
        return;
    }
    
    if ( !AiNodeDeclare( primNode, param.getName().c_str(), declStr.c_str() ) )
    {
        
        return;
    }
    
    IStringGeomParam::prop_type::sample_ptr_type valueSample =
                param.getExpandedValue( sampleSelector ).getVals();
    
    if ( param.getScope() == kConstantScope ||
            param.getScope() == kUnknownScope)
    {
        AiNodeSetStr( primNode, param.getName().c_str(),
                        reinterpret_cast<const std::string *>(
                                valueSample->get() )[0].c_str() );
    }
    else
    {
        std::vector<const char *> strPtrs;
        strPtrs.reserve( valueSample->size() );
        for ( size_t i = 0; i < valueSample->size(); ++i )
        {
            strPtrs.push_back( valueSample->get()[i].c_str() );
        }
        
        AiNodeSetArray( primNode, param.getName().c_str(),
                ArrayConvert( valueSample->size(), 1, AI_TYPE_STRING,
                        (void *) &strPtrs[0] ) );
        
    
    }
    
}
void AddArbitraryGeomParams( ICompoundProperty &parent,
                             ISampleSelector &sampleSelector,
                             AtNode * primNode,
                             const std::set<std::string> * excludeNames
                           )
{
    if ( primNode == NULL || !parent.valid() )
    {
        return;
    }
    
    for ( size_t i = 0; i < parent.getNumProperties(); ++i )
    {
        const PropertyHeader &propHeader = parent.getPropertyHeader( i );
        const std::string &propName = propHeader.getName();
        
        if (propName.empty()
            || ( excludeNames
                 && excludeNames->find( propName ) != excludeNames->end() ) )
        {
            continue;
        }
        
        if ( IFloatGeomParam::matches( propHeader ) )
        {
            AddArbitraryGeomParam<IFloatGeomParam>(
                    parent,
                    propHeader,
                    sampleSelector,
                    primNode,
                    AI_TYPE_FLOAT);
        }
        else if ( IInt32GeomParam::matches( propHeader ) )
        {
            AddArbitraryGeomParam<IInt32GeomParam>(
                    parent,
                    propHeader,
                    sampleSelector,
                    primNode,
                    AI_TYPE_INT);
        }
        else if ( IStringGeomParam::matches( propHeader ) )
        {
            AddArbitraryStringGeomParam(
                    parent,
                    propHeader,
                    sampleSelector,
                    primNode);
        }
        else if ( IV2fGeomParam::matches( propHeader ) )
        {
            AddArbitraryGeomParam<IV2fGeomParam>(
                    parent,
                    propHeader,
                    sampleSelector,
                    primNode,
                    AI_TYPE_POINT2);
        }
        else if ( IV3fGeomParam::matches( propHeader ) )
        {
            AddArbitraryGeomParam<IV3fGeomParam>(
                    parent,
                    propHeader,
                    sampleSelector,
                    primNode,
                    AI_TYPE_VECTOR);
        }
        else if ( IP3fGeomParam::matches( propHeader ) )
        {
            AddArbitraryGeomParam<IP3fGeomParam>(
                    parent,
                    propHeader,
                    sampleSelector,
                    primNode,
                    AI_TYPE_POINT);
        }
        else if ( IN3fGeomParam::matches( propHeader ) )
        {
            AddArbitraryGeomParam<IN3fGeomParam>(
                    parent,
                    propHeader,
                    sampleSelector,
                    primNode,
                    AI_TYPE_VECTOR);
        }
        else if ( IC3fGeomParam::matches( propHeader ) )
        {
            AddArbitraryGeomParam<IC3fGeomParam>(
                    parent,
                    propHeader,
                    sampleSelector,
                    primNode,
                    AI_TYPE_RGB);
        }
        else if ( IC4fGeomParam::matches( propHeader ) )
        {
            AddArbitraryGeomParam<IC4fGeomParam>(
                    parent,
                    propHeader,
                    sampleSelector,
                    primNode,
                    AI_TYPE_RGBA);
        }
        if ( IM44fGeomParam::matches( propHeader ) )
        {
            AddArbitraryGeomParam<IM44fGeomParam>(
                    parent,
                    propHeader,
                    sampleSelector,
                    primNode,
                    AI_TYPE_MATRIX);
        }
        
        
    }
}