// CameraDlg.cpp : 実装ファイル
//

#include "stdafx.h"
#include "Camera.h"
#include "CameraDlg.h"

#include "CAO_i.c"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CCameraDlg ダイアログ
CCameraDlg::CCameraDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CCameraDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	m_eng        = NULL;
	m_wss        = NULL;
	m_ws         = NULL;
	m_ctrl       = NULL;
	m_varCapture = NULL;
	m_varPause   = NULL;
}

void CCameraDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_BUTTON_INIT, btnInit);
	DDX_Control(pDX, IDC_BUTTON_CONNECT, btnConnect);
	DDX_Control(pDX, IDC_BUTTON_DISCONNECT, btnDisconnect);
	DDX_Control(pDX, IDC_BUTTON_CAPTUREV, btnCaptureVar);
	DDX_Control(pDX, IDC_BUTTON_CAPTUREF, btnCaptureFile);
	DDX_Control(pDX, IDC_LABEL_PAUSE, lblPauseValue);
	DDX_Control(pDX, IDC_BUTTON_READ, btnRead);
	DDX_Control(pDX, IDC_BUTTON_WRITE, btnWrite);
}

BEGIN_MESSAGE_MAP(CCameraDlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_WM_DESTROY()
	ON_BN_CLICKED(IDC_BUTTON_INIT, &CCameraDlg::OnBnClickedButtonInit)
	ON_BN_CLICKED(IDC_BUTTON_CONNECT, &CCameraDlg::OnBnClickedButtonConnect)
	ON_BN_CLICKED(IDC_BUTTON_DISCONNECT, &CCameraDlg::OnBnClickedButtonDisconnect)
	ON_BN_CLICKED(IDC_BUTTON_CAPTUREV, &CCameraDlg::OnBnClickedButtonCapturev)
	ON_BN_CLICKED(IDC_BUTTON_CAPTUREF, &CCameraDlg::OnBnClickedButtonCapturef)
	ON_BN_CLICKED(IDC_BUTTON_READ, &CCameraDlg::OnBnClickedButtonRead)
	ON_BN_CLICKED(IDC_BUTTON_WRITE, &CCameraDlg::OnBnClickedButtonWrite)
END_MESSAGE_MAP()


// CCameraDlg メッセージ ハンドラ

BOOL CCameraDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// このダイアログのアイコンを設定します。アプリケーションのメイン ウィンドウがダイアログでない場合、
	//  Framework は、この設定を自動的に行います。
	SetIcon(m_hIcon, TRUE);			// 大きいアイコンの設定
	SetIcon(m_hIcon, FALSE);		// 小さいアイコンの設定

	CoInitialize(NULL);

	return TRUE;  // フォーカスをコントロールに設定した場合を除き、TRUE を返します。
}

void CCameraDlg::OnDestroy()
{
	CDialog::OnDestroy();

	OnBnClickedButtonDisconnect();

	if(m_ws)
	{
		m_ws->Release();
		m_ws = NULL;
	}

	if(m_wss)
	{
		m_wss->Release();
		m_wss = NULL;
	}

	if(m_eng)
	{
		m_eng->Release();
		m_eng = NULL;
	}

	CoUninitialize();
}

// ダイアログに最小化ボタンを追加する場合、アイコンを描画するための
//  下のコードが必要です。ドキュメント/ビュー モデルを使う MFC アプリケーションの場合、
//  これは、Framework によって自動的に設定されます。

void CCameraDlg::OnPaint()
{
	CPaintDC dc(this); // 描画のデバイス コンテキスト

	if (IsIconic())
	{
		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// クライアントの四角形領域内の中央
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// アイコンの描画
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		if(m_vntImage.vt == (VT_UI1 | VT_ARRAY)) {
			CDC tmpDC, *pDC  = ((CStatic*)GetDlgItem(IDC_PICTURE_IMAGE))->GetDC();
			tmpDC.CreateCompatibleDC(pDC);

			LPBYTE lpbImage;
			SafeArrayAccessData(m_vntImage.parray, (void**)&lpbImage);

			// Bitmap File Header
			BITMAPFILEHEADER bmpFileHeader;
			memcpy(&bmpFileHeader, lpbImage, sizeof(BITMAPFILEHEADER));

			// Bitmap Information Header
			lpbImage += sizeof(BITMAPFILEHEADER);
			BITMAPINFOHEADER bmpInfoHeader;
			memcpy(&bmpInfoHeader, lpbImage, sizeof(BITMAPINFOHEADER));

			// Bitmap
			lpbImage += sizeof(BITMAPINFOHEADER);
			CBitmap bmpImage;
			bmpImage.CreateCompatibleBitmap(pDC, bmpInfoHeader.biWidth, bmpInfoHeader.biHeight);

			// 24bit -> 32bit
			LONG bmpSize = bmpInfoHeader.biWidth * bmpInfoHeader.biHeight;
			LPBYTE lpb32Color = new BYTE[4 * bmpSize];
			for(int i = 0; i < bmpInfoHeader.biHeight; i++) {
				for(int j = 0; j < bmpInfoHeader.biWidth; j++) {
					LONG posPix = i * bmpInfoHeader.biWidth + j;
					LONG negPix = (bmpInfoHeader.biHeight - i - 1) * bmpInfoHeader.biWidth + j;
					lpb32Color[4*negPix+0] = lpbImage[3*posPix+0]; // B
					lpb32Color[4*negPix+1] = lpbImage[3*posPix+1]; // G
					lpb32Color[4*negPix+2] = lpbImage[3*posPix+2]; // R
					lpb32Color[4*negPix+3] = 0x00; // Alpha
				}
			}

			// Draw image
			bmpImage.SetBitmapBits(4 * bmpSize, lpb32Color);
			tmpDC.SelectObject(bmpImage);
			pDC->BitBlt(0, 0, bmpInfoHeader.biWidth, bmpInfoHeader.biHeight, &tmpDC, 0, 0, SRCCOPY);

			delete [] lpb32Color;
			bmpImage.DeleteObject();

			SafeArrayUnaccessData(m_vntImage.parray);

			DeleteDC(tmpDC);
			((CStatic*)GetDlgItem(IDC_PICTURE_IMAGE))->ReleaseDC(pDC);
		}

		CDialog::OnPaint();
	}
}

// ユーザーが最小化したウィンドウをドラッグしているときに表示するカーソルを取得するために、
//  システムがこの関数を呼び出します。
HCURSOR CCameraDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void CCameraDlg::OnBnClickedButtonInit()
{
	// Create CAO Engine
	CoCreateInstance(CLSID_CaoEngine, NULL, CLSCTX_LOCAL_SERVER, IID_ICaoEngine, (void**)&m_eng);
	m_eng->get_Workspaces(&m_wss);
	m_wss->Item(CComVariant(0L), &m_ws);

	btnInit.EnableWindow(FALSE);
	btnConnect.EnableWindow(TRUE);
}

void CCameraDlg::OnBnClickedButtonConnect()
{
	HRESULT hr = E_FAIL;

	// Connect Dummy.Camera Provider
	if(m_ws != NULL)
	{
		hr = m_ws->AddController(CComBSTR(L"Camera"), CComBSTR(L"CaoProv.Dummy.Camera"), CComBSTR(L""), CComBSTR(L""), &m_ctrl);
		
		if(SUCCEEDED(hr))
		{
			m_ctrl->AddVariable(CComBSTR(L"@Image"), CComBSTR(L""), &m_varCapture);
			m_ctrl->AddVariable(CComBSTR(L"@Pause"), CComBSTR(L""), &m_varPause);
		}
	}

	if(SUCCEEDED(hr))
	{
		// Enable command buttons
		btnConnect.EnableWindow(FALSE);
		btnDisconnect.EnableWindow(TRUE);
		btnCaptureVar.EnableWindow(TRUE);
		btnCaptureFile.EnableWindow(TRUE);
		btnRead.EnableWindow(TRUE);
		btnWrite.EnableWindow(TRUE);
	}
	else
	{
		OnBnClickedButtonDisconnect();
		ShowErrorMessage(hr);
	}
}

void CCameraDlg::OnBnClickedButtonDisconnect()
{
	if(m_varCapture){
		m_varCapture->Release();
		m_varCapture = NULL;
	}

	if(m_varPause != NULL) {
		m_varPause->Release();
		m_varPause = NULL;
	}

	// Disconnect Provider
	if(m_ctrl)
	{
		if(m_ws)
		{
			CComVariant vntCtrlName;
			CComPtr<ICaoControllers> ctrls;

			m_ws->get_Controllers(&ctrls);

			vntCtrlName.vt = VT_BSTR;
			m_ctrl->get_Name(&vntCtrlName.bstrVal);

			ctrls->Remove(vntCtrlName);
		}

		m_ctrl->Release();
		m_ctrl = NULL;
	}

	// Disable command buttons
	btnConnect.EnableWindow(TRUE);
	btnDisconnect.EnableWindow(FALSE);
	btnCaptureVar.EnableWindow(FALSE);
	btnCaptureFile.EnableWindow(FALSE);
	btnRead.EnableWindow(FALSE);
	btnWrite.EnableWindow(FALSE);
}

void CCameraDlg::OnBnClickedButtonCapturev()
{
	HRESULT hr;
	m_vntImage.Clear();

	hr = m_varCapture->get_Value(&m_vntImage);
	if(SUCCEEDED(hr)) {
		Invalidate();
	} else {
		ShowErrorMessage(hr);
	}
}

void CCameraDlg::OnBnClickedButtonCapturef()
{
	HRESULT hr;
	m_vntImage.Clear();

	// Add File object
	CComPtr<ICaoFile> caoFl;
	hr = m_ctrl->AddFile(CComBSTR("File"), CComBSTR(""), &caoFl);
	if(SUCCEEDED(hr)) {
		hr = caoFl->get_Value(&m_vntImage);
		if(SUCCEEDED(hr)) {
			Invalidate();
		}
	}

	if(caoFl != NULL)
	{
		// Release File object
		CComVariant vntFileName;
		CComPtr<ICaoFiles> caoFls;

		m_ctrl->get_Files(&caoFls);

		vntFileName.vt = VT_BSTR;
		caoFl->get_Name(&vntFileName.bstrVal);

		caoFls->Remove(vntFileName);
	}

	if(FAILED(hr)) {
		ShowErrorMessage(hr);
	}
}

void CCameraDlg::OnBnClickedButtonRead()
{
	HRESULT hr;
	CString strValue;
	CComVariant vntValue;

	hr = m_varPause->get_Value(&vntValue);

	if(SUCCEEDED(hr))
	{
		strValue = (vntValue.boolVal == VARIANT_TRUE)
			? _T("True") : _T("False");
		lblPauseValue.SetWindowText(strValue);
	}
	else
	{
		ShowErrorMessage(hr);
	}
}

void CCameraDlg::OnBnClickedButtonWrite()
{
	HRESULT hr;
	CComVariant vntValue;

	hr = m_varPause->get_Value(&vntValue);

	if(SUCCEEDED(hr))
	{
		vntValue.boolVal = (vntValue.boolVal == VARIANT_TRUE)
			? VARIANT_FALSE : VARIANT_TRUE;
		hr = m_varPause->put_Value(vntValue);
	}
	
	if(FAILED(hr))
	{
		ShowErrorMessage(hr);
	}
}

void CCameraDlg::ShowErrorMessage(HRESULT hr)
{
	CString strMsg;
	strMsg.Format(_T("%X"), hr);
	MessageBox(strMsg, _T("Error"));
}
