// BaseClientDlg.cpp : Implementation file
//

#include "stdafx.h"
#include "BaseClient.h"
#include "BaseClientDlg.h"
#include "ListenSocket.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define TEST_PORT 54321

/////////////////////////////////////////////////////////////////////////////
// CBaseClientDlg dialog

CBaseClientDlg::CBaseClientDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CBaseClientDlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(CBaseClientDlg)
    m_iRadio1 = -1;
    m_sPlayStatus = _T("");
    //}}AFX_DATA_INIT
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    m_iRadio1 = -1;
    m_sPlayStatus = _T("");
    m_pVAibo = NULL;
    m_nAiboID = -1;
    m_nPlayID = -1;
    m_bConnected = FALSE;
    m_bControl = FALSE;
    m_myRequest = FALSE;
// for Socket
    m_pListen = NULL;
    m_uPort = TEST_PORT;

}

void CBaseClientDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CBaseClientDlg)
    DDX_Control(pDX, IDC_IPADDRESS1, m_ipAddress);
    DDX_Radio(pDX, IDC_RADIO1, m_iRadio1);
    DDX_Text(pDX, IDC_EDIT1, m_sPlayStatus);
    //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CBaseClientDlg, CDialog)
    //{{AFX_MSG_MAP(CBaseClientDlg)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BTN_AUTONOMY, OnBtnAutonomy)
    ON_BN_CLICKED(IDC_BTN_CONNECT, OnBtnConnect)
    ON_BN_CLICKED(IDC_BTN_PLAY, OnBtnPlay)
    ON_BN_CLICKED(IDC_BTN_REMOTE, OnBtnRemote)
    ON_WM_DESTROY()
    ON_BN_CLICKED(IDC_BTN_SOCKET, OnBtnSocket)
    //}}AFX_MSG_MAP
    // VAIBO Sever Messages
    ON_REGISTERED_MESSAGE(WM_VAIBO_CONNECT, OnVAIBOConnect)
    ON_REGISTERED_MESSAGE(WM_VAIBO_CLIENT_UPDATE, OnVAIBOConnectUpdate)
    ON_REGISTERED_MESSAGE(WM_VAIBO_DISCONNECT, OnVAIBODisconnect)
    ON_REGISTERED_MESSAGE(WM_VAIBO_SEMANTICS, OnVAIBOSemantics)
    ON_REGISTERED_MESSAGE(WM_VAIBO_REMOTE_NOTIFY, OnVAIBORemoteNotify)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CBaseClientDlg message handlers

BOOL CBaseClientDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    SetIcon(m_hIcon, TRUE);         // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon

    // TODO: Add extra initialization here
    if ( m_pVAibo == NULL ) {
        m_pVAibo = new CVAIBO( this->m_hWnd );
    }
    ASSERT(m_pVAibo);

    INT nField0, nField1, nField2, nField3;
    LPCTSTR p = theApp.m_sAiboIP.GetBuffer(128);
    ::sscanf( p, "%d.%d.%d.%d", &nField0, &nField1, &nField2, &nField3 );
    theApp.m_sAiboIP.ReleaseBuffer();
    m_ipAddress.SetAddress( nField0, nField1, nField2, nField3 );

    return TRUE;   // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CBaseClientDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

        // Center icon in client rectangle
        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;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialog::OnPaint();
    }
}

HCURSOR CBaseClientDlg::OnQueryDragIcon()
{
    return (HCURSOR) m_hIcon;
}

//  ON_REGISTERED_MESSAGE(WM_VAIBO_CLIENT_UPDATE, OnVAIBOConnectUpdate)
//  Another application has already connected to AIBO
LRESULT CBaseClientDlg::OnVAIBOConnectUpdate( WPARAM wParam, LPARAM lParam )
{
    LRESULT result;

    if ((unsigned) m_nAiboID != HIWORD(wParam)) {
        // This is not my AIBO that I requested to connect to
        return S_FALSE;
    }
    if (!m_myRequest) {
        // This is not my request, another application changes the connection status.
        return S_FALSE;
    }
    m_myRequest = FALSE;
    if (LOWORD(wParam) == 1) {
        result = OnVAIBOConnect(wParam, lParam );
    } else {
        result = OnVAIBODisconnect(wParam, lParam );
    }
    return result;
}
//  ON_REGISTERED_MESSAGE(WM_VAIBO_CONNECT, OnVAIBOConnect)
LRESULT CBaseClientDlg::OnVAIBOConnect( WPARAM wParam, LPARAM lParam )
{
    if ((unsigned) m_nAiboID != HIWORD(wParam)) {
        // This is not my AIBO that I requested to connect to
        return S_FALSE;
    }
    buttonConnect().SetWindowText( "Disconnect" );
    m_bConnected = TRUE;
    m_bControl = FALSE;
    buttonRemote().EnableWindow(TRUE);
    buttonAutonomy().EnableWindow(FALSE);
    buttonPlay().EnableWindow(FALSE);
    // Check another application getting remote control
    if ( m_pVAibo->IsRemote() ) {
        OnVAIBORemoteNotify(wParam, 1);
    } 
    return S_OK;
}

//  ON_REGISTERED_MESSAGE(WM_VAIBO_DISCONNECT, OnVAIBODisconnect)
LRESULT CBaseClientDlg::OnVAIBODisconnect( WPARAM wParam, LPARAM lParam )
{
    if ((unsigned) m_nAiboID != HIWORD(wParam)) {
        // This is not my AIBO that I was connected to
        return S_FALSE;
    }
    buttonConnect().SetWindowText( "Connect" );
    m_bConnected = FALSE;
    m_bControl = FALSE;
    m_nAiboID = -1;
    buttonRemote().EnableWindow(FALSE);
    buttonAutonomy().EnableWindow(FALSE);
    buttonPlay().EnableWindow(FALSE);
    return S_OK;
}
// ON_REGISTERED_MESSAGE(WM_VAIBO_SEMANTICS, OnVAIBOSemantics)
LRESULT CBaseClientDlg::OnVAIBOSemantics( WPARAM wParam, LPARAM lParam )
{
    int subinfo[4];

    if ((unsigned) m_nAiboID != HIWORD(wParam)) {
        // This semantics data didn't come from my AIBO
        return S_FALSE;
    }

    if (SEM_RESULT == LOWORD(wParam)) {
        m_pVAibo->GetSemInfo( subinfo );
        if (m_nPlayID == subinfo[0]) {
            UpdateData(TRUE);
            switch (lParam) {
            case RESULT_COMPLETE :
                m_sPlayStatus.Format("No.%d motion completed", subinfo[0]);
                break;
            case RESULT_INCOMPLETE :
                m_sPlayStatus.Format("No.%d motion incomplete", subinfo[0]);
                break;
            }
            UpdateData(FALSE);
        }
    }
    return S_OK;
}

//  ON_REGISTERED_MESSAGE(WM_VAIBO_REMOTE_NOTIFY, OnVAIBORemoteNotify)
LRESULT CBaseClientDlg::OnVAIBORemoteNotify( WPARAM wParam, LPARAM lParam )
{
    if ((unsigned) m_nAiboID != HIWORD(wParam)) {
        // This is not my AIBO that I requested to connect to
        return S_FALSE;
    }
    if (lParam) {
        // External control
        buttonRemote().EnableWindow(FALSE);
        buttonAutonomy().EnableWindow(TRUE);
        buttonPlay().EnableWindow(TRUE);
        m_bControl = TRUE;
    } else {
        // Internal control
        buttonRemote().EnableWindow(TRUE);
        buttonAutonomy().EnableWindow(FALSE);
        buttonPlay().EnableWindow(FALSE);
        m_bControl = FALSE;
    }
    return S_OK;
}

void CBaseClientDlg::OnBtnConnect()
{
    if ( !m_bConnected ) {
        UpdateData();

        BYTE        nField0, nField1, nField2, nField3;
        m_ipAddress.GetAddress(nField0, nField1, nField2, nField3 );
        theApp.m_sAiboIP.Format("%d.%d.%d.%d", nField0, nField1, nField2, nField3 );
        buttonConnect().SetWindowText( "Connecting..." );
        m_myRequest = TRUE;
		int nAiboID;
        nAiboID = m_pVAibo->Connect((LPCTSTR)theApp.m_sAiboIP);
        if (nAiboID < 0) {
            CString msgerr;
            msgerr.Format("AIBO connection error (%d), see VAIBODef.h", nAiboID);
            AfxMessageBox(msgerr);
        }else{
			m_nAiboID = nAiboID;
		}
    } else {
        buttonConnect().SetWindowText( "Disconnecting..." );
        m_myRequest = TRUE;
        int result = m_pVAibo->Disconnect();
        if (result != VAIBO_NOERROR) {
            CString msgerr;
            msgerr.Format("AIBO disconnection error (%d), see VAIBODef.h", result);
            AfxMessageBox(msgerr);
        }
    }
}

void CBaseClientDlg::OnBtnPlay()
{
    int result = VAIBO_NOERROR;
    CString msgerr;

    UpdateData();
    if ( m_bControl ) {
        switch (m_iRadio1) {
        // CommandList.txt contains a list of motions that AIBO can perform.
        case 0 : result = m_pVAibo->PlayMotion((0x11 << 24) | (0x00 << 16) | (0x00 << 8) | 0x05,
                     false, false, false); // LMS=0x11 0x00 0x00 Level 5 Hello motion
                break;
        case 1 : result = m_pVAibo->PlayMotion((0x11 << 24) | (0x00 << 16) | (0x03 << 8) | 0x00,
                     false, false, false); // LMS=0x11 0x00 0x03 Bye motion
                break;
        case 2 : result = m_pVAibo->PlayMotion((0x15 << 24) | (0x03 << 16) | (0x00 << 8) | 0x00,
                     false, false, false); // LMS=0x15 0x03 0x00 Dance motion
        }
        if (result < 0 ) {
            msgerr.Format("PlayContents error (%d), see VAIBODef.h", result);
            AfxMessageBox(msgerr);
        }
        m_nPlayID = result;
        m_sPlayStatus.Format("No.%d motion is playing", m_nPlayID);
        UpdateData(FALSE);
    }
}

void CBaseClientDlg::OnBtnRemote()
{
    if ( m_pVAibo != NULL ) {
        if (!m_bControl) {
            // Check another application getting remote control
            if ( m_pVAibo->IsRemote() ) {
                OnVAIBORemoteNotify(((unsigned)m_nAiboID)<<16, 1);
            } else 
            // Start controlling from PC
            if ( !(m_pVAibo->ExternalControl(FALSE)) ) {
                CString msgerr;
                msgerr.Format("ExternalControl error");
                AfxMessageBox(msgerr);
            }
        }
    }
}

void CBaseClientDlg::OnBtnAutonomy()
{
    if ( m_pVAibo != NULL ) {
        if (m_bControl) {
            // Check another application releasing remote control
            if ( !(m_pVAibo->IsRemote()) ) {
                OnVAIBORemoteNotify(((unsigned)m_nAiboID)<<16, 0);
            } else 
            // Stop controlling from PC
            if ( !(m_pVAibo->InternalControl(FALSE)) ) {
                CString msgerr;
                msgerr.Format("InternalControl error");
                AfxMessageBox(msgerr);
            }
        }
    }
}

void CBaseClientDlg::OnDestroy()
{
    CDialog::OnDestroy();

    if ( m_pVAibo != NULL ) {
        if ( m_bConnected ) {
            int result = m_pVAibo->Disconnect();
            if (result != VAIBO_NOERROR) {
                CString msgerr;
                msgerr.Format("AIBO disconnection error (%d), see VAIBODef.h", result);
                AfxMessageBox(msgerr);
            }
        }
        delete m_pVAibo;
        m_pVAibo = NULL;
    }
    // Terminate Listen Socket
    StopListening();
}

void CBaseClientDlg::OnBtnSocket()
{
    HICON hNew;
    if ( m_pListen != NULL ) {
        StopListening();
        hNew = ::LoadIcon(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_REDBALL));
        ASSERT(hNew != NULL);
        ::DestroyIcon(SocketStatus().SetIcon(hNew));
        buttonSocket().SetWindowText( "Socket Server ON" );
    } else {
        StartListening();
        hNew = ::LoadIcon(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_BLUEBALL));
        ASSERT(hNew != NULL);
        ::DestroyIcon(SocketStatus().SetIcon(hNew));
        buttonSocket().SetWindowText( "Socket Server OFF" );
    }
    UpdateWindow();                 // draw everything now
}

void CBaseClientDlg::StopListening()
{
    if ( m_pListen != NULL )
    {
        m_pListen->Close();
        delete m_pListen;
        m_pListen = NULL;
    }
}

BOOL CBaseClientDlg::StartListening()
{
    BOOL bOk = FALSE;
    StopListening();
    m_pListen = new CListenSocket(this);
    if ( m_pListen )
    {
        if ( m_pListen->Create( m_uPort, SOCK_STREAM, FD_ACCEPT ) )
            bOk = m_pListen->Listen();

        if ( !bOk )
        {
            CString strMsg;
            int nErr = m_pListen->GetLastError();
            if ( nErr == WSAEADDRINUSE )
                strMsg.Format( IDS_LISTEN_INUSE, m_uPort );
            else
                strMsg.Format( IDS_LISTEN_ERROR, m_uPort );

            AfxMessageBox( strMsg, MB_OK|MB_ICONSTOP );
            m_pListen->Close();
            delete m_pListen;
            m_pListen = NULL;
        }
    }
    else
        AfxMessageBox( IDS_CANT_LISTEN, MB_OK|MB_ICONSTOP );

    return bOk;
}
