// Copyright (c) ZeroC, Inc.

#include "Ice/Properties.h"
#include "Ice/Initialize.h"
#include "Util.h"
#include "ice.h"

using namespace std;
using namespace IceMatlab;

extern "C"
{
    //
    // Implementation note: We need to pass the implementation object from MATLAB code for the defaults argument.
    // If we passed the wrapper object instead, there is no way to extract the void pointer from the mxArray object.
    //
    mxArray* Ice_createProperties(mxArray* args, void* defaultsImpl, void** r)
    {
        try
        {
            vector<string> a;
            getStringList(args, a);
            shared_ptr<Ice::Properties> def;
            if (defaultsImpl)
            {
                def = deref<Ice::Properties>(defaultsImpl);
            }
            auto props = Ice::createProperties(a, def);
            *r = new shared_ptr<Ice::Properties>(move(props));
            return createResultValue(createStringList(a));
        }
        catch (...)
        {
            return createResultException(convertException(std::current_exception()));
        }
    }

    mxArray* Ice_Properties_unref(void* self)
    {
        delete reinterpret_cast<shared_ptr<Ice::Properties>*>(self);
        return createEmptyArray();
    }

    mxArray* Ice_Properties_getProperty(void* self, const char* key)
    {
        try
        {
            return createResultValue(createStringFromUTF8(deref<Ice::Properties>(self)->getProperty(key)));
        }
        catch (...)
        {
            return createResultException(convertException(std::current_exception()));
        }
    }

    mxArray* Ice_Properties_getIceProperty(void* self, const char* key)
    {
        try
        {
            return createResultValue(createStringFromUTF8(deref<Ice::Properties>(self)->getIceProperty(key)));
        }
        catch (...)
        {
            return createResultException(convertException(std::current_exception()));
        }
    }

    mxArray* Ice_Properties_getPropertyWithDefault(void* self, const char* key, const char* dflt)
    {
        try
        {
            return createResultValue(
                createStringFromUTF8(deref<Ice::Properties>(self)->getPropertyWithDefault(key, dflt)));
        }
        catch (...)
        {
            return createResultException(convertException(std::current_exception()));
        }
    }

    mxArray* Ice_Properties_getPropertyAsInt(void* self, const char* key, int* r)
    {
        try
        {
            *r = deref<Ice::Properties>(self)->getPropertyAsInt(key);
            return createEmptyArray();
        }
        catch (...)
        {
            return convertException(std::current_exception());
        }
    }

    mxArray* Ice_Properties_getIcePropertyAsInt(void* self, const char* key, int* r)
    {
        try
        {
            *r = deref<Ice::Properties>(self)->getIcePropertyAsInt(key);
            return createEmptyArray();
        }
        catch (...)
        {
            return convertException(std::current_exception());
        }
    }

    mxArray* Ice_Properties_getPropertyAsIntWithDefault(void* self, const char* key, int dflt, int* r)
    {
        try
        {
            *r = deref<Ice::Properties>(self)->getPropertyAsIntWithDefault(key, dflt);
            return createEmptyArray();
        }
        catch (...)
        {
            return convertException(std::current_exception());
        }
    }

    mxArray* Ice_Properties_getPropertyAsList(void* self, const char* key)
    {
        try
        {
            auto l = deref<Ice::Properties>(self)->getPropertyAsList(key);
            return createResultValue(createStringList(l));
        }
        catch (...)
        {
            return createResultException(convertException(std::current_exception()));
        }
    }

    mxArray* Ice_Properties_getIcePropertyAsList(void* self, const char* key)
    {
        try
        {
            auto l = deref<Ice::Properties>(self)->getIcePropertyAsList(key);
            return createResultValue(createStringList(l));
        }
        catch (...)
        {
            return createResultException(convertException(std::current_exception()));
        }
    }

    mxArray* Ice_Properties_getPropertyAsListWithDefault(void* self, const char* key, mxArray* dflt)
    {
        try
        {
            Ice::StringSeq d;
            getStringList(dflt, d);
            Ice::StringSeq l = deref<Ice::Properties>(self)->getPropertyAsListWithDefault(key, d);
            return createResultValue(createStringList(l));
        }
        catch (...)
        {
            return createResultException(convertException(std::current_exception()));
        }
    }

    mxArray* Ice_Properties_getPropertiesForPrefix(void* self, const char* prefix)
    {
        try
        {
            auto d = deref<Ice::Properties>(self)->getPropertiesForPrefix(prefix);
            return createResultValue(createStringMap(d));
        }
        catch (...)
        {
            return createResultException(convertException(std::current_exception()));
        }
    }

    mxArray* Ice_Properties_setProperty(void* self, const char* key, const char* value)
    {
        try
        {
            deref<Ice::Properties>(self)->setProperty(key, value);
            return createEmptyArray();
        }
        catch (...)
        {
            return convertException(std::current_exception());
        }
    }

    mxArray* Ice_Properties_getCommandLineOptions(void* self)
    {
        try
        {
            auto opts = deref<Ice::Properties>(self)->getCommandLineOptions();
            return createResultValue(createStringList(opts));
        }
        catch (...)
        {
            return createResultException(convertException(std::current_exception()));
        }
    }

    mxArray* Ice_Properties_parseCommandLineOptions(void* self, const char* prefix, mxArray* options)
    {
        try
        {
            Ice::StringSeq opts;
            getStringList(options, opts);
            Ice::StringSeq rem = deref<Ice::Properties>(self)->parseCommandLineOptions(prefix, opts);
            return createResultValue(createStringList(rem));
        }
        catch (...)
        {
            return createResultException(convertException(std::current_exception()));
        }
    }

    mxArray* Ice_Properties_parseIceCommandLineOptions(void* self, mxArray* options)
    {
        try
        {
            Ice::StringSeq opts;
            getStringList(options, opts);
            Ice::StringSeq rem = deref<Ice::Properties>(self)->parseIceCommandLineOptions(opts);
            return createResultValue(createStringList(rem));
        }
        catch (...)
        {
            return createResultException(convertException(std::current_exception()));
        }
    }

    mxArray* Ice_Properties_load(void* self, const char* file)
    {
        try
        {
            deref<Ice::Properties>(self)->load(file);
            return createEmptyArray();
        }
        catch (...)
        {
            return convertException(std::current_exception());
        }
    }

    mxArray* Ice_Properties_clone(void* self, void** r)
    {
        try
        {
            *r = new shared_ptr<Ice::Properties>(deref<Ice::Properties>(self)->clone());
            return createEmptyArray();
        }
        catch (...)
        {
            return convertException(std::current_exception());
        }
    }
}
