/*******************************************************************

Copyright (c) 2004 Open Mobile Alliance, Ltd.  All Rights Reserved.

This software is made available under the usage and distribution terms 
covered by the Common Public License 1.0 and by using this software you
are bound by the terms and conditions of the same.

EXCEPT AS EXPRESSLY SET FORTH IN THE COMMON PUBLIC LICENSE,
THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, 
ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
   
Each recipient is solely responsible for determining the 
appropriateness of using and distributing this program and assumes 
all risks associated with its exercise of rights under the Common 
Public License, including but not limited to the risks and 
costs of program errors, compliance with applicable laws, 
damage to or loss of data, programs or equipment, and 
unavailability or interruption of operations.

********************************************************************/

// CommandsPane.cpp : implementation file
//

#include "stdafx.h"
#include "scts3devman.h"
#include "CommandsPane.h"
#include "UIAPane.h"

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

/////////////////////////////////////////////////////////////////////////////
// CCommandsPane dialog


CCommandsPane::CCommandsPane(SctsDMServerTree *_tree,CWnd* pParent /*=NULL*/)
	: CDialog(CCommandsPane::IDD, pParent), tree(_tree)
{
	//{{AFX_DATA_INIT(CCommandsPane)
	//}}AFX_DATA_INIT
	firstSel=0;
	lastSel=0;
}


void CCommandsPane::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CCommandsPane)
	DDX_Control(pDX, IDC_COMMANDS, m_commands);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CCommandsPane, CDialog)
	//{{AFX_MSG_MAP(CCommandsPane)
	ON_NOTIFY(TVN_SELCHANGED, IDC_COMMANDS, OnSelchangedCommands)
	ON_BN_CLICKED(IDC_CMDATOMIC, OnCmdatomic)
	ON_BN_CLICKED(IDC_CMDSEQUENCE, OnCmdsequence)
	ON_BN_CLICKED(IDC_CMDDELETE, OnCmddelete)
	ON_NOTIFY(TVN_SELCHANGING, IDC_COMMANDS, OnSelchangingCommands)
	ON_COMMAND(ID_COMMANDS_INSERTATOMIC, OnCmdatomic)
	ON_COMMAND(ID_COMMANDS_INSERTSEQUENCE, OnCmdsequence)
	ON_COMMAND(ID_COMMANDS_DELETECOMMAND, OnCmddelete)
	ON_COMMAND(ID_COMMANDS_UIAAFTER, OnCommandsUiaafter)
	ON_COMMAND(ID_COMMANDS_UIABEFORE, OnCommandsUiabefore)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCommandsPane message handlers

BOOL CCommandsPane::OnInitDialog() 
{
	CDialog::OnInitDialog();
	/* Load image list */
	imgList.Create(16,16,ILC_MASK | ILC_COLOR8,7,0);
	imgList.Add(LoadIcon(AfxGetResourceHandle(),MAKEINTRESOURCE(IDI_CMD)));
	imgList.Add(LoadIcon(AfxGetResourceHandle(),MAKEINTRESOURCE(IDI_CMDADD)));
	imgList.Add(LoadIcon(AfxGetResourceHandle(),MAKEINTRESOURCE(IDI_CMDDELETE)));
	imgList.Add(LoadIcon(AfxGetResourceHandle(),MAKEINTRESOURCE(IDI_CMDREPLACE)));
	imgList.Add(LoadIcon(AfxGetResourceHandle(),MAKEINTRESOURCE(IDI_CMDGET)));
	imgList.Add(LoadIcon(AfxGetResourceHandle(),MAKEINTRESOURCE(IDI_UIADISPLAY)));
	imgList.Add(LoadIcon(AfxGetResourceHandle(),MAKEINTRESOURCE(IDI_UIACONFIRMATION)));
	imgList.Add(LoadIcon(AfxGetResourceHandle(),MAKEINTRESOURCE(IDI_CMDEXEC)));
	imgList.Add(LoadIcon(AfxGetResourceHandle(),MAKEINTRESOURCE(IDI_CMDCOPY)));
	
	m_commands.SetImageList(&imgList,TVSIL_NORMAL);

	Refresh();
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CCommandsPane::Refresh()
{
	int img;
	char *name;
	std::list <SctsDMCommand *>::iterator it;
	SctsDMCommand *command;
	HTREEITEM parent=TVI_ROOT,child;
	m_commands.DeleteAllItems();
	for (it=tree->cmdList.begin();it!=tree->cmdList.end();++it)
	{
		command=*it;
		img=0;
		if (command->command==SCTS_ALERT)
		{
			img=(int)((char **)command->data)[0]==1100?5:6;
			name=sctsStrdup(((char **)command->data)[2]);
			if (sctsStrlen(name) > 20) sctsStrcpy(name+17,"...");
			child=m_commands.InsertItem(name,img,img,parent);
			m_commands.SetItemData(child,(DWORD)command);
			sctsFree(name);
			continue;
		}
		switch (command->command)
		{
		case SCTS_ATOMIC_START:
		case SCTS_SEQUENCE_START:
			parent=m_commands.InsertItem(sctsCommandStrings[command->command],0,0,parent);
			m_commands.SetItemData(parent,(DWORD)command);
			break;
		case SCTS_ATOMIC_END:
		case SCTS_SEQUENCE_END:
			parent=m_commands.GetParentItem(parent);
			break;
		case SCTS_ADD:
			img=1;
			break;
		case SCTS_DELETE:
			img=2;
			break;
		case SCTS_REPLACE:
			img=3;
			break;
		case SCTS_GET:
			img=4;
			break;
        /*
         * Change to support Exec/Copy
         */
		case SCTS_EXEC:
			img=7;
			break;
		case SCTS_COPY:
			img=8;
			break;
		}
		if (img && command->nodeRef && !command->cmdRef)
		{
			name=tree->GetPath(command->nodeRef);
			child=m_commands.InsertItem(name,img,img,parent);
			m_commands.SetItemData(child,(DWORD)command);
			sctsFree(name);
		}
	}
	GetDlgItem(IDC_CMDATOMIC)->EnableWindow(FALSE);
	GetDlgItem(IDC_CMDSEQUENCE)->EnableWindow(FALSE);
	GetDlgItem(IDC_CMDDELETE)->EnableWindow(FALSE);
	m_commands.SelectItem(0);
}

void CCommandsPane::OnSelchangedCommands(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	HTREEITEM item;
	HTREEITEM endItem=0;
	*pResult = 0;
	UINT state=0;
	SctsCommandType commandType=((SctsDMCommand *)pNMTreeView->itemNew.lParam)->command;
	bool flag=GetKeyState(VK_LSHIFT)&0x8000 || GetKeyState(VK_RSHIFT)&0x8000;
	GetDlgItem(IDC_CMDATOMIC)->EnableWindow(commandType!=SCTS_ATOMIC_START && commandType!=SCTS_GET && commandType!=SCTS_SEQUENCE_START);
	GetDlgItem(IDC_CMDSEQUENCE)->EnableWindow(TRUE);
	for (item=m_commands.GetParentItem(pNMTreeView->itemNew.hItem);item;item=m_commands.GetParentItem(item))
	{
		if (((SctsDMCommand *)m_commands.GetItemData(item))->command==SCTS_ATOMIC_START)
		{
			GetDlgItem(IDC_CMDATOMIC)->EnableWindow(FALSE);
			GetDlgItem(IDC_CMDSEQUENCE)->EnableWindow(FALSE);
			break;
		}
	}
	if (firstSel)
	{
		/* Clear all selected if the parent has changed */
		item=m_commands.GetParentItem(firstSel);
		if (m_commands.GetParentItem(pNMTreeView->itemNew.hItem)!=item || !flag)
		{
			for (item=m_commands.GetChildItem(item);item;item=m_commands.GetNextSiblingItem(item)) m_commands.SetItemState(item,0,TVIS_SELECTED);
			firstSel=lastSel=pNMTreeView->itemNew.hItem;
			m_commands.SetItemState(firstSel,TVIS_SELECTED,TVIS_SELECTED);
		}
		else
		{
			m_commands.SetFocus();
			lastSel=pNMTreeView->itemNew.hItem;
			/* Select all items in range */
			for (item=m_commands.GetChildItem(item);item;item=m_commands.GetNextSiblingItem(item))
			{
				if (state==0 && (item==lastSel || item==firstSel))
				{
					if (item==lastSel)
						endItem=firstSel;
					else
						endItem=lastSel;
					state=TVIS_SELECTED;
				}
				if (m_commands.GetItemState(item,TVIS_SELECTED)!=state) m_commands.SetItemState(item,state,TVIS_SELECTED);
				commandType=((SctsDMCommand *)m_commands.GetItemData(item))->command;
				if (state==TVIS_SELECTED && (commandType==SCTS_ATOMIC_START || commandType==SCTS_GET || commandType==SCTS_SEQUENCE_START)) GetDlgItem(IDC_CMDATOMIC)->EnableWindow(FALSE);
				if (item==endItem) state=0;
			}
		}
	}
	else
		lastSel=firstSel=pNMTreeView->itemNew.hItem;

}

void CCommandsPane::OnCmdsequence() 
{
	InsertContainer(SCTS_SEQUENCE_START);	
}

void CCommandsPane::OnCmdatomic() 
{
	InsertContainer(SCTS_ATOMIC_START);
}

void CCommandsPane::InsertContainer(SctsCommandType commandType)
{
	SctsDMCommand *command;
	std::list <SctsDMCommand *>::iterator it;
	HTREEITEM item=m_commands.GetChildItem(m_commands.GetParentItem(firstSel));
	for (;item && item!=lastSel && item!=firstSel;item=m_commands.GetNextSiblingItem(item));
	SCTSASSERT(item);
	/* Find the first command and insert the start container infront of it */
	command=(SctsDMCommand *)m_commands.GetItemData(item);
	for (it=tree->cmdList.begin();it!=tree->cmdList.end() && *it!=command;++it);
	SCTSASSERT(it!=tree->cmdList.end());
	tree->cmdList.insert(it,new SctsDMCommand(commandType));
	/* Find the last command and insert the end container after it */
	command=(SctsDMCommand *)m_commands.GetItemData((item==firstSel)?lastSel:firstSel);
	for (;it!=tree->cmdList.end() && *it!=command;++it);
	/* Find the closing container if it is an opening container */
	if (command->command==SCTS_ATOMIC_START || command->command==SCTS_SEQUENCE_START)
	{
		int i=1;
		SctsCommandType commandType;
		SCTSASSERT(it!=tree->cmdList.end());
		for (++it;it!=tree->cmdList.end();++it)
		{
			commandType=(*it)->command;
			if (commandType==SCTS_ATOMIC_START || commandType==SCTS_SEQUENCE_START) ++i;
			if (commandType==SCTS_ATOMIC_END || commandType==SCTS_SEQUENCE_END) --i;
			if (!i) break;
		}
	}
	SCTSASSERT(it!=tree->cmdList.end());
	tree->cmdList.insert(++it,new SctsDMCommand((SctsCommandType)(commandType+1)));
	/* Refresh the tree */
	Refresh();
}

void CCommandsPane::OnCmddelete() 
{
	SctsDMCommand *command;
	std::list <SctsDMCommand *>::iterator firstIt,lastIt;
	int i=0;
	bool markerFound=false;
	HTREEITEM item=m_commands.GetChildItem(m_commands.GetParentItem(firstSel));
	for (;item && item!=lastSel && item!=firstSel;item=m_commands.GetNextSiblingItem(item));
	SCTSASSERT(item);
	/* Find the first command */
	command=(SctsDMCommand *)m_commands.GetItemData(item);
	for (firstIt=tree->cmdList.begin();firstIt!=tree->cmdList.end() && *firstIt!=command;++firstIt);
	SCTSASSERT(firstIt!=tree->cmdList.end());
	/* Find the last command and insert a marker after it */
	command=(SctsDMCommand *)m_commands.GetItemData((item==firstSel)?lastSel:firstSel);
	for (lastIt=firstIt;lastIt!=tree->cmdList.end() && *lastIt!=command;++lastIt);
	SCTSASSERT(lastIt!=tree->cmdList.end());
	tree->cmdList.insert(++lastIt,new SctsDMCommand(SCTS_COMMAND_COUNT,0));
	/* Rollback all commands */
	while (firstIt!=tree->cmdList.end())
	{
		command=*firstIt;
		if (command->command==SCTS_COMMAND_COUNT)
		{
			markerFound=true;
			/* Delete the marker */
			delete command;
			firstIt=tree->cmdList.erase(firstIt);
			continue;
		}
		/* Break out of loop only if the marker has been found and we're not in a container */
		if (markerFound && !i) break;
		switch (command->command)
		{
		case SCTS_ATOMIC_START:
		case SCTS_SEQUENCE_START:
			++i;
			if (i==1)
			{
				delete *firstIt;
				firstIt=tree->cmdList.erase(firstIt);
				continue;
			}
			break;
		case SCTS_ATOMIC_END:
		case SCTS_SEQUENCE_END:
			--i;
			break;
		case SCTS_ADD:
			if (!i) 
			{
				if (tree->uiCallback) (*tree->uiCallback)(tree,command->nodeRef,SCTS_DELETE);
				command->RollBack(tree->cmdList,firstIt);
			}
			break;
		case SCTS_COPY:
			if (!i) 
			{
				if (tree->uiCallback) (*tree->uiCallback)(tree,command->nodeRef,SCTS_DELETE);
				command->RollBack(tree->cmdList,firstIt);
			}
			break;
		case SCTS_DELETE:
			if (!i)
			{
				command->RollBack();
				if (tree->uiCallback) (*tree->uiCallback)(tree,command->nodeRef,SCTS_ADD);
			}
			break;
		case SCTS_ALERT:
			break;
		default:
			if (!i)	command->RollBack();
		}
		if (i) 
			++firstIt;
		else
		{
			delete *firstIt;
			firstIt=tree->cmdList.erase(firstIt);
		}
	}
	/* Refresh the tree */
	Refresh();
}


void CCommandsPane::OnSelchangingCommands(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	BOOL enable=FALSE;
	if (pNMTreeView->itemNew.hItem) enable=TRUE;
	GetDlgItem(IDC_CMDATOMIC)->EnableWindow(enable);
	GetDlgItem(IDC_CMDSEQUENCE)->EnableWindow(enable);
	GetDlgItem(IDC_CMDDELETE)->EnableWindow(enable);
	*pResult = 0;
}

BOOL CCommandsPane::PreTranslateMessage(MSG* pMsg) 
{
	/* Disable ESC  and Enter */
	if (pMsg->message==WM_KEYDOWN && (pMsg->wParam==VK_ESCAPE || pMsg->wParam==VK_RETURN)) return TRUE;
	if (pMsg->message==WM_RBUTTONDOWN && pMsg->hwnd==m_commands.m_hWnd && firstSel && lastSel)
	{
		/* Load menu */
		CMenu menu;
		VERIFY(menu.LoadMenu(IDR_MENUS));
		CMenu *commandsMenu=menu.GetSubMenu(1);
		ASSERT(commandsMenu != NULL);
		HTREEITEM item;
		POINT point={pMsg->lParam&0xFFFF, pMsg->lParam>>16};
		if ((item=m_commands.HitTest(point)))
		{
			m_commands.ClientToScreen(&point);
			if (m_commands.GetItemState(item,LVIS_SELECTED)!=LVIS_SELECTED) m_commands.SelectItem(item);
			commandsMenu->EnableMenuItem(ID_COMMANDS_INSERTATOMIC,GetDlgItem(IDC_CMDATOMIC)->IsWindowEnabled()?MF_ENABLED:MF_GRAYED);
			commandsMenu->EnableMenuItem(ID_COMMANDS_INSERTSEQUENCE,GetDlgItem(IDC_CMDSEQUENCE)->IsWindowEnabled()?MF_ENABLED:MF_GRAYED);
			commandsMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,point.x,point.y , this);
			return TRUE;
		}
	}
	
	return CDialog::PreTranslateMessage(pMsg);
}


void CCommandsPane::InsertUIA(bool after)
{
	SctsDMCommand *command;
	SctsDMCommand *uiaCommand;
	std::list <SctsDMCommand *>::iterator it;
	/* Display the UIA pane */
	CUIAPane uiaPane(&uiaCommand);
	uiaPane.DoModal();
	if (!uiaCommand) return;
	HTREEITEM item=m_commands.GetChildItem(m_commands.GetParentItem(firstSel));
	for (;item && item!=lastSel && item!=firstSel;item=m_commands.GetNextSiblingItem(item));
	SCTSASSERT(item);
	if (after)
	{
		/* Find the last command and insert the end container after it */
		command=(SctsDMCommand *)m_commands.GetItemData((item==firstSel)?lastSel:firstSel);
		for (it=tree->cmdList.begin();it!=tree->cmdList.end() && *it!=command;++it);
		/* Find the closing container if it is an opening container */
		if (command->command==SCTS_ATOMIC_START || command->command==SCTS_SEQUENCE_START)
		{
			int i=1;
			SctsCommandType commandType;
			SCTSASSERT(it!=tree->cmdList.end());
			for (++it;it!=tree->cmdList.end();++it)
			{
				commandType=(*it)->command;
				if (commandType==SCTS_ATOMIC_START || commandType==SCTS_SEQUENCE_START) ++i;
				if (commandType==SCTS_ATOMIC_END || commandType==SCTS_SEQUENCE_END) --i;
				if (!i) break;
			}
		}
		SCTSASSERT(it!=tree->cmdList.end());
		tree->cmdList.insert(++it,uiaCommand);
	}
	else
	{
		/* Find the first command and insert the start container infront of it */
		command=(SctsDMCommand *)m_commands.GetItemData(item);
		for (it=tree->cmdList.begin();it!=tree->cmdList.end() && *it!=command;++it);
		SCTSASSERT(it!=tree->cmdList.end());
		tree->cmdList.insert(it,uiaCommand);
		/* Refresh the tree */
	}
	Refresh();
}

void CCommandsPane::OnCommandsUiaafter() 
{
	InsertUIA(true);
}

void CCommandsPane::OnCommandsUiabefore() 
{
	InsertUIA(false);	
}
