/*
 * Copyright (C) 2009 - 2010 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

/* $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));
		}

		if (readProperty(pch, "MAXDT", result))
		{
			out.push_back(UIOptionalParameterData(e_MAXDT, result));
		}
		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)
{
}


MOTreeResponseCommand * AlertCommand::CreateResponse()
{
	MOTreeResponseCommand *pResponse = 
		new AlertResponseCommand(m_pProfile, m_AlertCommand, m_resCode, m_messageID, m_results, m_serverID);
	if (m_pCommandsSink)
		pResponse->SetCommandsSink(*m_pCommandsSink);
	return pResponse;
}


bool AlertCommand::Execute()
{
	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:
			break;
	}

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

	InvokeResult();
    return true;
}


StatusCode AlertCommand::handleAlert(int alertcode)
{
	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)
			{
				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:
						UserAvialableChoiseSet 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] = {0};
								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();
				SAFE_DELETE(pMessenger);
			}
			else
				GDLERROR("Returned pointer to Messenger is NULL");
		}
		else
			GDLERROR("Second alert's item have empty data");
	}
	else
		GDLERROR("Items count (%d != 2)", items ? items->size() : -1);

	return result;
}
