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

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.

********************************************************************/
// WBXML2XMLConv.cpp : implementation file
//

#include "stdafx.h"
#include "scts3devman.h"
#include "WBXML2XMLConv.h"

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


/* Implementation of conversion logic */
static Ret_t convHandleAddCmd(InstanceID_t id,VoidPtr_t param,SmlAddPtr_t pContent)
{
	return smlAddCmd(*((InstanceID_t *)param),pContent);
}

static Ret_t convHandleAlertCmd(InstanceID_t id,VoidPtr_t param,SmlAlertPtr_t pContent)
{
	return smlAlertCmd(*((InstanceID_t *)param),pContent);
}

static Ret_t convHandleCopyCmd(InstanceID_t id,VoidPtr_t param,SmlCopyPtr_t pContent)
{
	return smlCopyCmd(*((InstanceID_t *)param),pContent);
}

static Ret_t convHandleDeleteCmd(InstanceID_t id,VoidPtr_t param,SmlDeletePtr_t pContent)
{
	return smlDeleteCmd(*((InstanceID_t *)param),pContent);
}

static Ret_t convHandleExecCmd(InstanceID_t id,VoidPtr_t param,SmlExecPtr_t pContent)
{
	return smlExecCmd(*((InstanceID_t *)param),pContent);
}

static Ret_t convHandleGetCmd(InstanceID_t id,VoidPtr_t param,SmlGetPtr_t pContent)
{
	return smlGetCmd(*((InstanceID_t *)param),pContent);
}

static Ret_t convHandlePutCmd(InstanceID_t id,VoidPtr_t param,SmlPutPtr_t pContent)
{
	return smlPutCmd(*((InstanceID_t *)param),pContent);
}

static Ret_t convHandleMapCmd(InstanceID_t id,VoidPtr_t param,SmlMapPtr_t pContent)
{
	return smlMapCmd(*((InstanceID_t *)param),pContent);
}

static Ret_t convHandleResultsCmd(InstanceID_t id,VoidPtr_t param,SmlResultsPtr_t pContent)
{
	return smlResultsCmd(*((InstanceID_t *)param),pContent);
}

static Ret_t convHandleSearchCmd(InstanceID_t id,VoidPtr_t param,SmlSearchPtr_t pContent)
{
	return smlSearchCmd(*((InstanceID_t *)param),pContent);
}

static Ret_t convHandleStatusCmd(InstanceID_t id,VoidPtr_t param,SmlStatusPtr_t pContent)
{
	return smlStatusCmd(*((InstanceID_t *)param),pContent);
}

static Ret_t convHandleReplaceCmd(InstanceID_t id,VoidPtr_t param,SmlReplacePtr_t pContent)
{
	return smlReplaceCmd(*((InstanceID_t *)param),pContent);
}

static Ret_t convHandleStartMessage(InstanceID_t id,VoidPtr_t param,SmlSyncHdrPtr_t pContent)
{
	return smlStartMessage(*((InstanceID_t *)param),pContent);
}

static Ret_t convHandleEndMessage(InstanceID_t id,VoidPtr_t param,Boolean_t final)
{
	return smlEndMessage(*((InstanceID_t *)param),final);
}

static Ret_t convHandleStartSync(InstanceID_t id,VoidPtr_t param,SmlSyncPtr_t pContent)
{
	return smlStartSync(*((InstanceID_t *)param),pContent);
}

static Ret_t convHandleEndSync(InstanceID_t id,VoidPtr_t param)
{
	return smlEndSync(*((InstanceID_t *)param));
}

static Ret_t convHandleStartAtomic(InstanceID_t id,VoidPtr_t param,SmlAtomicPtr_t pContent)
{
	return smlStartAtomic(*((InstanceID_t *)param),pContent);
}

static Ret_t convHandleEndAtomic (InstanceID_t id,VoidPtr_t param)
{
	return smlEndAtomic(*((InstanceID_t *)param));
}

static Ret_t convHandleStartSequence(InstanceID_t id,VoidPtr_t param,SmlSequencePtr_t pContent)
{
	return smlStartSequence(*((InstanceID_t *)param),pContent);
}

static Ret_t convHandleEndSequence (InstanceID_t id,VoidPtr_t param)
{
	return smlEndSequence(*((InstanceID_t *)param));
}

static DWORD CALLBACK EditStreamCallBack(DWORD dwCookie, LPBYTE pbBuff, LONG cb, 
					LONG *pcb)
{
	char **data=(char **)dwCookie;
	if( strlen(*data) < cb )
	{
		*pcb = strlen(*data);
		memcpy(pbBuff, *data, *pcb );
	}
	else
	{
		*pcb = cb;
		memcpy(pbBuff, *data, *pcb );
		*data+=*pcb;
	}
	return 0;
}

/* Ref#0026 : Remember the last directory used */
CString CWBXML2XMLConv::lastDir="";

void CWBXML2XMLConv::Convert()
{
	InstanceID_t xmlInstance;						
	InstanceID_t wbxmlInstance;
	MemPtr_t startPtr;
	MemSize_t freeBytes;
	MemSize_t size=0;
	MemSize_t oldsize=0;
	Ret_t rc;
	int cnt=0;
	int dataSize=0;
	char *data=0;
	char buffer[200];
	FILE *fp;
	SmlInstanceOptions_t options;
	SmlCallbacks_t callbackFunctions =
	{
		convHandleStartMessage,
		convHandleEndMessage,
		convHandleStartSync,
		convHandleEndSync,
		convHandleStartSequence,
		convHandleEndSequence,
		convHandleStartAtomic,
		convHandleEndAtomic,
		convHandleAddCmd,
		convHandleAlertCmd,
		convHandleDeleteCmd,
		convHandleGetCmd,
		convHandlePutCmd,
		convHandleMapCmd,
		convHandleResultsCmd,
		convHandleStatusCmd,
		convHandleReplaceCmd,
		convHandleCopyCmd,
		convHandleExecCmd,
		convHandleSearchCmd,
		0,
		0
	};	
	CFileDialog fDlg(TRUE,"cfg",NULL,OFN_HIDEREADONLY | OFN_FILEMUSTEXIST,"WBXML Files (*.*)|*.*||");
 	fDlg.m_ofn.lpstrTitle="Load File";
	/* Ref#0026 : Remember the last dir used */
	if (!lastDir.IsEmpty()) fDlg.m_ofn.lpstrInitialDir=(LPCTSTR)lastDir;
	if (fDlg.DoModal()==IDCANCEL) 
	{
		SetCurrentDirectory(logPath);
		return;
	}
	/* Ref#0026 : Remember the last file used */
	GetCurrentDirectory(200,buffer);
	lastDir=buffer;
	SetCurrentDirectory(logPath);
	if (!(fp=fopen(fDlg.m_ofn.lpstrFile,"rb"))) 
	{
		mainPane->MessageBox("File doesn't exist.","Error",MB_ICONSTOP);
		return;
	}
	fclose(fp);
	
	while (true)
	{
		/* Initialize the SyncML instance */
		ltoa((long)time(0),buffer,16);
		options.workspaceSize=MAX_WORKSPACE_SIZE;
		options.workspaceName=buffer;
		options.encoding= SML_XML;
		if ((rc=smlInitInstance(&callbackFunctions,&options,0,&xmlInstance)))
		{
			rc=1;
			break;
		}

		/* Initialize the SyncML instance */
		strcat(buffer,"wb");
		options.encoding= SML_WBXML;
		if ((rc=smlInitInstance(&callbackFunctions,&options,&xmlInstance,&wbxmlInstance)))
		{
			rc=1;
			break;
		}
		
		if ((rc=smlLockWriteBuffer(wbxmlInstance,&startPtr,&freeBytes))) 
		{
			rc=1;
			break;
		}
		if (!(fp=fopen(fDlg.m_ofn.lpstrFile,"rb"))) return;
		fseek(fp,oldsize,0);
		while ((startPtr[0]=fgetc(fp))!=2 && !feof(fp)) 
			++oldsize;
		if (startPtr[0]!=2) 
		{
			fclose(fp);
			if (!cnt) 
				rc=1;
			else
				rc=0;
			break;
		}
		++cnt;
		size=fread(startPtr+1,1,freeBytes-1,fp)+1;
		fclose(fp);
		if ((rc=smlUnlockWriteBuffer(wbxmlInstance,size))) 
		{
			rc=1;
			break;
		}

		if ((rc=smlProcessData(wbxmlInstance,SML_ALL_COMMANDS)))
		{
			rc=1;
			break;
		}
		
		if ((rc=smlLockReadBuffer(wbxmlInstance, &startPtr, &freeBytes))) 
		{
			rc=1;
			break;
		}

		oldsize+=size-freeBytes;

		if ((rc=smlUnlockReadBuffer(wbxmlInstance, 0)))
		{
			rc=1;
			break;
		}
		
		if ((rc=smlLockReadBuffer(xmlInstance, &startPtr, &size))) 
		{
			rc=1;
			break;
		}
		if (!(data=(char *)realloc(data,dataSize+size+1)))
		{
			rc=1;
			break;
		}
		memcpy(data+dataSize,startPtr,size);
		dataSize+=size;
		data[dataSize]=0;

		if ((rc=smlUnlockReadBuffer(xmlInstance, size)))
		{
			rc=1;
			break;
		}
		smlTerminateInstance(xmlInstance);
		smlTerminateInstance(wbxmlInstance);
	}
	smlTerminateInstance(xmlInstance);
	smlTerminateInstance(wbxmlInstance);
	if (rc)
	{
		if (data) free(data);
		mainPane->MessageBox("Error while trying to convert WBXML to XML.","Error",MB_ICONSTOP);
		return;
	}
	CWBXML2XMLConv *wbxml2xmlConv=new CWBXML2XMLConv(data);
	wbxml2xmlConv->Create(IDD_WBXML2XML);
	wbxml2xmlConv->GetWindowText(buffer,100);
	sprintf(buffer+strlen(buffer)," [%s]",fDlg.m_ofn.lpstrFile);
	wbxml2xmlConv->SetWindowText(buffer);
	wbxml2xmlConv->m_xmlCtrl.SetSel(0,0);
}



/////////////////////////////////////////////////////////////////////////////
// CWBXML2XMLConv dialog


CWBXML2XMLConv::CWBXML2XMLConv(char *_data,CWnd* pParent /*=NULL*/)
	: CDialog(CWBXML2XMLConv::IDD, pParent),data(_data)
{
	//{{AFX_DATA_INIT(CWBXML2XMLConv)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
}


void CWBXML2XMLConv::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CWBXML2XMLConv)
	DDX_Control(pDX, IDC_RICHEDIT, m_xmlCtrl);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CWBXML2XMLConv, CDialog)
	//{{AFX_MSG_MAP(CWBXML2XMLConv)
	ON_WM_SIZE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CWBXML2XMLConv message handlers

BOOL CWBXML2XMLConv::OnInitDialog() 
{
	CDialog::OnInitDialog();
	CString indent="";
	long flen;
	int indentLevel=0;
	int len=0;
	int cnt=0;
	char *pos1;
	char *pos2;
	char filename[50];
	BOOL isTag=FALSE;
	FILE *fp;
	SetIcon((HICON)LoadIcon(AfxGetResourceHandle(),MAKEINTRESOURCE(IDI_WBXML)),false);
	sprintf(filename,"w2x%ld.dat",GetCurrentThreadId());
	fp=fopen(filename,"w+b");
	SCTSASSERT(fp);

	RECT rect;
	GetClientRect(&rect);
	m_xmlCtrl.MoveWindow(&rect);

	pos1=pos2=data;

	/* Format XML */
	fprintf(fp,"{\\rtf1\\ansi\\deff0\\deftab720{\\fonttbl{\\f0\\fswiss "
		"Arial;}}\n{\\colortbl\\red0\\green0\\blue0;\\red255\\green255\\blue255;"
		"\\red0\\green0\\blue255;\\red160\\green64\\blue0;\\red180\\green180\\blue180;}\\fs20");
	while(pos1[(len=strcspn(pos1,"<\n\\"))])
	{
	  	if (pos1[len]=='\\')
		{
			fwrite(pos1,1,len,fp);
			fwrite("\\\\",1,2,fp);
			pos1+=len+1;
			continue;
		}
		indent="";
		for (cnt=indentLevel;cnt;cnt--)
			indent+="    ";
		if (pos1[len]=='\n')
		{
			if (!isTag) 
			{
				fwrite("\\par",1,4,fp);
				fwrite((LPCTSTR)indent,1,indent.GetLength(),fp);
				fwrite("    ",1,4,fp);
			}
			fwrite(pos1,1,len,fp);
			fwrite("\\par",1,4,fp);
			fwrite((LPCTSTR)indent,1,indent.GetLength(),fp);
			fwrite("    ",1,4,fp);
			pos1+=len+1;
			isTag=TRUE;
			continue;
		}
		if (pos1[len]=='<')
		{
			fwrite(pos1,1,len,fp);
			pos1+=len;
			/* Handle CDATA section */
			if (!strncmp(pos1+1,"![CDATA[",8))
			{
				char *pos3;
				fwrite("\\par",1,4,fp);
				fwrite((LPCTSTR)indent,1,indent.GetLength(),fp);
				fwrite("\\b0\\cf2<![CDATA[\\cf0",1,20,fp);
				pos2=pos1+len+9;
				pos1=strstr(pos2,"]]>");
				pos1[0]='\n';
				pos1[1]=0;
				pos1+=3;
				while ((pos3=strchr(pos2,'\n')))
				{
					fwrite("\\par",1,4,fp);
					fwrite((LPCTSTR)indent,1,indent.GetLength(),fp);
					fwrite(pos2,1,pos3-pos2,fp);
					pos2=pos3+1;
				}
				fwrite("\\cf2]]>\\cf0",1,11,fp);
				continue;
			}
			*pos1='<';
			pos2=strchr(pos1,'>');
			if(*(pos2-1)=='/' || *(pos2-1)=='?' || *(pos1+1)=='!')
			{
				indentLevel--;
			}
			if (isTag)
			{
				fwrite("\\par",1,4,fp);
				fwrite((LPCTSTR)indent,1,indent.GetLength(),fp);
			}
			if (pos1[1]=='/' && indentLevel)
				indentLevel--;
			else
			{
				indentLevel++;
				fwrite("    ",1,4,fp);
			}
			fwrite("\\b0\\cf2<",1,8,fp);
			if (*(pos1+1)=='!')
				fwrite("\\cf4",1,4,fp);
			else if (*(pos2-1)!='?')
				fwrite("\\cf3",1,4,fp);
			fwrite(pos1+1,1,pos2-pos1-1,fp);
			fwrite("\\cf2>\\cf0\\b ",1,12,fp);
			pos1=pos2+1;
			isTag=(*pos1=='<');
			indent="";
		}
	}
	fprintf(fp,"\n\\par }");
	fclose(fp);
	free(data);
	fp=fopen(filename,"rb");
	fseek(fp,0,SEEK_END);
	flen=ftell(fp);
	fseek(fp,0,SEEK_SET);
	data=(char *)malloc(flen+1);
	data[flen]=0;
	fread(data,1,flen,fp);
	fclose(fp);
	remove(filename);
	m_xmlCtrl.LimitText(flen);
	/* Ref#0026 : RTF data must be streamed in for Win NT */
	char *streamData=data;
	EDITSTREAM es = {(DWORD)&streamData, 0, EditStreamCallBack};
	m_xmlCtrl.SetTargetDevice(NULL,0);
	m_xmlCtrl.StreamIn(SF_RTF | SFF_SELECTION, es);
	free(data);
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CWBXML2XMLConv::OnSize(UINT nType, int cx, int cy) 
{
	CDialog::OnSize(nType, cx, cy);
	if (m_xmlCtrl.m_hWnd)
	{
		RECT rect;
		GetClientRect(&rect);
		m_xmlCtrl.MoveWindow(&rect);
		m_xmlCtrl.RedrawWindow();
	}
}
