/*
* 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 "MessageListenerActionThread.h"
#include "DaemonDM/MessageListener.h"
#include "DaemonDM/IMessageHandler.h"
#include "MessengerDefs.h"
#include "common/Buffer.h"
#include "Logger/Logger.h"

#include "platform.h"

namespace NS_DM_Client
{

//------------------------------------------------------------------------------------------------------
MessageListenerActionThread::MessageListenerActionThread()
{
}
//------------------------------------------------------------------------------------------------------
MessageListenerActionThread::~MessageListenerActionThread()
{
}
//------------------------------------------------------------------------------------------------------
MessageListenerActionThread& MessageListenerActionThread::operator=(MessageListenerActionThread&)
{
    #ifndef PLATFORM_ANDROID
        throw "error: trying to call operator= for MessageListenerActionThread";
    #else
        NULL;
    #endif

    return *this;
}
//------------------------------------------------------------------------------------------------------
MessageListenerActionThread::MessageListenerActionThread(MessageListenerActionThread&)
{
    #ifndef PLATFORM_ANDROID
        throw "error: trying to call copy constructor for MessageListenerActionThread";
    #else
        NULL;
    #endif
}
//------------------------------------------------------------------------------------------------------
bool MessageListenerActionThread::Init(MessageListener* listener)
{
    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "ENTER >> MessageListenerActionThread::Init");
    m_listener = listener;
    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << MessageListenerActionThread::Init, Return status: %d", true);
    return true;
}
//------------------------------------------------------------------------------------------------------
StatusCode perform_Display(const Buffer& buffer, IMessageHandler* handler);
StatusCode respond_Display(StatusCode status, IFIFOWrapper* response_fifo);

StatusCode perform_Confirmation(const Buffer& buffer, IMessageHandler* handler);
StatusCode respond_Confirmation(StatusCode status, IFIFOWrapper* response_fifo);

StatusCode perform_userInput(const Buffer& buffer, IMessageHandler* handler, String& input);
StatusCode respond_userInput(StatusCode status, IFIFOWrapper* response_fifo, const String& input);

StatusCode perform_userChoises(const Buffer& buffer, IMessageHandler* handler, UserChoiseSet& choise);
StatusCode respond_userChoises(StatusCode status, IFIFOWrapper* response_fifo, const UserChoiseSet& choise);

StatusCode perform_progressNotification(const Buffer& buffer, IMessageHandler* handler);
StatusCode respond_progressNotification(StatusCode status, IFIFOWrapper* response_fifo);
//------------------------------------------------------------------------------------------------------
bool MessageListenerCheckStopCondition(const Buffer& buffer)
{
    char stop_request[c_StopRequestSize + 1];
    memset(stop_request, '\0', c_StopRequestSize + 1);
    memcpy(stop_request, buffer.GetPointer(), c_StopRequestSize);
    if (strcmp(stop_request, c_StopRequest) == 0)
    {
        return true;
    }
    return false;
}
//------------------------------------------------------------------------------------------------------
void MessageListenerActionThread::run()
{
    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "ENTER >> MessageListenerActionThread::run");

    IFIFOWrapper* fifo_request, *fifo_response;
    while (true)
    {
        if (!initializeFifos(fifo_request, fifo_response, false, true))
        {
            LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << MessageListenerActionThread::run with fail, reason: initialize fifos failed");
            return;
        }
        while (true)
        {
            Buffer buffer(sizeof(UIExchangeHead), '\0');
            UIExchangeHead request_head;
            if (fifo_request->Read(buffer) == e_Ok)
            {
                if (MessageListenerCheckStopCondition(buffer))
                {   // stop thread
                    releaseFifos(fifo_request, fifo_response);
                    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << MessageListenerActionThread::run, reason: arrive stop request");
                    return;
                }
                memset(&request_head, '\0', sizeof(UIExchangeHead));
                memcpy(&request_head, buffer.GetPointer(), sizeof(UIExchangeHead));

                LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "Request head readed. Request type: %d, Payload size: %d", request_head.m_type, request_head.m_payload_size);

                buffer.Allocate(request_head.m_payload_size, '\0');
                if (fifo_request->Read(buffer) == e_Ok)
                {
                LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "buffer: %s", (char*)buffer.GetPointer());

                    switch(request_head.m_type)
                    {
                    case e_Display:
                    {
                        StatusCode res = perform_Display(buffer, m_listener->GetMessageHandler());
                        respond_Display(res, fifo_response);
                        break;
                    }
                    case e_Confirmation:
                    {
                        StatusCode res = perform_Confirmation(buffer, m_listener->GetMessageHandler());
                        respond_Confirmation(res, fifo_response);
                        break;
                    }
                    case e_UserInput:
                    {
                        String user_input;
                        StatusCode res = perform_userInput(buffer, m_listener->GetMessageHandler(), user_input);
                        respond_userInput(res, fifo_response, user_input);
                        break;
                    }
                    case e_UserChoice:
                    {
                        UserChoiseSet user_choises;
                        StatusCode res = perform_userChoises(buffer, m_listener->GetMessageHandler(), user_choises);
                        respond_userChoises(res, fifo_response, user_choises);
                        break;
                    }
                    case e_ProgressNotification:
                    {
                        StatusCode res = perform_progressNotification(buffer, m_listener->GetMessageHandler());
                        respond_progressNotification(res, fifo_response);
                        break;
                    }
                    default:
                    {
                        break;
                    }
                    };
                }
            }
            else
            {
                releaseFifos(fifo_request, fifo_response);
                LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "read from request fifo failed");
                break;
            }
        }
    }
    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << MessageListenerActionThread::run with fail");
    return;
}
//------------------------------------------------------------------------------------------------------
StatusCode perform_Display(const Buffer& buffer, IMessageHandler* handler)
{
    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "ENTER >> perform_Display");

    String message = "";
    String pars = "";
    if (!extractComplexRequestPayload(buffer.GetPointer(), buffer.Size(), message, pars, 0, 0))
    {
        LOG_ERROR_(NS_Logging::GetLogger(c_MessageListenerLog), "%s", "can't extract request payload");
        LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << perform_Display. Return status: %d", e_Failed);
        return e_Failed;
    }

    UIOptionalParameters opt_pars;
    memset(&opt_pars, 0,sizeof(UIOptionalParameters));
    if (!formOptParsFromPayload(pars, opt_pars))
    {
        LOG_ERROR_(NS_Logging::GetLogger(c_MessageListenerLog), "%s", "can't extract optional parameters from payload");
        LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << perform_Display. Return status: %d", e_Failed);
        return e_Failed;
    }

    long min_dt = -1, max_dt = -1;
    get_MINDT(opt_pars, min_dt);
    get_MAXDT(opt_pars, max_dt);

    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "BEFORE CALL IMessageHandler::Display: message= %s, min time = %ld, max time = %ld", message.c_str(), min_dt, max_dt);
    StatusCode input_res = handler->Display(message.c_str(), min_dt, max_dt);
    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "AFTER CALL IMessageHandler::Display: result status = %d", input_res);

    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << perform_Display. Return status: %d", input_res);
    return input_res;
}
//------------------------------------------------------------------------------------------------------
StatusCode respond_Display(StatusCode status, IFIFOWrapper* response_fifo)
{
    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "ENTER >> respond_Display. Status code for response = %d", status);

    UIResponseExchangeHead head(status, 0); /* payload size for display == 0 */
    Buffer response(sizeof(head) + head.m_payload_size, '\0');
    memcpy(response.GetPointer(), &head, sizeof(head));

	bool response_res = (response_fifo->Write(response) == e_Ok) ? true : false;
    if (!response_res)
    {
        LOG_ERROR_(NS_Logging::GetLogger(c_MessageListenerLog), "write to response fifo failed");
    }

    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << respond_Display. Return status: %d", response_res ? e_Ok : e_Failed);
    return (response_res ? e_Ok : e_Failed);
}
//------------------------------------------------------------------------------------------------------
StatusCode perform_Confirmation(const Buffer& buffer, IMessageHandler* handler)
{
    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "ENTER >> perform_Confirmation");

    String message = "";
    String pars = "";

    if (!extractComplexRequestPayload(buffer.GetPointer(), buffer.Size(), message, pars, 0, 0))
    {
        LOG_ERROR_(NS_Logging::GetLogger(c_MessageListenerLog), "%s", "can't extract request payload");
        LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << perform_Confirmation. Return status: %d", e_Failed);
        return e_Failed;
    }

    UIOptionalParameters opt_pars;
    memset(&opt_pars, 0,sizeof(UIOptionalParameters));
    if (!formOptParsFromPayload(pars, opt_pars))
    {
        LOG_ERROR_(NS_Logging::GetLogger(c_MessageListenerLog), "%s", "can't extract optional parameters from payload");
        LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << perform_Confirmation. Return status: %d", e_Failed);
        return e_Failed;
    }

    long min_dt = -1, max_dt = -1;
    get_MINDT(opt_pars, min_dt);
    get_MAXDT(opt_pars, max_dt);

    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "BEFORE CALL IMessageHandler::Confirmation: message= %s, min time = %ld, max time = %ld", message.c_str(), min_dt, max_dt);
    StatusCode input_res = handler->Confirmation(message.c_str(), min_dt, max_dt);
    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "AFTER CALL IMessageHandler::Confirmation: result status = %d", input_res);

    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << perform_Confirmation. Return status: %d", input_res);
    return input_res;
}
//------------------------------------------------------------------------------------------------------
StatusCode respond_Confirmation(StatusCode status, IFIFOWrapper* response_fifo)
{
    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "ENTER >> respond_Confirmation. Status code for response = %d", status);

    UIResponseExchangeHead head(status, 0); /* payload size for confirmation == 0 */
    Buffer response(sizeof(head) + head.m_payload_size, '\0');
    memcpy(response.GetPointer(), &head, sizeof(head));

    bool response_res = (response_fifo->Write(response) == e_Ok) ? true : false;
    if (!response_res)
    {
        LOG_ERROR_(NS_Logging::GetLogger(c_MessageListenerLog), "write to response fifo failed");
    }

    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << respond_Confirmation. Return status: %d", response_res ? e_Ok : e_Failed);
    return (response_res ? e_Ok : e_Failed);
}
//------------------------------------------------------------------------------------------------------
StatusCode perform_userInput(const Buffer& buffer, IMessageHandler* handler, String& input)
{
    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "ENTER >> perform_userInput");

    String message = "";
    String pars = "";

    if (!extractComplexRequestPayload(buffer.GetPointer(), buffer.Size(), message, pars, 0, 0))
    {
        LOG_ERROR_(NS_Logging::GetLogger(c_MessageListenerLog), "%s", "can't extract request payload");
        LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << perform_userInput. Return status: %d", e_Failed);
        return e_Failed;
    }

    UIOptionalParameters opt_pars;
    memset(&opt_pars, 0,sizeof(UIOptionalParameters));
    if (!formOptParsFromPayload(pars, opt_pars))
    {
        LOG_ERROR_(NS_Logging::GetLogger(c_MessageListenerLog), "%s", "can't extract optional parameters from payload");
        LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << perform_userInput. Return status: %d", e_Failed);
        return e_Failed;
    }

    long min_dt = -1, max_dt = -1, max_len = -1;
    bool max_len_present = false;
    bool echo_password = true;
    bool echo_password_present = false;

    get_MINDT(opt_pars, min_dt);
    get_MAXDT(opt_pars, max_dt);
    if (get_MAXLEN(opt_pars, max_len))
    {
        max_len_present = true;
    }
    if (get_ET(opt_pars, echo_password))
    {
        echo_password_present = true;
    }

    char* user_input = 0;


    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog),
        "BEFORE CALL IMessageHandler::UserInput: message= %s, min time = %ld, max time = %ld, max length = %d, echo mode =%d",
        message.c_str(), min_dt, max_dt, max_len_present ? (&max_len) : 0, echo_password_present ? echo_password : 0);

    StatusCode input_res = handler->UserInput(message.c_str(), min_dt, max_dt, user_input,
        max_len_present ? max_len : 0, echo_password_present ? echo_password : 0);

    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog),
        "AFTER CALL IMessageHandler::UserInput: user input = %s, result status = %d", user_input ? user_input : "no input", input_res);

    input = user_input;
    handler->ReleaseString(user_input);

    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << perform_userInput. Return status: %d", input_res);
    return input_res;
}
//------------------------------------------------------------------------------------------------------
StatusCode respond_userInput(StatusCode status, IFIFOWrapper* response_fifo, const String& input)
{
    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "ENTER >> respond_userInput. Status code for response = %d", status);

    UIResponseExchangeHead head(status, (status == e_Ok) ? (input.length() + 1) : 0);
    Buffer response(sizeof(head) + head.m_payload_size, '\0');
    memcpy(response.GetPointer(), &head, sizeof(head));
    memcpy( ((char*)response.GetPointer()) + sizeof(head), input.c_str(), input.length());
    ((char*)response.GetPointer())[sizeof(head) + input.length()] = '\0';

	bool response_res = (response_fifo->Write(response) == e_Ok) ? true : false;
    if (!response_res)
    {
        LOG_ERROR_(NS_Logging::GetLogger(c_MessageListenerLog), "write to response fifo failed");
    }

    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << respond_userInput. Return status: %d", response_res ? e_Ok : e_Failed);
    return (response_res ? e_Ok : e_Failed);
}
//------------------------------------------------------------------------------------------------------
StatusCode perform_userChoises(const Buffer& buffer, IMessageHandler* handler, UserChoiseSet& choise)
{
    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "ENTER >> perform_userChoises");

    String message = "";
    String pars = "";
    String choises = "";

    if (!extractComplexRequestPayload(buffer.GetPointer(), buffer.Size(), message, pars, &choises, 0))
    {
        LOG_ERROR_(NS_Logging::GetLogger(c_MessageListenerLog), "%s", "can't extract request payload");
        LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << perform_userChoises. Return status: %d", e_Failed);
        return e_Failed;
    }

    UIOptionalParameters opt_pars;
    memset(&opt_pars, 0,sizeof(UIOptionalParameters));
    bool allowMultipleChoises = false;
    if (!formOptParsFromPayload(pars, opt_pars, &allowMultipleChoises))
    {
        LOG_ERROR_(NS_Logging::GetLogger(c_MessageListenerLog), "%s", "can't extract optional parameters from payload");
        LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << perform_userChoises. Return status: %d", e_Failed);
        return e_Failed;
    }

    long min_dt = -1, max_dt = -1;
    get_MINDT(opt_pars, min_dt);
    get_MAXDT(opt_pars, max_dt);

    char* user_choise = 0;

    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog),
        "BEFORE CALL IMessageHandler::UserChoice: message= %s, min time = %ld, max time = %ld, avialable choise set = %s, allow multiple choises =%d",
        message.c_str(), min_dt, max_dt, choises.c_str(), allowMultipleChoises);

    StatusCode input_res = handler->UserChoice(message.c_str(), min_dt, max_dt, choises.c_str(), user_choise, allowMultipleChoises);

    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog),
        "AFTER CALL IMessageHandler::UserChoice: user choise = %s, result status = %d", user_choise ? user_choise : "no choise", input_res);

    if (input_res == e_Ok)
    {
        String usr_choise = user_choise;
        if (!getNumericUserChoise(choises, usr_choise, choise))
        {
            LOG_ERROR_(NS_Logging::GetLogger(c_MessageListenerLog), "%s", "can't get numeric user choises from string representation");
            input_res = e_Failed;
        }
    }
    handler->ReleaseString(user_choise);

    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << perform_userChoises. Return status: %d", input_res);
    return input_res;
}
//------------------------------------------------------------------------------------------------------
StatusCode respond_userChoises(StatusCode status, IFIFOWrapper* response_fifo, const UserChoiseSet& choise)
{
    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "ENTER >> respond_userChoises. Status code for response = %d", status);

    String str_choises = "";
    formStringFromNumericUserChoise(choise, str_choises);
LOG_INFO_(NS_Logging::GetLogger(c_MessageListenerLog), "str_choises: %s", str_choises.c_str());

    UIResponseExchangeHead head(status, (status == e_Ok) ? (str_choises.length() + 1) : 0);
    Buffer response(sizeof(head) + head.m_payload_size, '\0');
    memcpy(response.GetPointer(), &head, sizeof(head));
    memcpy( ((char*)response.GetPointer()) + sizeof(head), str_choises.c_str(), str_choises.length());
    ((char*)response.GetPointer())[sizeof(head) + str_choises.length()] = '\0';

	bool response_res = (response_fifo->Write(response) == e_Ok) ? true : false;
    if (!response_res)
    {
        LOG_ERROR_(NS_Logging::GetLogger(c_MessageListenerLog), "write to response fifo failed");
    }

    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << respond_userChoises. Return status: %d", response_res ? e_Ok : e_Failed);
    return (response_res ? e_Ok : e_Failed);
}
//------------------------------------------------------------------------------------------------------
StatusCode perform_progressNotification(const Buffer& buffer, IMessageHandler* handler)
{
    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "ENTER >> perform_progressNotification");

    String message = "";
    String pars = "";
    UIOptionalParameters opt_pars;
    String progress = "";

    if (!extractComplexRequestPayload(buffer.GetPointer(), buffer.Size(), message, pars, 0, &progress))
    {
        LOG_ERROR_(NS_Logging::GetLogger(c_MessageListenerLog), "%s", "can't extract request payload");
        LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << perform_progressNotification. Return status: %d", e_Failed);
        return e_Failed;
    }

    memset(&opt_pars, 0,sizeof(UIOptionalParameters));
    if (!formOptParsFromPayload(pars, opt_pars))
    {
        LOG_ERROR_(NS_Logging::GetLogger(c_MessageListenerLog), "%s", "can't extract optional parameters from payload");
        LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << perform_progressNotification. Return status: %d", e_Failed);
        return e_Failed;
    }

    long min_dt = -1, max_dt = -1;
    get_MINDT(opt_pars, min_dt);
    get_MAXDT(opt_pars, max_dt);

    long long_progress = 0;

	#if defined PLATFORM_WINDOWS
		sscanf_s(progress.c_str(), "%ld", &long_progress);
	#else
		sscanf(progress.c_str(), "%ld", &long_progress);
	#endif

	LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog),
        "BEFORE CALL IMessageHandler::ProgressNotification: message= %s, min time = %ld, max time = %ld, progress =%ld",
        message.c_str(), min_dt, max_dt, long_progress);

    StatusCode progress_res = handler->ProgressNotification(message.c_str(), min_dt, max_dt, long_progress);

    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog),
        "AFTER CALL IMessageHandler::ProgressNotification: result status = %d", progress_res);

    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << perform_progressNotification. Return status: %d", progress_res);
    return progress_res;
}
//------------------------------------------------------------------------------------------------------
StatusCode respond_progressNotification(StatusCode status, IFIFOWrapper* response_fifo)
{
    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "ENTER >> respond_progressNotification. Status code for response = %d", status);

    UIResponseExchangeHead head(status, 0); /* payload size for notification == 0 */
    Buffer response(sizeof(head) + head.m_payload_size, '\0');
    memcpy(response.GetPointer(), &head, sizeof(head));

	bool response_res = (response_fifo->Write(response) == e_Ok) ? true : false;
    if (!response_res)
    {
        LOG_ERROR_(NS_Logging::GetLogger(c_MessageListenerLog), "write to response fifo failed");
    }

    LOG_DEBUG_(NS_Logging::GetLogger(c_MessageListenerLog), "LEAVE << respond_progressNotification. Return status: %d", response_res ? e_Ok : e_Failed);
    return (response_res ? e_Ok : e_Failed);
}
//------------------------------------------------------------------------------------------------------

}
