
// MainFrm.cpp : CMainFrame クラスの実装
//

#include "stdafx.h"
#include "TestLib.h"

#include "MainFrm.h"

#include "DlgInputSingleLine.h"

#include <wininet.h>
#pragma comment( lib, "wininet.lib" )

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

using namespace RLib;


struct CParsedUrl
{
	CString			sScheme;		// scheme name
	INTERNET_SCHEME nScheme;		// enumerated scheme type (if known)
	CString			sHostName;		// host name
	INTERNET_PORT	nPort;			// converted port number
	CString			sUserName;		// user name
	CString			sPassword;		// password
	CString			sUrlPath;		// URL-path
	CString			sExtraInfo;		// extra information (e.g. ?foo or #foo)
	CParsedUrl()
		:nScheme(INTERNET_SCHEME_UNKNOWN)
		,nPort(0)
		{}
};

CParsedUrl ParseUrl(const CString &sUrl)
{
	CParsedUrl r;

	const size_t size = sUrl.GetLength();

	vector<TCHAR> vScheme(size+1);
	vector<TCHAR> vHostName(size+1);
	vector<TCHAR> vUserName(size+1);
	vector<TCHAR> vPassword(size+1);
	vector<TCHAR> vUrlPath(size+1);
	vector<TCHAR> vExtraInfo(size+1);

	URL_COMPONENTS uc;
	uc.dwStructSize = sizeof(uc);
	uc.lpszScheme		= &vScheme[0];
	uc.dwSchemeLength	= vScheme.size();
	uc.lpszHostName		= &vHostName[0];
	uc.dwHostNameLength	= vHostName.size();
	uc.lpszUserName		= &vUserName[0];
	uc.dwUserNameLength	= vUserName.size();
	uc.lpszPassword		= &vPassword[0];
	uc.dwPasswordLength	= vPassword.size();
	uc.lpszUrlPath		= &vUrlPath[0];
	uc.dwUrlPathLength	= vUrlPath.size();
	uc.lpszExtraInfo	= &vExtraInfo[0];
	uc.dwExtraInfoLength= vUrlPath.size();

	if( ::InternetCrackUrl(sUrl, 0, 0, &uc) ){
		r.sScheme	= uc.lpszScheme;
		r.nScheme	= uc.nScheme;
		r.sHostName	= uc.lpszHostName;
		r.nPort		= uc.nPort;
		r.sUserName	= uc.lpszUserName;
		r.sPassword	= uc.lpszPassword;
		r.sUrlPath	= uc.lpszUrlPath;
		r.sExtraInfo= uc.lpszExtraInfo;
	}

	return r;
}

////////////////////////////////////////////////

// CMainFrame

IMPLEMENT_DYNAMIC(CMainFrame, CFrameWndEx)

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
	ON_WM_CREATE()
	ON_WM_SETFOCUS()
	ON_COMMAND(ID_VIEW_CUSTOMIZE, &CMainFrame::OnViewCustomize)
	ON_REGISTERED_MESSAGE(AFX_WM_CREATETOOLBAR, &CMainFrame::OnToolbarCreateNew)
	ON_COMMAND(ID_UDPHOLEPUNCHING_SERVER, &CMainFrame::OnUdpholepunchingServer)
	ON_COMMAND(ID_UDPHOLEPUNCHING_CLIENT, &CMainFrame::OnUdpholepunchingClient)
END_MESSAGE_MAP()

// CMainFrame コンストラクション/デストラクション

CMainFrame::CMainFrame()
{
	// TODO: メンバ初期化コードをここに追加してください。
}

CMainFrame::~CMainFrame()
{
}

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CFrameWndEx::OnCreate(lpCreateStruct) == -1)
		return -1;

	BOOL bNameValid;

	// すべてのユーザー インターフェイス要素の描画に使用される、ビジュアル マネージャを設定します
	CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));

	if (!m_wndMenuBar.Create(this))
	{
		TRACE0("メニュー バーを作成できませんでした\n");
		return -1;      // 作成できませんでした。
	}

	m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);

	// アクティブになったときメニュー バーにフォーカスを移動しない
	CMFCPopupMenu::SetForceMenuFocus(FALSE);

	// フレームのクライアント領域全体を占めるビューを作成します。
	if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
	{
		TRACE0("ビュー ウィンドウを作成できませんでした。\n");
		return -1;
	}

	//CString strToolBarName;
	//bNameValid = strToolBarName.LoadString(IDS_TOOLBAR_STANDARD);
	//ASSERT(bNameValid);
	//m_wndToolBar.SetWindowText(strToolBarName);

	//CString strCustomize;
	//bNameValid = strCustomize.LoadString(IDS_TOOLBAR_CUSTOMIZE);
	//ASSERT(bNameValid);
	//m_wndToolBar.EnableCustomizeButton(TRUE, ID_VIEW_CUSTOMIZE, strCustomize);

	// TODO: ツール バーおよびメニュー バーをドッキング可能にしない場合は、この 5 つの行を削除します
	m_wndMenuBar.EnableDocking(CBRS_ALIGN_ANY);
	//m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
	EnableDocking(CBRS_ALIGN_ANY);
	DockPane(&m_wndMenuBar);
	//DockPane(&m_wndToolBar);


	// Visual Studio 2005 スタイルのドッキング ウィンドウ動作を有効にします
	CDockingManager::SetDockingMode(DT_SMART);
	// Visual Studio 2005 スタイルのドッキング ウィンドウの自動非表示動作を有効にします
	EnableAutoHidePanes(CBRS_ALIGN_ANY);

	// ツール バーとドッキング ウィンドウ メニューの配置変更を有効にします
	//EnablePaneMenu(TRUE, ID_VIEW_CUSTOMIZE, strCustomize, ID_VIEW_TOOLBAR);

	// ツール バーのクイック (Alt キーを押しながらドラッグ) カスタマイズを有効にします
	CMFCToolBar::EnableQuickCustomization();

	return 0;
}

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	if( !CFrameWndEx::PreCreateWindow(cs) )
		return FALSE;
	// TODO: この位置で CREATESTRUCT cs を修正して Window クラスまたはスタイルを
	//  修正してください。

	cs.dwExStyle &= ~WS_EX_CLIENTEDGE;
	cs.lpszClass = AfxRegisterWndClass(0);
	return TRUE;
}

// CMainFrame 診断

#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
	CFrameWndEx::AssertValid();
}

void CMainFrame::Dump(CDumpContext& dc) const
{
	CFrameWndEx::Dump(dc);
}
#endif //_DEBUG


// CMainFrame メッセージ ハンドラ

void CMainFrame::OnSetFocus(CWnd* /*pOldWnd*/)
{
	// ビュー ウィンドウにフォーカスを与えます。
	m_wndView.SetFocus();
}

BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
	// ビューに最初にコマンドを処理する機会を与えます。
	if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
		return TRUE;

	// それ以外の場合は、既定の処理を行います。
	return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}

void CMainFrame::OnViewCustomize()
{
	CMFCToolBarsCustomizeDialog* pDlgCust = new CMFCToolBarsCustomizeDialog(this, TRUE /* メニューをスキャンします*/);
	pDlgCust->Create();
}

LRESULT CMainFrame::OnToolbarCreateNew(WPARAM wp,LPARAM lp)
{
	LRESULT lres = CFrameWndEx::OnToolbarCreateNew(wp,lp);
	if (lres == 0)
	{
		return 0;
	}

	CMFCToolBar* pUserToolbar = (CMFCToolBar*)lres;
	ASSERT_VALID(pUserToolbar);

	BOOL bNameValid;
	CString strCustomize;
	bNameValid = strCustomize.LoadString(IDS_TOOLBAR_CUSTOMIZE);
	ASSERT(bNameValid);

	pUserToolbar->EnableCustomizeButton(TRUE, ID_VIEW_CUSTOMIZE, strCustomize);
	return lres;
}


void CMainFrame::OnUdpholepunchingServer()
{
	CDlgInputSingleLine dlg;
	dlg.m_sInfo = _T("待ち受けポート番号");
	dlg.m_sText = _T("11801");
	if( dlg.DoModal() == IDOK ){
		boost::shared_ptr<CUdpHolepunching> sp(new CUdpHolepunching(boost::bind(&CChildView::OnMessage,&m_wndView,_1)));
		if( boost::optional<int> port = CRString::ToInt(dlg.m_sText) ){
			sp->Server(*port);
			m_setUdpHolepunching.insert(sp);
		}
	}
}

void CMainFrame::OnUdpholepunchingClient()
{
	CDlgInputSingleLine dlg;
	dlg.m_sInfo = _T("接続先");
	dlg.m_sText = _T("localhost:11801");
	if( dlg.DoModal() == IDOK ){
		boost::shared_ptr<CUdpHolepunching> sp(new CUdpHolepunching(boost::bind(&CChildView::OnMessage,&m_wndView,_1)));
		CParsedUrl r = ParseUrl(dlg.m_sText);
		if( r.nPort == 0 ) r = ParseUrl( _T("http://") +  dlg.m_sText);		// スキーム(HTTP)をつけて解釈を試みる
		const CString sPort = CRString::Format(_T("%d"),r.nPort);
		sp->Client( CStringA(r.sHostName).GetBuffer(0), CStringA(sPort).GetBuffer(0) );
		m_setUdpHolepunching.insert(sp);
	}
}
