//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//	$Revision: 4 $																//
//																				//
//	Name       : SwiSMSEngine.cpp												//
//                                                                              //
//	Purpose    : SMS engine for sample application                  			//
//																				//
//	Copyright (c) 2002-2003 Sierra Wireless, Inc.  All rights reserved	 		//
//																				//
//////////////////////////////////////////////////////////////////////////////////

#include "list.h"
#include "time.h"
#include "stdafx.h"
#include <GobiAPI.h>
#include "SMSEngine.h"
#include "MTListCtrl.h"
#include <GobiConnectionMgmtAPI.h>
#include "SwiWwanCmApi.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CSwiSMSSampleApp construction

CSMSEngine::CSMSEngine()
{
	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
}

CSMSEngine::~CSMSEngine()
{
}

CSMSMsgInfo & CSMSMsgInfo::operator=(CSMSMsgInfo & msgInfo)
{
	m_StorageType		= msgInfo.m_StorageType;
	m_Tag				= msgInfo.m_Tag;
	m_Format			= msgInfo.m_Format;
	m_RefNum			= msgInfo.m_RefNum;
	memset(m_SenderAddr, 0x00, 14*2);
	memcpy(m_SenderAddr, msgInfo.m_SenderAddr, 14*2);
	memcpy(m_TimeStamp, msgInfo.m_TimeStamp, 7);
	m_TotalFragments	= msgInfo.m_TotalFragments;

	POSITION pos = msgInfo.m_MsgFragList.GetHeadPosition();

	if(pos != NULL)
	{
		for (int i=0; i<msgInfo.m_MsgFragList.GetCount(); i++)
		{
			m_MsgFragList.AddTail(msgInfo.m_MsgFragList.GetNext(pos));
		}
	}
	return msgInfo;
}

CSMSMsgInfo::CSMSMsgInfo(CSMSMsgInfo& msgInfo)
{
	m_StorageType		= msgInfo.m_StorageType;
	m_Tag				= msgInfo.m_Tag;
	m_Format			= msgInfo.m_Format;
	m_RefNum			= msgInfo.m_RefNum;
	memset(m_SenderAddr, 0x00, 14*2);
	memcpy(m_SenderAddr, msgInfo.m_SenderAddr, 14*2);
	memcpy(m_TimeStamp, msgInfo.m_TimeStamp, 7);
	m_TotalFragments	= msgInfo.m_TotalFragments;

	POSITION pos = msgInfo.m_MsgFragList.GetHeadPosition();

	if(pos != NULL)
	{

		for (int i=0; i<msgInfo.m_MsgFragList.GetCount(); i++)
		{
			m_MsgFragList.AddTail(msgInfo.m_MsgFragList.GetNext(pos));
		}
	}
}

CSMSMsgInfo::CSMSMsgInfo()
{
	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
}

CSMSMsgFrag::CSMSMsgFrag(CSMSMsgFrag & msgFrag)
{
	m_Index			= msgFrag.m_Index;
	m_FragmentNum	= msgFrag.m_FragmentNum;
	memset(m_TextMessage, 0, 482);
	memcpy(m_TextMessage, msgFrag.m_TextMessage, 480);
}

CSMSMsgInfo::~CSMSMsgInfo()
{
}


CSMSMsgFrag::CSMSMsgFrag()
{
	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
}

CSMSMsgFrag::~CSMSMsgFrag()
{
}

CSMSMsgFrag & CSMSMsgFrag::operator=(CSMSMsgFrag & msgFrag)
{
	m_Index		= msgFrag.m_Index;
	m_FragmentNum = msgFrag.m_FragmentNum;
	memset(m_TextMessage, 0x00, 482);
	memcpy(m_TextMessage, msgFrag.m_TextMessage, 480);

	return msgFrag;
}

void CSMSEngine::StartupEngine(CMTListCtrl* pInboxUI)
{
	m_pInboxUI = pInboxUI;
	ULONG ret;
	ULONG msgList[255][2];
	ULONG storageType;
	ULONG tag;
	ULONG msgListSize;

    // BZ30177, we need to retrieve and list all the received SMSs in both
    // CDMA and WCDMA protocol.
    for (int i = 0; i <= 1; i++)
    {
        // BZ30177: In order to retrieve and list all the received SMSs, we need 
        // to set the SMS protocol first.
        SetSMSProtocol( i );

	    // Get READ messages from USIM
	    storageType = 0;	// USIM
	    tag = 0;			// READ
	    msgListSize = 255;	// Maximum number of message
    	
	    ret = GetSMSList(storageType, &tag, &msgListSize, (BYTE *)&msgList[0][0]);
	    if(ret == 0)
	    {
		    // loop through all the READ messages on the USIM
		    for(ULONG i = 0; i < msgListSize; i++)
		    {
			    GetNewMessage(storageType, msgList[i][0]);
		    }
	    }

	    // Get UNREAD messages from UIM
	    storageType = 0;	// USIM
	    tag = 1;			// UNREAD
	    msgListSize = 255;	// Maximum number of messages
	    ret = GetSMSList(storageType, &tag, &msgListSize, (BYTE *)&msgList[0][0]);
	    if(ret == 0)
	    {
		    // loop through all the UNREAD messages on the USIM
		    for(ULONG i = 0; i < msgListSize; i++)
		    {
			    GetNewMessage(storageType, msgList[i][0]);
		    }
	    }

	    // Get READ messages from NV
	    storageType = 1;	// NV
	    tag = 0;			// READ
	    msgListSize = 255;	// Maximum number of messages
	    ret = GetSMSList(storageType, &tag, &msgListSize, (BYTE *)&msgList[0][0]);
	    if(ret == 0)
	    {
		    // loop through all the READ messages from NV
		    for(ULONG i = 0; i < msgListSize; i++)
		    {
			    GetNewMessage(storageType, msgList[i][0]);
		    }
	    }

	    // Get UNREAD messages from NV
	    storageType = 1;	// NV
	    tag = 1;			// UNREAD
	    msgListSize = 255;	// Maximum number of messages
	    ret = GetSMSList(storageType, &tag, &msgListSize, (BYTE *)&msgList[0][0]);
	    if(ret == 0)
	    {
		    // loop through all the UNREAD messages from NV
		    for(ULONG i = 0; i < msgListSize; i++)
		    {
			    GetNewMessage(storageType, msgList[i][0]);
		    }
	    }
    }
}

void CSMSEngine::GetNewMessage(ULONG storageType, ULONG msgIndex)
{
	ULONG ret;
	ULONG tag;
	ULONG format;
	BYTE addressLength = 20;
	CHAR address[20];
	BYTE textLength = 255;
	ULONG msgLength = 176;
	BYTE  message[176];
	BOOLEAN fragmentedMsg;
	BOOLEAN newMsg = TRUE;
	POSITION pos = NULL;
		
	ret = GetSMS(storageType, msgIndex, &tag, &format, &msgLength, message);

	if(ret == 0)
	{
		CSMSMsgInfo MsgEntry;
		CSMSMsgFrag MsgText;

		MsgText.m_Index= msgIndex;
		MsgText.m_FragmentNum = 1;

		MsgEntry.m_Tag = tag;
		MsgEntry.m_StorageType = storageType;
		MsgEntry.m_Format = format;
		MsgEntry.m_TotalFragments = 1;
		MsgEntry.m_RefNum = 0;

		if(format == 6)
		{
			if((tag == 0) || (tag == 1))
			{
				ret = WCDMADecodeMTTextMsg(message, 
						&addressLength, 
						address,
						&textLength,
						MsgText.m_TextMessage,
						NULL,
						NULL,
						NULL,
						NULL,
						NULL,
						MsgEntry.m_TimeStamp,
						&fragmentedMsg,
						&MsgEntry.m_RefNum,
						&MsgEntry.m_TotalFragments,
						&MsgText.m_FragmentNum);

				if (ret)
					return;

				MultiByteToWideChar(CP_ACP, 0, address, -1, MsgEntry.m_SenderAddr, 14);

				if(!fragmentedMsg)
				{
					MsgEntry.m_MsgFragList.AddTail(MsgText);
					m_Inbox.AddTail(MsgEntry);
					pos = m_Inbox.GetTailPosition();
				}
				else
				{
					pos = FindMessage(storageType, format, MsgEntry.m_RefNum, MsgEntry.m_TotalFragments);

					if(pos != NULL)
					{
						CSMSMsgInfo existingEntry = m_Inbox.GetAt(pos);

						// if existing entry is READ and new fragment is UNREAD
						if(existingEntry.m_Tag == 0 && MsgEntry.m_Tag == 1)
						{
							// mark existing message as UNREAD
							existingEntry.m_Tag = 1;
						}
						existingEntry.m_MsgFragList.AddTail(MsgText);
						m_Inbox.SetAt(pos, existingEntry);
						newMsg = FALSE;
					}
					else
					{
						MsgEntry.m_MsgFragList.AddTail(MsgText);
						m_Inbox.AddTail(MsgEntry);
						pos = m_Inbox.GetTailPosition();
					}
				}
			}
             ChangeInboxDisplay(newMsg, pos);
		}
		// CDMA case
		else if (format == 0) 
		{
			ret = CDMADecodeMTTextMsg(msgLength, 
					message, 
					&MsgEntry.m_RefNum, 
					&addressLength, 
					address,
					&textLength,
					MsgText.m_TextMessage,
					NULL, 
					NULL,
					NULL,
					MsgEntry.m_TimeStamp,
					NULL,
					NULL,
					NULL,
					NULL,
					NULL,
					NULL);

			MultiByteToWideChar(CP_ACP, 0, address, -1, MsgEntry.m_SenderAddr, 14);
			MsgEntry.m_MsgFragList.AddTail(MsgText);
			m_Inbox.AddTail(MsgEntry);
			pos = m_Inbox.GetTailPosition();

			ChangeInboxDisplay(newMsg, pos);
		}
        else 
        {
            // something went wrong
        }
	}
}

POSITION CSMSEngine::FindMessage(ULONG storageType, ULONG format, ULONG refNum, BYTE totalFragments)
{
	POSITION pos = m_Inbox.GetHeadPosition();
	CSMSMsgInfo msgEntry;

	if(pos == NULL)
	{
		return NULL;
	}

	for(int i = (int)m_Inbox.GetCount(); i != 0; i--)
	{
		msgEntry = m_Inbox.GetAt(pos);

		if( (msgEntry.m_StorageType == storageType) &&
			(msgEntry.m_Format == format) &&
			(msgEntry.m_RefNum == refNum) &&
			(msgEntry.m_TotalFragments == totalFragments))
		{
			return(pos);
		}
		m_Inbox.GetNext(pos);
	}
	return (NULL);
}

void CSMSEngine::DeleteMessage(ULONG msgHandle)
{
	//get messageInfo
	CSMSMsgInfo msgEntry = m_Inbox.GetAt((POSITION)msgHandle);
	CSMSMsgFrag fragInfo;

	// delete from inbox display

	POSITION pos =  msgEntry.m_MsgFragList.GetHeadPosition();
	if(pos != NULL)
	{
		for(int i = (int)msgEntry.m_MsgFragList.GetCount(); i != 0; i--)
		{
			fragInfo = msgEntry.m_MsgFragList.GetAt(pos);
			DeleteSMS(msgEntry.m_StorageType, &fragInfo.m_Index, NULL);
			msgEntry.m_MsgFragList.GetNext(pos);
		}
		msgEntry.m_MsgFragList.RemoveAll();

		// delete entry
		m_Inbox.RemoveAt((POSITION)msgHandle);
	}
}

void CSMSEngine::DeleteAllMessages(void)
{
	POSITION pos = m_Inbox.GetHeadPosition();
	CSMSMsgInfo msgEntry;

	if(pos == NULL)
	{
		return;
	}

	for(int i = (int)m_Inbox.GetCount(); i != 0; i--)
	{
		msgEntry = m_Inbox.GetAt(pos);

		POSITION posFrag =  msgEntry.m_MsgFragList.GetHeadPosition();
		if(posFrag != NULL)
		{
			for(int j = (int)msgEntry.m_MsgFragList.GetCount(); j != 0; j--)
			{
				CSMSMsgFrag fragInfo = msgEntry.m_MsgFragList.GetAt(posFrag);
				DeleteSMS(msgEntry.m_StorageType, &fragInfo.m_Index, NULL);
				msgEntry.m_MsgFragList.GetNext(posFrag);
			}
			msgEntry.m_MsgFragList.RemoveAll();
		}
		m_Inbox.GetNext(pos);
	}
	m_Inbox.RemoveAll();
}

void CSMSEngine::ChangeMessageStatus(ULONG msgHandle)
{
	//get messageInfo
	CSMSMsgInfo msgEntry = m_Inbox.GetAt((POSITION)msgHandle);
	CSMSMsgFrag fragInfo;

	// if message is marked as UNREAD
	if(msgEntry.m_Tag == 1)
	{
		POSITION pos =  msgEntry.m_MsgFragList.GetHeadPosition();
		if(pos != NULL)
		{
			// loop through all the fragments marking them as READ
			for(int i = (int)msgEntry.m_MsgFragList.GetCount(); i != 0; i--)
			{	
				fragInfo = msgEntry.m_MsgFragList.GetAt(pos);
                // We are not changing the SMS protocol here as we have no knowledge about 
                // the SMS protocol of current message.  So, potentially, we might be getting
                // to read a CDMA unread message, but can't modify the SMS status as the 
                // current SMS protocol setting is set to WCDMA, or vice versa.  Ideally, 
                // this protocol information should be coming from the modem notification, 
                // and bundled with the message itself.
				ModifySMSStatus(msgEntry.m_StorageType, fragInfo.m_Index, 0);
				msgEntry.m_MsgFragList.GetNext(pos);
			}
		}
		// mark cached copy as READ
		msgEntry.m_Tag = 0;
		m_Inbox.SetAt((POSITION)msgHandle, msgEntry);
	}
	// update the display
	ChangeInboxDisplay(FALSE, (POSITION)msgHandle);
}

void CSMSEngine::ChangeInboxDisplay(BOOLEAN newMsg, POSITION msgPos)
{
		//get messageInfo
	CSMSMsgInfo msgEntry = m_Inbox.GetAt(msgPos);
	CSMSMsgFrag fragInfo;

			// convert time
	TCHAR timeString[MAX_PATH];
	if(msgEntry.m_TimeStamp[1]== 0xff && msgEntry.m_TimeStamp[2] == 0xff) //0xff when no timestamp
	{
		swprintf(timeString, L"No time stamp");
		
	}
	else
	{
		CTime timestamp(msgEntry.m_TimeStamp[0] + 2000, 
					msgEntry.m_TimeStamp[1], 
					msgEntry.m_TimeStamp[2],
					msgEntry.m_TimeStamp[3],
					msgEntry.m_TimeStamp[4],
					msgEntry.m_TimeStamp[5]);
		wcscpy(timeString, (timestamp.Format(L"%c")).GetBuffer());
	}

	// construct text message
	CString textmessage = L"";

	BOOLEAN found = FALSE;
	BOOLEAN previousnotfound = FALSE;

	for(BYTE fragNum = 1; fragNum <= msgEntry.m_TotalFragments; fragNum++)
	{
		found = FALSE;
		POSITION pos =  msgEntry.m_MsgFragList.GetHeadPosition();
		if(pos != NULL)
		{
			// loop through all the fragments marking them as READ
			for(int i = (int)msgEntry.m_MsgFragList.GetCount(); i != 0; i--)
			{	
				fragInfo = msgEntry.m_MsgFragList.GetAt(pos);
				if(fragInfo.m_FragmentNum == fragNum)
				{
					found = TRUE;
					previousnotfound = FALSE;
					textmessage += fragInfo.m_TextMessage;
					break;
				}
				msgEntry.m_MsgFragList.GetNext(pos);
			}
		}
		if(!found && !previousnotfound)
		{
			previousnotfound = TRUE;
			textmessage += L"[Receiving Text...]";
		}
	}

	// display information to user
	if(newMsg)
	{
		m_pInboxUI->AddMessage((ULONG)msgPos, &msgEntry.m_StorageType, &msgEntry.m_Format, &msgEntry.m_Tag, msgEntry.m_SenderAddr, timeString, textmessage.GetBuffer());
	}
	else
	{
		m_pInboxUI->UpdateMessage((ULONG)msgPos, &msgEntry.m_StorageType, &msgEntry.m_Format, &msgEntry.m_Tag, msgEntry.m_SenderAddr, timeString, textmessage.GetBuffer());
	}
}