
// NetConfig_VC++Dlg.cpp : 实现文件
//

#include "stdafx.h"
#include "NetConfig_VC++.h"
#include "NetConfig_VC++Dlg.h"
#include "afxdialogex.h"
#include "PasswordDlg.h"
#include "helper.h"
#include "UpgradeDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CNetConfig_VCDlg 对话框



CNetConfig_VCDlg::CNetConfig_VCDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CNetConfig_VCDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CNetConfig_VCDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_LIST_DEV, m_listDevs);
    DDX_Control(pDX, IDC_MFCPROPERTYGRID1, m_propertyGrid);
}

BEGIN_MESSAGE_MAP(CNetConfig_VCDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BTN_SEARCH, &CNetConfig_VCDlg::OnBnClickedBtnSearch)
    ON_BN_CLICKED(IDC_BTN_GET_CONFIG, &CNetConfig_VCDlg::OnBnClickedBtnGetConfig)
    ON_BN_CLICKED(IDC_BTN_RESET_DEV, &CNetConfig_VCDlg::OnBnClickedBtnResetDev)
    ON_BN_CLICKED(IDC_BTN_RESTORE_DEV, &CNetConfig_VCDlg::OnBnClickedBtnRestoreDev)
    ON_BN_CLICKED(IDC_BTN_UPGRADE, &CNetConfig_VCDlg::OnBnClickedBtnUpgrade)
    ON_BN_CLICKED(IDC_SAVE_CONFIG, &CNetConfig_VCDlg::OnBnClickedSaveConfig)
    ON_BN_CLICKED(IDC_BTN_CLEAR_DEV, &CNetConfig_VCDlg::OnBnClickedBtnClearDev)
END_MESSAGE_MAP()


// CNetConfig_VCDlg 消息处理程序

BOOL CNetConfig_VCDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时，框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO:  在此添加额外的初始化代码
    m_listDevs.SetExtendedStyle(m_listDevs.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);

    m_listDevs.InsertColumn(0, L"设备类型", 0, 120);
    m_listDevs.InsertColumn(1, L"IP地址", 0, 130);

    m_propertyGrid.MarkModifiedProperties();
    m_propertyGrid.EnableHeaderCtrl(TRUE, L"属性项", L"值");
    HDITEM item;
    item.cxy = 120;
    item.mask = HDI_WIDTH;
    m_propertyGrid.GetHeaderCtrl().SetItem(0, new HDITEM(item));

	return TRUE;  // 除非将焦点设置到控件，否则返回 TRUE
}

void CNetConfig_VCDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮，则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序，
//  这将由框架自动完成。

void CNetConfig_VCDlg::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
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CNetConfig_VCDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

CString DeviceTypeStr(int devType) 
{
    switch (devType)
    {
    case ZN_TYPE_CANET_E: return L"CANET-E-U";
    case ZN_TYPE_CANET_2E: return L"CANET-2E-U";
    case ZN_TYPE_CANET_4E: return L"CANET-4E-U";
    case ZN_TYPE_CANET_8E: return L"CANET-8E-U";
    case ZN_TYPE_CANFDNET_200U: return L"CANFDNET-200U";
    }
    return L"Unknown";
}

void CNetConfig_VCDlg::OnBnClickedBtnSearch()
{
    // 最好开线程执行，否则卡界面
    ZN_ERR_CODE ret = ZN_SearchDevice();
    if (ret != ZN_SUCCESS) {
        MessageBox(L"搜索失败！" + ErrorCodeStr(ret), NULL, MB_ICONWARNING);
        return;
    }

    uint32 cnt = ZN_GetDeviceCount();
    TRACE("%d devices\r\n", cnt);

    for (uint32 i = 0; i < cnt; i++) {
        DEV_HANDLE hdev = ZN_GetDeviceAt(i);
        if (hdev == INVALID_DEV_HANDLE) {
            continue;
        }
        DeviceInfo devInfo;
        devInfo.hDev = hdev;
        ZN_PROPERTY prop;
        ret = ZN_GetProperty(hdev, NAME_DEVTYPE, &prop);
        if (ret == ZN_SUCCESS) {
            devInfo.devType = atoi(prop.value);
        }
        ret = ZN_GetProperty(hdev, NAME_DEVIP, &prop);
        if (ret == ZN_SUCCESS) {
            devInfo.ip = prop.value;
        }
        ret = ZN_GetProperty(hdev, NAME_DEVMAC, &prop);
        if (ret == ZN_SUCCESS) {

            devInfo.mac = prop.value;
        }
        bool exist = false;
        for (DeviceInfo &d : m_devices) {
            if (d.devType == devInfo.devType && d.ip == devInfo.ip && d.mac == devInfo.mac) {
                exist = true;
                break;
            }
        }

        if (!exist) {
            m_devices.push_back(devInfo);
            int listCnt = m_listDevs.GetItemCount();
            m_listDevs.InsertItem(listCnt, DeviceTypeStr(devInfo.devType));
            m_listDevs.SetItemText(listCnt, 1, devInfo.ip);

            m_listDevs.SetItemData(listCnt, m_devices.size() - 1);
        }
    }
}

void CNetConfig_VCDlg::OnBnClickedBtnClearDev()
{
    m_listDevs.DeleteAllItems();
    m_devices.clear();
    ZN_ClearDevice();

    m_propertyGrid.RemoveAll();
    m_propertyGrid.Invalidate();
    m_properties.clear();
    m_curDevice = nullptr;
}

void CNetConfig_VCDlg::OnBnClickedBtnGetConfig()
{
    m_propertyGrid.RemoveAll();
    m_propertyGrid.Invalidate();
    m_properties.clear();
    m_curDevice = nullptr;

    int cursel = m_listDevs.GetSelectionMark();
    if (cursel < 0) {
        return;
    }

    DeviceInfo *pDevInfo = &m_devices[m_listDevs.GetItemData(cursel)];
    if (!pDevInfo) {
        return;
    }

    ZN_COMM_INFO comm;
    comm.commType = ZN_COMM_UDP;
    if (ZN_Connect(pDevInfo->hDev, &comm) != ZN_SUCCESS) {
        return;
    }

    ZN_ERR_CODE ret = ZN_LoadInfo(pDevInfo->hDev);
    if (ret != ZN_SUCCESS) {
        CString msg;
        msg.Format(L"获取设备 %s 配置信息失败！%s", pDevInfo->ip, ErrorCodeStr(ret));
        MessageBox(msg, NULL, MB_ICONWARNING);
        return;
    }

    m_curDevice = pDevInfo;
    LoadDeviceCommonProperties(pDevInfo);

    if (pDevInfo->devType == ZN_TYPE_CANFDNET_200U) {
        LoadCanfdnet200uProperties(pDevInfo);
    }

    m_propertyGrid.ExpandAll(TRUE);
}

void CNetConfig_VCDlg::LoadCanfdnet200uProperties(const DeviceInfo *pDevInfo)
{
    ZN_PROPERTY p;
    memset(&p, 0, sizeof(p));
    ZN_ERR_CODE ret = ZN_SUCCESS;

    for (int can = 1; can <= 2; can++) {
        CString groupName;
        groupName.Format(_T("CAN%d"), can-1);
        CMFCPropertyGridProperty *group = new CMFCPropertyGridProperty(groupName);
        m_propertyGrid.AddProperty(group);
        CMFCPropertyGridProperty *propItem = NULL;

#define  ADD_CAN_BASIC_PROP(nameFmt, display, readonly) { \
        sprintf_s(p.name, nameFmt, can); \
        ret = ZN_GetProperty(pDevInfo->hDev, p.name, &p); \
        if (ret == ZN_SUCCESS) { \
            propItem = new CMFCPropertyGridProperty(display, CString(p.value)); \
            propItem->AllowEdit(!readonly); \
            m_properties.push_back(p); \
            propItem->SetData(m_properties.size() - 1); \
            group->AddSubItem(propItem);\
        } \
        }

        ADD_CAN_BASIC_PROP(NAME_CANFDNET_CAN_N_TYPE, L"控制器类型", false);
        ADD_CAN_BASIC_PROP(NAME_CANFDNET_CAN_N_MODE, L"工作模式", false);
        ADD_CAN_BASIC_PROP(NAME_CANFDNET_CAN_N_CLOCK, L"控制器时钟", true);
        ADD_CAN_BASIC_PROP(NAME_CANFDNET_CAN_N_NBAUD, L"仲裁域波特率", false);
        ADD_CAN_BASIC_PROP(NAME_CANFDNET_CAN_N_DBAUD, L"数据域波特率", false);
    }
}

void CNetConfig_VCDlg::LoadDeviceCommonProperties(const DeviceInfo *pDevInfo)
{
    ZN_PROPERTY p;
    ZN_ERR_CODE ret = ZN_SUCCESS;
    CMFCPropertyGridProperty *propItem = NULL;

    CMFCPropertyGridProperty *group = new CMFCPropertyGridProperty(L"基本属性");
    m_propertyGrid.AddProperty(group);
    
    ret = ZN_GetProperty(pDevInfo->hDev, NAME_DEVNAME, &p);
    if (ret == ZN_SUCCESS) {
        propItem = new CMFCPropertyGridProperty(L"设备名称", CString(p.value));
        propItem->AllowEdit(FALSE);
        group->AddSubItem(propItem);
    }

    ret = ZN_GetProperty(pDevInfo->hDev, NAME_DEVMAC, &p);
    if (ret == ZN_SUCCESS) {
        propItem = new CMFCPropertyGridProperty(L"MAC地址", CString(p.value));
        propItem->AllowEdit(FALSE);
        group->AddSubItem(propItem);
    }

    ret = ZN_GetProperty(pDevInfo->hDev, NAME_FIRMWARE_VER, &p);
    if (ret == ZN_SUCCESS) {
        propItem = new CMFCPropertyGridProperty(L"固件版本", CString(p.value));
        propItem->AllowEdit(FALSE);
        group->AddSubItem(propItem);
    }

    ret = ZN_GetProperty(pDevInfo->hDev, NAME_HARDWARE_VER, &p);
    if (ret == ZN_SUCCESS) {
        propItem = new CMFCPropertyGridProperty(L"硬件版本", CString(p.value));
        propItem->AllowEdit(FALSE);
        group->AddSubItem(propItem);
    }
}

void CNetConfig_VCDlg::OnBnClickedBtnResetDev()
{
    if (!m_curDevice) {
        return;
    }

    CPasswordDlg dlg(this);
    if (dlg.DoModal() != IDOK) {
        return;
    }

    CString password = dlg.GetPassword();

    ZN_ERR_CODE ret = ZN_Reset(m_curDevice->hDev, ws2s(password.GetString()).c_str());
    if (ret != ZN_SUCCESS) {
        MessageBox(L"设备复位失败！\n" + ErrorCodeStr(ret), NULL, MB_ICONWARNING);
    }
    else {
        MessageBox(L"设备复位成功。", NULL, MB_ICONINFORMATION);
    }
}

void CNetConfig_VCDlg::OnBnClickedBtnRestoreDev()
{
    if (!m_curDevice) {
        return;
    }

    CPasswordDlg dlg(this);
    if (dlg.DoModal() != IDOK) {
        return;
    }

    CString password = dlg.GetPassword();

    ZN_ERR_CODE ret = ZN_FactoryReset(m_curDevice->hDev, ws2s(password.GetString()).c_str());
    if (ret != ZN_SUCCESS) {
        MessageBox(L"设备恢复出厂失败！\n" + ErrorCodeStr(ret), NULL, MB_ICONWARNING);
    }
    else {
        MessageBox(L"设备恢复出厂成功。\n\n将会再次获取设备参数...", NULL, MB_ICONINFORMATION);
        OnBnClickedBtnGetConfig();
    }
}

void CNetConfig_VCDlg::OnBnClickedBtnUpgrade()
{
    if (!m_curDevice) {
        return;
    }

    CUpgradeDlg dlg(m_curDevice->hDev, this);
    dlg.DoModal();
}

bool CNetConfig_VCDlg::SaveModifiedProperty(CMFCPropertyGridProperty *base)
{
    if (!base) {
        return false;
    }

    if (base->IsGroup()) {
        int subCnt = base->GetSubItemsCount();
        for (int subIdx = 0; subIdx < subCnt; subIdx++) {
            CMFCPropertyGridProperty *subItem = base->GetSubItem(subIdx);
            if (!SaveModifiedProperty(subItem)) {
                return false;
            }
        }
        return true;
    }

    if (!base->IsModified()) {
        return true;
    }

    int data = base->GetData();
    if (data < 0 || data >= (int)m_properties.size()) {
        return false;
    }

    ZN_PROPERTY prop = m_properties[data];
    CString value = base->GetValue();
    sprintf_s(prop.value, ws2s(value.GetString()).c_str());

    ZN_ERR_CODE ret = ZN_SUCCESS;
    ret = ZN_SetProperty(m_curDevice->hDev, &prop);
    if (ret != ZN_SUCCESS) {
        MessageBox(base->GetName() + CString("\n") + ErrorCodeStr(ret), NULL, MB_ICONWARNING);
        return false;
    }

    return true;
}

void CNetConfig_VCDlg::OnBnClickedSaveConfig()
{
    if (!m_curDevice) {
        return;
    }

    CPasswordDlg dlg(this);
    if (dlg.DoModal() != IDOK) {
        return;
    }

    CString password = dlg.GetPassword();
    
    int cnt = m_propertyGrid.GetPropertyCount();
    for (int i = 0; i < cnt; i++) {
        CMFCPropertyGridProperty *item = m_propertyGrid.GetProperty(i);
        if (!SaveModifiedProperty(item)) {
            return;
        }
    }

    ZN_ERR_CODE ret = ZN_SubmitInfo(m_curDevice->hDev, ws2s(password.GetString()).c_str());
    if (ret != ZN_SUCCESS) {
        MessageBox(L"提交更改失败！\n" + ErrorCodeStr(ret), NULL, MB_ICONWARNING);
    }
    else {
        MessageBox(L"设备属性更改成功。\n\n将会再次获取设备参数...", NULL, MB_ICONINFORMATION);
        OnBnClickedBtnGetConfig();
    }
}
