#define		STRICT
#define		INITGUID
#include	<windows.h>
#include	<commctrl.h>
#include	<coguid.h>
#include	"aygshell.h"
#include	"sip.h"
#include	"resource.h"
#include	"controls.h"
#include	"main.h"
#include	"pobox.h"
#include	"dialog.h"

extern "C" {
	extern	DWORD	g_dwWidth ;
	extern	DWORD	g_dwHeight ;
} ;

BOOL		GetReg() ;
void		SetReg() ;

LONG		g_cServerLocks = 0 ;
RECT		g_rcRect ;

// {FE872260-0596-11d2-94D1-006097A8699E}
extern "C" const IID CLSID_CPOBoxIm = {
	0xfe872260, 0x0596, 0x11d2, { 0x94, 0xd1, 0x00, 0x60, 0x97, 0xa8, 0x69, 0x9e },
} ;
// {42429666-ae04-11d0-a4f8-00aa00a749b9}
extern "C" const IID IID_IInputMethod = {
	0x42429666, 0xae04, 0x11d0, { 0xa4, 0xf8, 0x00, 0xaa, 0x00, 0xa7, 0x49, 0xb9 },
} ;

CPOBoxIm::CPOBoxIm() : m_cRef(1), m_bInit(FALSE)
{
	HBITMAP		hbmp ;

	m_hwndCtrl = 0 ;
	m_imlNarrow = ImageList_Create( 16, 16, ILC_COLOR|ILC_MASK, 2, 2 ) ;
	hbmp = LoadBitmap( g_hInst, MAKEINTRESOURCE(IDB_BITMAP_NARROW) ) ;
	ImageList_AddMasked( m_imlNarrow, hbmp, RGB(128,128,128) ) ;
	DeleteObject( hbmp ) ;
	m_imlWide   = ImageList_Create( 32, 16, ILC_COLOR|ILC_MASK, 2, 2 ) ;
	hbmp = LoadBitmap( g_hInst, MAKEINTRESOURCE(IDB_BITMAP_WIDE) ) ;
	ImageList_AddMasked( m_imlWide, hbmp, RGB(128,128,128) ) ;
	DeleteObject( hbmp ) ;
	m_pimCallback = 0 ;
}

CPOBoxIm::~CPOBoxIm()
{
	if ( m_hwndCtrl ) {
		DestroyWindow( m_hwndCtrl ) ;
		m_hwndCtrl = 0 ;
	}
	if ( m_imlNarrow ) {
		ImageList_Destroy( m_imlNarrow ) ;
		m_imlNarrow = 0 ;
	}
	if ( m_imlWide ) {
		ImageList_Destroy( m_imlWide ) ;
		m_imlWide = 0 ;
	}
}

HRESULT
CPOBoxIm::QueryInterface( const IID& iid, void **ppv )
{
	if ( iid == IID_IUnknown ) {
		*ppv = static_cast<IInputMethod*>( this ) ;
	} else if ( iid == IID_IInputMethod ) {
		*ppv = static_cast<IInputMethod*>( this ) ;
	} else {
		*ppv = NULL ;
		return E_NOINTERFACE ;
	}
	reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
	return S_OK ;
}

ULONG
CPOBoxIm::AddRef()
{
	return InterlockedIncrement( &m_cRef ) ;
}

ULONG
CPOBoxIm::Release()
{
	if ( InterlockedDecrement( &m_cRef ) == 0 ) {
		delete this ;
		return 0 ;
	}
	return m_cRef ;
}

HRESULT
CPOBoxIm::Select( /* [in] */ HWND hwndSip )
{
	GetReg() ;
	if ( readphrases() ) {
		return MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_ITF, E_FAIL ) ;
	}
	m_hwndCtrl = CreateWindowEx( 0,
					CTRL_POBoxCtrl,
					TEXT("POBox"),
					WS_CHILD|WS_VISIBLE|WS_BORDER,
					0, 0, g_dwWidth, g_dwHeight,
					hwndSip,
					0,
					g_hInst,
					0 ) ;
	return MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_ITF, S_OK ) ;
}

HRESULT
CPOBoxIm::Deselect( void )
{
	DestroyWindow( m_hwndCtrl ) ;
	m_hwndCtrl = 0 ;
	writephrases() ;
	return MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_ITF, S_OK ) ;
}

HRESULT
CPOBoxIm::Showing( void )
{
	SendMessage( m_hwndCtrl, POBOX_SHOW, (WPARAM) TRUE, 0 ) ;
	return MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_ITF, S_OK ) ;
}

HRESULT
CPOBoxIm::Hiding( void )
{
	SendMessage( m_hwndCtrl, POBOX_SHOW, (WPARAM) FALSE, 0 ) ;
	return MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_ITF, S_OK ) ;
}

HRESULT
CPOBoxIm::GetInfo( /* [out] */ IMINFO __RPC_FAR *pimi )
{
	memset( pimi, 0, sizeof (IMINFO) ) ;
	/* Imageはここで登録されるようだ */
	pimi->cbSize = sizeof (IMINFO) ;
	pimi->hImageNarrow = m_imlNarrow ;
	pimi->hImageWide   = m_imlWide ;
	pimi->iNarrow = 0 ;
	pimi->iWide = 0 ;
	pimi->fdwFlags = 0x00000002 ;
	return MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_ITF, S_OK ) ;
}

HRESULT
CPOBoxIm::ReceiveSipInfo( /* [in] */ SIPINFO __RPC_FAR *psi )
{
	memcpy( &g_rcRect, &psi->rcSipRect, sizeof (RECT) ) ;
	return MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_ITF, S_OK ) ;
}

HRESULT
CPOBoxIm::RegisterCallback( /* [in] */ IIMCallback __RPC_FAR *lpIMCallback )
{
	m_pimCallback = lpIMCallback ;
	if ( m_hwndCtrl ) {
		SendMessage( m_hwndCtrl, POBOX_SETCALLBACK, 0, (LPARAM) m_pimCallback ) ;
	}
	IMINFO	imi, *pimi = &imi ;
	memset( pimi, 0, sizeof (IMINFO) ) ;
	pimi->cbSize = sizeof (IMINFO) ;
	pimi->hImageNarrow = m_imlNarrow ;
	pimi->hImageWide   = m_imlWide ;
	pimi->iNarrow = 0 ;
	pimi->iWide = 0 ;
	pimi->fdwFlags = 0x00000002 ;
	m_pimCallback->SetImInfo( pimi ) ;
	return MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_ITF, S_OK ) ;
}

HRESULT
CPOBoxIm::GetImData( /* [in] */ DWORD dwSize, /* [out] */ LPVOID pvImData )
{
	return MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_ITF, S_OK ) ;
}

HRESULT
CPOBoxIm::SetImData( /* [in] */ DWORD dwSize, /* [in] */ LPVOID pvImData )
{
	return MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_ITF, S_OK ) ;
}

HRESULT
CPOBoxIm::UserOptionsDlg( /* [in] */ HWND hwndParent )
{
	GetReg() ;
	if ( SetupDialogExec( g_hInst, hwndParent ) & DIALOG_RET_CHANGE ) {
		SetReg() ;
	}
	return MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_ITF, S_OK ) ;
}

class CFactory : public IClassFactory {
public:
	// IUnknown
	virtual HRESULT STDMETHODCALLTYPE QueryInterface( const IID& iid, void **ppv ) ;
	virtual ULONG STDMETHODCALLTYPE AddRef() ;
	virtual ULONG STDMETHODCALLTYPE Release() ;
	// IClassFactory
	virtual HRESULT STDMETHODCALLTYPE CreateInstance( IUnknown *pUnknownOuter, const IID& iid, void **ppv ) ;
	virtual HRESULT STDMETHODCALLTYPE LockServer( BOOL bLock ) ;

	CFactory() : m_cRef(1) {}
	~CFactory() {}

private:
	LONG	m_cRef ;
} ;

HRESULT
CFactory::QueryInterface( const IID& iid, void **ppv )
{
	if ( iid == IID_IUnknown || iid == IID_IClassFactory ) {
		*ppv = static_cast<IClassFactory*>( this ) ;
	} else {
		*ppv = NULL ;
		return E_NOINTERFACE ;
	}
	reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
	return S_OK ;
}

ULONG
CFactory::AddRef()
{
	return InterlockedIncrement( &m_cRef ) ;
}

ULONG
CFactory::Release()
{
	if ( InterlockedDecrement( &m_cRef ) == 0 ) {
		delete this ;
		return 0 ;
	}
	return m_cRef ;
}

HRESULT
CFactory::CreateInstance( IUnknown *pUnknownOuter, const IID& iid, void **ppv )
{
	if ( pUnknownOuter != NULL ) {
		return CLASS_E_NOAGGREGATION ;
	}
	CPOBoxIm	*pPOBoxIm = new CPOBoxIm ;
	if ( pPOBoxIm == NULL ) {
		return E_OUTOFMEMORY ;
	}
	HRESULT		hr = pPOBoxIm->QueryInterface( iid, ppv ) ;
	pPOBoxIm->Release() ;
	return hr ;
}

HRESULT
CFactory::LockServer( BOOL bLock )
{
	if ( bLock ) {
		InterlockedIncrement( &g_cServerLocks ) ;
	} else {
		InterlockedDecrement( &g_cServerLocks ) ;
	}
	return S_OK ;
}

STDAPI
MyCanUnloadNow()
{
	if ( g_cServerLocks == 0 ) {
		return S_OK ;
	} else {
		return S_FALSE ;
	}
}

HRESULT PASCAL
MyGetClassObject( REFCLSID clsid, REFIID iid, LPVOID *ppv )
{
	if ( clsid != CLSID_CPOBoxIm ) {
		return CLASS_E_CLASSNOTAVAILABLE ;
	}

	CFactory	*pFactory = new CFactory ;
	if ( pFactory == NULL ) {
		return E_OUTOFMEMORY ;
	}
	HRESULT		hr = pFactory->QueryInterface( iid, ppv ) ;
	pFactory->Release() ;
	return hr ;
}

#define		szTitleName		TEXT("POBox")
#define		szClassName		TEXT("KANJIIN")
#define		GawaroBaseKey	TEXT("Software\\Gawaro")
#define		VAR_BASEDIR		TEXT("BaseDir")
#define		VAR_PREWAIT		TEXT("PreWait")
#define		VAR_POSTWAIT	TEXT("PostWait")
#define		VAR_JIS			TEXT("JIS")
#define		VAR_SOFTKEY		TEXT("SoftKey")
#define		VAR_LEFTPOS		TEXT("LeftPos")
#define		VAR_SAVEDIC		TEXT("SaveDic")
#define		VAR_PREDICT		TEXT("Predict")
#define		VAR_SELCOLOR	TEXT("SelColor")

extern "C" {
	extern	TCHAR	MessageBuf[ 512 ] ;
	extern	TCHAR	g_szDictBase[ MAX_PATH ] ;
	extern	DWORD	g_dwSoftKey ;			/* 0:NONE, 1:HIRA, 2:ROMA, 3:1LINE */
	extern	BOOL	g_fSaveDic ;			/* 辞書保存フラグ */
	extern	BOOL	g_fPredict ;			/* 予測表示フラグ */
	extern	DWORD	g_dwSelColor ;
} ;

BOOL
GetReg()
{
	HKEY	hk ;
	LONG	lret ;
	LPCTSTR	name ;
	LPBYTE	lpData ;
	TCHAR	sValue[ 256 ] ;
	DWORD	dwType, cbData, dwValue = 0 ;

	wsprintf( sValue, TEXT("%s\\%s"), GawaroBaseKey, szTitleName ) ;
	/* レジストリキーをオープンする */
	lret = RegOpenKeyEx( HKEY_CURRENT_USER, sValue, 0,
						 KEY_QUERY_VALUE, &hk ) ;
	if ( lret == ERROR_SUCCESS ) {
		/* BaseDir */
		name = VAR_BASEDIR ;
		dwType = REG_SZ ;
		lpData = (LPBYTE) sValue ;
		cbData = sizeof sValue ;
		if ( RegQueryValueEx( hk, name, NULL, &dwType, lpData, &cbData ) == ERROR_SUCCESS ) {
			_tcscpy( g_szDictBase, sValue ) ;
		}
		/* ソフトキーモード */
		name = VAR_SOFTKEY ;
		dwType = REG_DWORD ;
		lpData = (LPBYTE) &dwValue ;
		cbData = sizeof dwValue ;
		if ( RegQueryValueEx( hk, name, NULL, &dwType, lpData, &cbData ) == ERROR_SUCCESS ) {
			g_dwSoftKey = dwValue ;
		}
		/* 辞書保存モード */
		name = VAR_SAVEDIC ;
		dwType = REG_DWORD ;
		lpData = (LPBYTE) &dwValue ;
		cbData = sizeof dwValue ;
		if ( RegQueryValueEx( hk, name, NULL, &dwType, lpData, &cbData ) == ERROR_SUCCESS ) {
			g_fSaveDic = dwValue ;
		}
		/* 予測表示モード */
		name = VAR_PREDICT ;
		dwType = REG_DWORD ;
		lpData = (LPBYTE) &dwValue ;
		cbData = sizeof dwValue ;
		if ( RegQueryValueEx( hk, name, NULL, &dwType, lpData, &cbData ) == ERROR_SUCCESS ) {
			g_fPredict = dwValue ;
		}
		/* SelColor */
		name = VAR_SELCOLOR ;
		dwType = REG_DWORD ;
		lpData = (LPBYTE) &dwValue ;
		cbData = sizeof dwValue ;
		if ( RegQueryValueEx( hk, name, NULL, &dwType, lpData, &cbData ) == ERROR_SUCCESS ) {
			g_dwSelColor = dwValue ;
		}
		/* レジストリクローズ */
		RegCloseKey( hk ) ;
	}
	return TRUE ;
}

void
SetReg()
{
	HKEY	hk ;
	LONG	lret ;
	LPTSTR	name ;
	LPBYTE	lpData ;
	TCHAR	sValue[ 256 ] ;
	DWORD	ret, dwType, cbData, dwValue ;

	wsprintf( sValue, TEXT("%s\\%s"), GawaroBaseKey, szTitleName ) ;
	/* レジストリキーを作成する */
	lret = RegCreateKeyEx( HKEY_CURRENT_USER, sValue, 0, TEXT(""), 0,
#ifdef	_WIN32_WCE
						   0,
#else	/* _WIN32_WCE */
						   KEY_ALL_ACCESS,
#endif	/* _WIN32_WCE */
						   NULL, &hk, &ret ) ;
	if ( lret == ERROR_SUCCESS ) {
		/* BaseDir */
		name = VAR_BASEDIR ;
		dwType = REG_SZ ;
		lpData = (LPBYTE) g_szDictBase ;
		cbData = (_tcslen(g_szDictBase) + 1) * sizeof (*g_szDictBase) ;
		lret = RegSetValueEx( hk, name, 0, dwType, lpData, cbData ) ;
		/* ソフトキーモード */
		name = VAR_SOFTKEY ;
		dwType = REG_DWORD ;
		dwValue = g_dwSoftKey ;
		lpData = (LPBYTE) &dwValue ;
		cbData = sizeof dwValue ;
		lret = RegSetValueEx( hk, name, 0, dwType, lpData, cbData ) ;
		/* 辞書保存モード */
		name = VAR_SAVEDIC ;
		dwType = REG_DWORD ;
		dwValue = g_fSaveDic ;
		lpData = (LPBYTE) &dwValue ;
		cbData = sizeof dwValue ;
		lret = RegSetValueEx( hk, name, 0, dwType, lpData, cbData ) ;
		/* 予測表示モード */
		name = VAR_PREDICT ;
		dwType = REG_DWORD ;
		dwValue = g_fPredict ;
		lpData = (LPBYTE) &dwValue ;
		cbData = sizeof dwValue ;
		lret = RegSetValueEx( hk, name, 0, dwType, lpData, cbData ) ;
		/* SelColor */
		name = VAR_SELCOLOR ;
		dwType = REG_DWORD ;
		dwValue = g_dwSelColor ;
		lpData = (LPBYTE) &dwValue ;
		cbData = sizeof dwValue ;
		RegSetValueEx( hk, name, 0, dwType, lpData, cbData ) ;
		/* レジストリクローズ */
		RegCloseKey( hk ) ;
	}
}
