/*
 * Copyright 2009 Funambol, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id$ */

#include "Errors.h"
#include "commontypes.h"
#include "daemon/ProfileComponentsHolder.h"
#include "DaemonDM/Messenger.h"
#include "Logger/LoggerMacroses.h"
#include "treemanager/AlertCommand.h"
#include "treemanager/AlertResponseCommand.h"
#include "serverexchange/commands/AlertCodes.h"


using namespace NS_DM_Client;
using namespace NS_DM_Client::NS_SyncMLCommand;

static const char *c_LogName = "AlertCommand";


static bool readProperty(const char *prop, const char *pname, String &out)
{
    if (!prop) return false;

    char *pch = const_cast<char*>(strstr(prop, pname));
    if (pch)
    {
        pch += strlen(pname);
        while (*pch != '=' && *pch != '\0')
            ++pch;
        if (pch)
        {
            pch++;
            out = pch;
            GDLDEBUG("Property '%s' has value '%s'", pname, pch);
            return true;
        }
    }
    return false;
}


static void parseOptionalParams(const char *prop, UIOptionalParameters &out)
{
    if (!prop) return;

    char *buf = Funambol::stringdup(prop);
    char *pch = strtok(buf, "&");
    while (pch)
    {
        // look for: MINDT, MAXDT
        String result;
        if (readProperty(pch, "MINDT", result))
        {
            out.push_back(UIOptionalParameterData(e_MINDT, result));
        }
        else if (readProperty(pch, "MAXDT", result))
        {
            out.push_back(UIOptionalParameterData(e_MAXDT, result));
        }
        else if (readProperty(pch, "DR", result))
        {
            out.push_back(UIOptionalParameterData(e_DR, result));
        }
        else if (readProperty(pch, "MAXLEN", result))
        {
            out.push_back(UIOptionalParameterData(e_MAXLEN, result));
        }
        else if (readProperty(pch, "IT", result))
        {
            out.push_back(UIOptionalParameterData(e_IT, result));
        }
        else if (readProperty(pch, "ET", result))
        {
            out.push_back(UIOptionalParameterData(e_ET, result));
        }
        else
        {
            GDLWARN("unkown Option");
        }

        pch = strtok(NULL, "&");
    }

    SAFE_DELETE_ARR(buf);
}


AlertCommand::AlertCommand(ProfileComponentsHolder* prholder,
                           AlertPtr& cmd,
                           const String& msgID,
                           const char* serverId)
    : ActionCommand(prholder, cmd, msgID, serverId), m_AlertCommand(cmd)
{
    if(cmd.get() == NULL)
    {
        GDLWARN("cmd is NULL");
    }
}


MOTreeResponseCommand * AlertCommand::CreateResponse()
{
GDLDEBUG("ENTER");

    MOTreeResponseCommand *pResponse = 
        new(std::nothrow) AlertResponseCommand(m_pProfile, m_AlertCommand, m_resCode, m_messageID, m_results, m_serverID);
    if(pResponse == (MOTreeResponseCommand*)NULL)
    {
        GDLWARN("new AlertResponseCommand");
    }

    if (m_pCommandsSink)
    {
        pResponse->SetCommandsSink(*m_pCommandsSink);
    }
GDLDEBUG("LEAVE");

    return pResponse;
}


bool AlertCommand::Execute()
{
GDLDEBUG("ENTER");

    m_resCode = e_OptionalFeatureNotSupported;

    int data = 0;
    if (m_AlertCommand.get())
    {
        data = m_AlertCommand->getData();
    }

    GDLDEBUG("Alert data - %d", data);
    switch (data)
    {
        case AC_DISPLAY_MESSAGE:
        case AC_CONFIRM_OR_REJECT:
        case AC_TEXT_INPUT:
        case AC_SINGLE_CHOICE:
        case AC_MULTIPLE_CHOICE:
            m_resCode = handleAlert(data); break;
        default:
            GDLWARN("Unkown Alert Code");
            break;
    }

    GDLDEBUG("Alert display result: %d", m_resCode);

    InvokeResult();

GDLDEBUG("LEAVE");

    return true;
}


StatusCode AlertCommand::handleAlert(int alertcode)
{
GDLDEBUG("ENTER");

    StatusCode result = e_CommandFailed;
    Funambol::ArrayList *items = m_AlertCommand->getItems();
    if (items && items->size() >= 2)
    {
        Funambol::Item *pParamItem = (Funambol::Item *)items->get(0);
        Funambol::Item *pMsgItem  = (Funambol::Item *)items->get(1);
        if (pMsgItem->getData() && pMsgItem->getData()->getData())
        {
            const char *data = NULL;
            if (pParamItem->getData() && pParamItem->getData()->getData())
            {
                data = pParamItem->getData()->getData();
            }
            const char * msg = pMsgItem->getData()->getData();

            Messenger *pMessenger = CreateMessenger();
            GDLDEBUG("Messenger instance: %x", pMessenger);
            if (pMessenger != (Messenger*)NULL)
            {
                GDLDEBUG("Display message: '%s'", msg);
                UIOptionalParameters params;
                String userinput;
                parseOptionalParams(data, params);

                switch (alertcode)
                {
                    case AC_DISPLAY_MESSAGE:
                        result = pMessenger->Display(msg, params);
                        break;

                    case AC_CONFIRM_OR_REJECT:
                        result = pMessenger->Confirmation(msg, params);
                        break;

                    case AC_TEXT_INPUT:
                        result = pMessenger->UserInput(msg, params, userinput);
                        m_results.push_back(userinput);
                        break;

                    case AC_SINGLE_CHOICE:
                    case AC_MULTIPLE_CHOICE:
                        UserAvailableChoiseSet choises;
                        for (int i=2; i<items->size(); ++i)
                        {
                            Funambol::Item *item = (Funambol::Item *) items->get(i);
                            if (item && item->getData() && item->getData()->getData())
                            {
                                choises.push_back(item->getData()->getData());
                            }
                            else
                            {
                                GDLERROR("Item contains empty data for choice");
                                result = e_IncompleteCommand;
                            }
                        }

                        if (!choises.empty())
                        {
                            int choicescount = 0;
                            UserChoiseSet choosedset;
                            if (AC_MULTIPLE_CHOICE == alertcode)
                            {
                                result = pMessenger->UserChoice(msg, params, choises, choosedset, true);
                            }
                            else
                            {
                                result = pMessenger->UserChoice(msg, params, choises, choosedset, false);
                            }
                            for (unsigned int i=0; i<choosedset.size(); ++i)
                            {
                                char buffer[16];
                                memset(buffer, '\0', 16);
                                if (choosedset[i] <= choicescount && choosedset[i] >= 1)
                                {
                                    sprintf(buffer, "%d", choosedset[i]);
                                    m_results.push_back(buffer);
                                }
                                else
                                {
                                    GDLERROR("Wrong result from user chice - %d; expected values are in [%d, %d]",
                                        choosedset[i], 1, choicescount);
                                    result = e_CommandFailed;
                                    break;
                                }
                            }
                        }
                        else
                        {
                            GDLERROR("No items for choice display");
                            result = e_IncompleteCommand;
                        }
                }
                pMessenger->Release();
                pMessenger = (Messenger*)NULL;
            } // if (pMessenger)
            else
            {
                GDLERROR("Returned pointer to Messenger is NULL");
            }
        } // if (pMsgItem->getData() && pMsgItem->getData()->getData())
        else
        {
            GDLERROR("Second alert's item have empty data");
        }
    } // if (items && items->size() >= 2)
    else
    {
        GDLERROR("Items count (%d != 2)", items ? items->size() : -1);
    }

GDLDEBUG("LEAVE");

    return result;
}
