// TaskDlg.cpp : 実装ファイル
//

#include "stdafx.h"
#include "Task.h"
#include "TaskDlg.h"
#include "CAO_i.c"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CTaskDlg ダイアログ

CTaskDlg::CTaskDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CTaskDlg::IDD, pParent),
	m_eng(NULL), m_wss(NULL), m_ws(NULL),
	m_ctrls(NULL), m_ctrl(NULL), m_tsks(NULL)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CTaskDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_COMBO_PARAMETER, m_cmbParam);
	DDX_Control(pDX, IDC_COMBO_START, m_cmbStart);
	DDX_Control(pDX, IDC_COMBO_STOP, m_cmbStop);
	DDX_Control(pDX, IDC_BUTTON_CONNECT, m_btnConn);
	DDX_Control(pDX, IDC_BUTTON_DISCONNECT, m_btnDisconn);
	DDX_Control(pDX, IDC_BUTTON_START, m_btnStart);
	DDX_Control(pDX, IDC_BUTTON_STOP, m_btnStop);
	DDX_Control(pDX, IDC_BUTTON_REFRESH, m_btnRefresh);
	DDX_Control(pDX, IDC_BUTTON_EXIT, m_btnExit);
	DDX_Control(pDX, IDC_LIST_TASK, m_lstTask);
}

BEGIN_MESSAGE_MAP(CTaskDlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_BUTTON_CONNECT, &CTaskDlg::OnBnClickedButtonConnect)
	ON_BN_CLICKED(IDC_BUTTON_DISCONNECT, &CTaskDlg::OnBnClickedButtonDisconnect)
	ON_BN_CLICKED(IDC_BUTTON_START, &CTaskDlg::OnBnClickedButtonStart)
	ON_BN_CLICKED(IDC_BUTTON_STOP, &CTaskDlg::OnBnClickedButtonStop)
	ON_BN_CLICKED(IDC_BUTTON_REFRESH, &CTaskDlg::OnBnClickedButtonRefresh)
	ON_BN_CLICKED(IDC_BUTTON_EXIT, &CTaskDlg::OnBnClickedButtonExit)
	ON_WM_DESTROY()
	ON_WM_TIMER()
END_MESSAGE_MAP()


// CTaskDlg メッセージ ハンドラ

BOOL CTaskDlg::OnInitDialog()
{
	int index;

	CDialog::OnInitDialog();

	// このダイアログのアイコンを設定します。アプリケーションのメイン ウィンドウがダイアログでない場合、
	//  Framework は、この設定を自動的に行います。
	SetIcon(m_hIcon, TRUE);			// 大きいアイコンの設定
	SetIcon(m_hIcon, FALSE);		// 小さいアイコンの設定

	// フォーム初期化
	m_cmbParam.AddString(_T("Server=192.168.0.1"));
	m_cmbParam.AddString(_T("WPJ=*"));
	m_cmbParam.SetCurSel(0);

	index = m_cmbStart.AddString(_T("1 - One cycle execution"));
	m_cmbStart.SetItemData(index, 1);
	index = m_cmbStart.AddString(_T("2 - Continuous execution"));
	m_cmbStart.SetItemData(index, 2);
	index = m_cmbStart.AddString(_T("3 - Step forward"));
	m_cmbStart.SetItemData(index, 3);
	m_cmbStart.SetCurSel(0);

	index = m_cmbStop.AddString(_T("0 - Default stop"));
	m_cmbStop.SetItemData(index, 0);
	index = m_cmbStop.AddString(_T("1 - Instant stop"));
	m_cmbStop.SetItemData(index, 1);
	index = m_cmbStop.AddString(_T("2 - Step stop"));
	m_cmbStop.SetItemData(index, 2);
	index = m_cmbStop.AddString(_T("3 - Cycle stop"));
	m_cmbStop.SetItemData(index, 3);
	index = m_cmbStop.AddString(_T("4 - Initialized stop"));
	m_cmbStop.SetItemData(index, 4);
	m_cmbStop.SetCurSel(0);

	InitializeList();

	CoInitialize(NULL);
	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);
	m_ws->get_Controllers(&m_ctrls);

	return TRUE;  // フォーカスをコントロールに設定した場合を除き、TRUE を返します。
}

void CTaskDlg::OnDestroy()
{
	CDialog::OnDestroy();

	OnBnClickedButtonDisconnect();

	if(m_ctrls != NULL) {
		m_ctrls->Release();
		m_ctrls = NULL;
	}

	if(m_ws != NULL) {
		m_ws->Release();
		m_ws = NULL;
	}

	if(m_wss != NULL) {
		m_wss->Release();
		m_wss = NULL;
	}

	if(m_eng != NULL) {
		m_eng->Release();
		m_eng = NULL;
	}

	CoUninitialize();
}

// ダイアログに最小化ボタンを追加する場合、アイコンを描画するための
//  下のコードが必要です。ドキュメント/ビュー モデルを使う MFC アプリケーションの場合、
//  これは、Framework によって自動的に設定されます。

void CTaskDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 描画のデバイス コンテキスト

		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
	{
		CDialog::OnPaint();
	}
}

// ユーザーが最小化したウィンドウをドラッグしているときに表示するカーソルを取得するために、
//  システムがこの関数を呼び出します。
HCURSOR CTaskDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void CTaskDlg::OnBnClickedButtonConnect()
{
	OnBnClickedButtonDisconnect();

	TCHAR tchTmp[1024];
	m_cmbParam.GetWindowText(tchTmp, 1024);

	CString strConn = tchTmp;

	HRESULT hr = m_ws->AddController(CComBSTR(L""), CComBSTR(L"CaoProv.DENSO.RC8"), CComBSTR(L""), CComBSTR(strConn), &m_ctrl);
	if(FAILED(hr)) {
		ShowErrorNumber(hr);
		return;
	}

	m_ctrl->get_Tasks(&m_tsks);

	OnBnClickedButtonRefresh();

	m_btnStart.EnableWindow(TRUE);
	m_btnStop.EnableWindow(TRUE);
	m_btnRefresh.EnableWindow(TRUE);

	SetTimer(1, 150, NULL);
}

void CTaskDlg::OnBnClickedButtonDisconnect()
{
	KillTimer(1);

	m_btnStart.EnableWindow(FALSE);
	m_btnStop.EnableWindow(FALSE);
	m_btnRefresh.EnableWindow(FALSE);

	if(m_tsks != NULL) {
		m_tsks->Clear();
		m_tsks->Release();
		m_tsks = NULL;
	}

	if(m_ctrl != NULL) {
		CComVariant index(0L);
		m_ctrl->get_Index(&index.lVal);
		m_ctrls->Remove(index);
		m_ctrl->Release();
		m_ctrl = NULL;
	}
}

void CTaskDlg::OnBnClickedButtonStart()
{
	VARIANT index;
	index.vt   = VT_I4;
	index.lVal = m_lstTask.GetNextItem(-1, LVNI_ALL|LVNI_SELECTED);

	CComPtr<ICaoTask> task;
	m_tsks->Item(index, &task);

	long mode = (long)m_cmbStart.GetItemData(m_cmbStart.GetCurSel());
	HRESULT hr = task->Start(mode, CComBSTR(L""));

	if(FAILED(hr)) {
		ShowErrorNumber(hr);
	}
}

void CTaskDlg::OnBnClickedButtonStop()
{
	VARIANT index;
	index.vt   = VT_I4;
	index.lVal = m_lstTask.GetNextItem(-1, LVNI_ALL|LVNI_SELECTED);

	CComPtr<ICaoTask> task;
	m_tsks->Item(index, &task);

	long mode = (long)m_cmbStop.GetItemData(m_cmbStop.GetCurSel());
	HRESULT hr = task->Stop(mode, CComBSTR(L""));

	if(FAILED(hr)) {
		ShowErrorNumber(hr);
	}
}

void CTaskDlg::OnBnClickedButtonRefresh()
{
	HRESULT hr;
	CComVariant names;

	// Clear all task in caoCtrl.Tasks
	m_tsks->Clear();

	// Append all task into caoCtrl.Tasks
	hr = m_ctrl->get_TaskNames(CComBSTR(L""), &names);
	if(SUCCEEDED(hr) && (names.vt == (VT_ARRAY | VT_BSTR))) {
		ULONG i, count;
		BSTR *pbstr;

		count = names.parray->rgsabound->cElements;
		SafeArrayAccessData(names.parray, (void**)&pbstr);

		for(i = 0; i < count; i++) {
			CComPtr<ICaoTask> task;
			m_ctrl->AddTask(pbstr[i], CComBSTR(L""), &task);

			CComPtr<ICaoVariable> var;
			task->AddVariable(CComBSTR(L"@STATUS"), CComBSTR(L""), &var);
			var.Release();
			task->AddVariable(CComBSTR(L"@LINE_NO"), CComBSTR(L""), &var);
			var.Release();
			task->AddVariable(CComBSTR(L"@CYCLE_TIME"), CComBSTR(L""), &var);
			var.Release();
			task->AddVariable(CComBSTR(L"@PRIORITY"), CComBSTR(L""), &var);
		}

		SafeArrayUnaccessData(names.parray);
	}
}

void CTaskDlg::OnBnClickedButtonExit()
{
	DestroyWindow();
}

void CTaskDlg::OnTimer(UINT_PTR nIDEvent)
{
	long i, j, k, elem, tskCnt, varCnt, valCnt;	
	LVITEM lvi;
	lvi.mask = LVIF_TEXT;

	m_tsks->get_Count(&tskCnt);
	for(i = 0; i < tskCnt; i++) {
		lvi.iItem = i;

		CComVariant tskInd(i);

		CComPtr<ICaoTask> task;
		m_tsks->Item(tskInd, &task);

		CComPtr<ICaoVariables> vars;
		task->get_Variables(&vars);

		vars->get_Count(&varCnt);
		for(j = 0; j < varCnt+1; j++) {
			lvi.iSubItem = j;

			if(j == 0) {
				CComBSTR name;
				task->get_Name(&name);
				lvi.pszText = (LPWSTR)name;

				if(i == m_lstTask.GetItemCount()) {
					m_lstTask.InsertItem(&lvi);
				}
				else {
					m_lstTask.SetItem(&lvi);
				}
			}
			else {
				CComVariant index(j-1), value;

				CComPtr<ICaoVariable> var;
				vars->Item(index, &var);
				
				var->get_Value(&value);
				if(value.vt & VT_ARRAY) {
					void *pData;
					CComBSTR text(L"");

					elem   = value.parray->cbElements;
					valCnt = value.parray->rgsabound->cElements;

					SafeArrayAccessData(value.parray, (void**)&pData);

					for(k = 0; k < valCnt; k++) {
						CComVariant tmp;
						tmp.vt = value.vt ^ VT_ARRAY;

						switch(tmp.vt) {
							case VT_I4:
								tmp.lVal = *((long*)pData);
								break;
						}

						if(tmp.vt != VT_BSTR) {
							VariantChangeType(&tmp, &tmp, 0, VT_BSTR);
						}

						text += tmp.bstrVal;
						if(k != valCnt - 1) text += L",";
						pData = ((char*)pData)+elem;
					}

					SafeArrayUnaccessData(value.parray);

					lvi.pszText = (LPWSTR)text;
					m_lstTask.SetItem(&lvi);
				}
				else {
					if(value.vt != VT_BSTR) {
						VariantChangeType(&value, &value, 0, VT_BSTR);
					}
					lvi.pszText = (LPWSTR)value.bstrVal;
					m_lstTask.SetItem(&lvi);
				}
			}
		}
	}

	CDialog::OnTimer(nIDEvent);
}

void CTaskDlg::InitializeList()
{
    LVCOLUMN    lvc;
    int         i;
    TCHAR       caption[][128] = {
		_T("Program name"), _T("Status"), _T("LineNo"),
		_T("CycleTime"), _T("Priority")
	};
    const int clmNum = sizeof(caption)/sizeof(caption[0]);

    lvc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
    for(i = 0; i < clmNum; i++){
        lvc.iSubItem    = i;
        lvc.pszText     = caption[i];
        lvc.cx          = 85;
        if(m_lstTask.InsertColumn(i, &lvc) == -1){
			break;
		}
    }
}

void CTaskDlg::ShowErrorNumber(HRESULT hr)
{
	TCHAR tchVal[9];

	_stprintf_s(tchVal, 9, _T("%x"), hr);

	MessageBox(tchVal, _T("Error Number"), MB_OK);
}

