//!
/**
 **************************************************************************************************************************************************************
 * Bot-Strike MFC renderer
 **************************************************************************************************************************************************************
 * @file   Main.cpp
 * @author Cyanide
 **************************************************************************************************************************************************************/

/**************************************************************************************************************************************************************
 * Bot-Strike MFC renderer defines
 **************************************************************************************************************************************************************/

#include <list>

// certains constructeurs CString seront explicites
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS

#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN            // Exclure les en-t黎es Windows rarement utilisés
#endif

#ifndef WINVER                  // Autorise l'utilisation des fonctionnalités spécifiques à Windows95 et Windows NT4 ou version ultérieure.
#define WINVER 0x0400           // Attribuez la valeur appropriée à cet élément pour cibler Windows98 et Windows2000 ou version ultérieure.
#endif

#ifndef _WIN32_WINNT            // Autorise l'utilisation des fonctionnalités spécifiques à Windows NT4 ou version ultérieure.
#define _WIN32_WINNT 0x0400     // Attribuez la valeur appropriée à cet élément pour cibler Windows2000 ou version ultérieure.
#endif                        

#ifndef _WIN32_WINDOWS          // Autorise l'utilisation des fonctionnalités spécifiques à Windows98 ou version ultérieure.
#define _WIN32_WINDOWS 0x0410   // Attribuez la valeur appropriée à cet élément pour cibler WindowsMe ou version ultérieure.
#endif

#ifndef _WIN32_IE               // Autorise l'utilisation des fonctionnalités spécifiques à IE4.0 ou version ultérieure.
#define _WIN32_IE 0x0400        // Attribuez la valeur appropriée à cet élément pour cibler IE5.0 ou version ultérieure.
#endif

#include <afxwin.h>             // Composants MFC principaux et standard
#include <afxext.h>             // Extensions MFC

#ifndef _AFX_NO_OLE_SUPPORT
#include <afxole.h>             // Classes OLE MFC
#include <afxodlgs.h>           // Classes de boîte de dialogue OLE MFC
#include <afxdisp.h>            // Classes MFC Automation
#endif

#ifndef _AFX_NO_DB_SUPPORT
#include <afxdb.h>              // Classes de base de données ODBC MFC
#endif

#ifndef _AFX_NO_DAO_SUPPORT
#include <afxdao.h>             // Classes de base de données DAO MFC
#endif

#include <afxdtctl.h>           // Prise en charge des MFC pour les contrôles communs Internet Explorer 4
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>             // Prise en charge des MFC pour les contrôles communs Windows
#endif

/**************************************************************************************************************************************************************
 * Resources
 **************************************************************************************************************************************************************/

#include "Resource.h"

/**
 **************************************************************************************************************************************************************
 * Bot-Strike MFC renderer Application
 **************************************************************************************************************************************************************/
class CRendererMfcApp : public CWinApp
{
public:
                 CRendererMfcApp ();
    virtual BOOL InitInstance    ();

    DECLARE_MESSAGE_MAP()
};

/**
 **************************************************************************************************************************************************************
 * Only one application instance
 **************************************************************************************************************************************************************/
CRendererMfcApp theApp;

/**
 **************************************************************************************************************************************************************
 * Bot-Strike MFC renderer Application main frame
 **************************************************************************************************************************************************************/
class CRendererMfcMainFrame : public CFrameWnd
{
public:
                 CRendererMfcMainFrame ();
    virtual     ~CRendererMfcMainFrame ();
    virtual BOOL PreCreateWindow       (CREATESTRUCT& cs);

    DECLARE_MESSAGE_MAP()
    DECLARE_DYNCREATE(CRendererMfcMainFrame)

#ifdef _DEBUG

    virtual void AssertValid() const;
    virtual void Dump(CDumpContext& dc) const;

#endif
};

/**
 **************************************************************************************************************************************************************
 * Bot-Strike MFC renderer Application document
 **************************************************************************************************************************************************************/
class CRendererMfcDoc : public CDocument
{
public:

                 CRendererMfcDoc ();
    virtual     ~CRendererMfcDoc ();
    virtual BOOL OnNewDocument   ();
    virtual void Serialize       (CArchive& ar);

    DECLARE_MESSAGE_MAP()
    DECLARE_DYNCREATE(CRendererMfcDoc)

#ifdef _DEBUG

    virtual void AssertValid() const;
    virtual void Dump(CDumpContext& dc) const;

#endif
};

/**
 **************************************************************************************************************************************************************
 * Bot-Strike MFC renderer Application document view
 **************************************************************************************************************************************************************/
class CRendererMfcView : public CView
{
public:

                 CRendererMfcView ();
	virtual     ~CRendererMfcView ();
    virtual void OnDraw           (CDC* pDC);
	virtual BOOL PreCreateWindow  (CREATESTRUCT& cs);

	CRendererMfcDoc* GetDocument  () const;

    DECLARE_MESSAGE_MAP()
	DECLARE_DYNCREATE(CRendererMfcView)

#ifdef _DEBUG

    virtual void AssertValid() const;
    virtual void Dump(CDumpContext& dc) const;

#endif
};

/**************************************************************************************************************************************************************/

#ifndef _DEBUG

inline CRendererMfcDoc* CRendererMfcView::GetDocument() const
{
    return reinterpret_cast<CRendererMfcDoc*>(m_pDocument);
}

#endif

/**************************************************************************************************************************************************************
 * Includes
 **************************************************************************************************************************************************************/

#include "BotStrike.h"

#include <iostream>
#include <list>
#include <string>

/**************************************************************************************************************************************************************
 * Implementation
 **************************************************************************************************************************************************************/

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

/**************************************************************************************************************************************************************
 * Bot-Strike MFC renderer magical stuff
 **************************************************************************************************************************************************************/

IMPLEMENT_DYNCREATE(CRendererMfcDoc,       CDocument)
IMPLEMENT_DYNCREATE(CRendererMfcMainFrame, CFrameWnd)
IMPLEMENT_DYNCREATE(CRendererMfcView,      CView)

/**************************************************************************************************************************************************************
 * Application messages
 **************************************************************************************************************************************************************/

BEGIN_MESSAGE_MAP(CRendererMfcApp, CWinApp)

    ON_COMMAND(ID_FILE_NEW,  CWinApp::OnFileNew)
    ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)

END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP(CRendererMfcDoc, CDocument)
END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP(CRendererMfcMainFrame, CFrameWnd)
END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP(CRendererMfcView, CView)
END_MESSAGE_MAP()

/**************************************************************************************************************************************************************
 * CRendererMfcApp
 **************************************************************************************************************************************************************/

CRendererMfcApp::CRendererMfcApp()
{
}

/**************************************************************************************************************************************************************/

BOOL CRendererMfcApp::InitInstance()
{
    CWinApp::InitInstance();

    // Initialize OLE libraries
    if (!AfxOleInit())
    {
        AfxMessageBox(IDP_OLE_INIT_FAILED);
        return FALSE;
    }
    AfxEnableControlContainer();

    // Standard initialization
    // If you are not using these features and wish to reduce the size
    // of your final executable, you should remove from the following
    // the specific initialization routines you do not need
    // Change the registry key under which our settings are stored
    // TODO: You should modify this string to be something appropriate
    // such as the name of your company or organization

    SetRegistryKey(_T("Bot-Strike"));

    LoadStdProfileSettings(4);  // Load standard INI file options (including MRU)

    // Register the application's document templates.  Document templates
    //  serve as the connection between documents, frame windows and views

    CSingleDocTemplate* pDocTemplate;

    pDocTemplate = new CSingleDocTemplate
    (
        IDR_MAINFRAME,
        RUNTIME_CLASS(CRendererMfcDoc),
        RUNTIME_CLASS(CRendererMfcMainFrame), // main SDI frame window
        RUNTIME_CLASS(CRendererMfcView)
    );

    AddDocTemplate(pDocTemplate);
    
    // Enable DDE Execute open
    EnableShellOpen();
    RegisterShellFileTypes(TRUE);
    
    // Parse command line for standard shell commands, DDE, file open
    CCommandLineInfo cmdInfo;
    ParseCommandLine(cmdInfo);

    // Dispatch commands specified on the command line.  Will return FALSE if
    // app was launched with /RegServer, /Register, /Unregserver or /Unregister.
    if (!ProcessShellCommand(cmdInfo))
        return FALSE;

    // The one and only window has been initialized, so show and update it

    m_pMainWnd->MoveWindow(0,0,600,800);
    m_pMainWnd->ShowWindow(SW_SHOW);
    m_pMainWnd->UpdateWindow();

    // call DragAcceptFiles only if there's a suffix
    // In an SDI app, this should occur after ProcessShellCommand
    // Enable drag/drop open
    m_pMainWnd->DragAcceptFiles();

    return TRUE;
}

/**************************************************************************************************************************************************************/

CRendererMfcDoc::CRendererMfcDoc()
{
}

CRendererMfcDoc::~CRendererMfcDoc()
{
}

BOOL CRendererMfcDoc::OnNewDocument()
{
    return TRUE == CDocument::OnNewDocument();
}

void CRendererMfcDoc::Serialize(CArchive& ar)
{
    if (ar.IsStoring()) {} else {}
}

#ifdef _DEBUG

void CRendererMfcDoc::AssertValid() const
{
    CDocument::AssertValid();
}

void CRendererMfcDoc::Dump(CDumpContext& dc) const
{
    CDocument::Dump(dc);
}

#endif

/**************************************************************************************************************************************************************/

CRendererMfcMainFrame::CRendererMfcMainFrame()
{
}

CRendererMfcMainFrame::~CRendererMfcMainFrame()
{
}

BOOL CRendererMfcMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    if (!CFrameWnd::PreCreateWindow(cs)) return FALSE;

    cs.hMenu = 0;
    cs.style = WS_OVERLAPPED | WS_CAPTION | FWS_ADDTOTITLE | WS_THICKFRAME | WS_MINIMIZEBOX;

    return TRUE;
}

#ifdef _DEBUG

void CRendererMfcMainFrame::AssertValid() const
{
    CFrameWnd::AssertValid();
}

void CRendererMfcMainFrame::Dump(CDumpContext& dc) const
{
    CFrameWnd::Dump(dc);
}

#endif

/**************************************************************************************************************************************************************/

CRendererMfcView::CRendererMfcView()
{
}

CRendererMfcView::~CRendererMfcView()
{
}

BOOL CRendererMfcView::PreCreateWindow(CREATESTRUCT& cs)
{
    return CView::PreCreateWindow(cs);
}

void CRendererMfcView::OnDraw(CDC*)
{
    CRendererMfcDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
}

#ifdef _DEBUG

void CRendererMfcView::AssertValid() const
{
    CView::AssertValid();
}

void CRendererMfcView::Dump(CDumpContext& dc) const
{
    CView::Dump(dc);
}

CRendererMfcDoc* CRendererMfcView::GetDocument() const
{
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CRendererMfcDoc)));
    return (CRendererMfcDoc*)m_pDocument;
}

#endif

/**
 **************************************************************************************************************************************************************
 * DLL entry point
 **************************************************************************************************************************************************************/
DLL_EXPORT void render(BS::CMessage& msg)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    static std::list<std::string> chat;
    
    if (theApp.m_pMainWnd)
    {
        theApp.m_pMainWnd->SetActiveWindow();
        theApp.m_pMainWnd->ShowWindow(SW_SHOW);
        theApp.m_pMainWnd->UpdateWindow();
    }

    static CClientDC* pDC = 0;

    static const int W         = 600;
    static const int H         = 800;
    static const int text_dy   = 20;
    static const int text_y0   = 550;
	static const int CHAT_SIZE = 8;

    static CRect linerect(0,text_y0,W,text_y0+text_dy);
    
    if (!pDC)
    {
        POSITION          posDocTmp    = theApp.GetFirstDocTemplatePosition();          if (!posDocTmp)    return;    
        CDocTemplate*     pDocTemplate = theApp.GetNextDocTemplate(posDocTmp);          if (!pDocTemplate) return;    
        POSITION          posDoc       = pDocTemplate->GetFirstDocPosition();           if (!posDoc)       return;    
        CDocument*        pDoc         = pDocTemplate->GetNextDoc(posDoc);              if (!pDoc)         return;
        POSITION          posView      = pDoc->GetFirstViewPosition();                  if (!posView)      return;    
        CRendererMfcView* pView        = (CRendererMfcView*)pDoc->GetNextView(posView); if (!pView)        return;
        
        pDC = new CClientDC(pView);

        if (!pDC) return;
    }

    switch(msg.type)
    {    
        case BS::EMessage::Renderer::Init :
        {
            pDC->FillSolidRect(0,0,W,H,RGB(255,255,255));
            pDC->DrawText("MFC renderer intitialized", &linerect, DT_LEFT);
            break;
        }
 
        case BS::EMessage::Renderer::Release :
        {
			delete pDC;
            break;
        }

        case BS::EMessage::Renderer::Text :
        {
            if (msg.str && strlen(msg.str)>0)
            {
                if (chat.size() > CHAT_SIZE) chat.pop_front();
                chat.push_back(msg.str);

                if (linerect.top < H)
                {
                    pDC->FillSolidRect(&linerect, RGB(255,255,255));
                    pDC->DrawText(msg.str, &linerect, DT_LEFT);

                    linerect.top    += text_dy;
                    linerect.bottom += text_dy;
                }
            }

            break;
        }

        case BS::EMessage::Renderer::Arena :
        {
            static COLORREF RGB_BACK    = RGB(171, 180,  90);
            static COLORREF RGB_BOX     = RGB(153,  95,   1);
            static COLORREF RGB_DEAD    = RGB(200, 200, 200);
            static COLORREF RGB_BLUE    = RGB( 61, 120, 153);
            static COLORREF RGB_RED     = RGB(153,  11,  11);
            static COLORREF RGB_BULLET  = RGB(  0,   0,   0);
            static COLORREF RGB_GRENADE = RGB(105, 158,  85);

            CRect arenarect(0,0,W,W);

            int dx = (int)((float)W / (float)(1+msg.arena.width));
            int dy = (int)((float)W / (float)(1+msg.arena.height));

            for (int y0=0; y0<msg.arena.height; ++y0)
            for (int x0=0; x0<msg.arena.width;  ++x0)
            {
                int x = x0 * dx;
                int y = y0 * dy;

				int dx2 = dx / 2;
				int dy2 = dy / 2;
				int dx4 = dx / 4;
				int dy4 = dy / 4;

                if (msg.arena.cell(x0,y0) & BS::ECell::Grenade)
                {
                    pDC->FillSolidRect(x,y,dx,dy,RGB_BACK);
                    pDC->FillSolidRect(x,y, dx, dx,RGB_GRENADE);
                }
                else if (msg.arena.cell(x0,y0) & BS::ECell::Bullet)
                {
                    pDC->FillSolidRect(x,y,dx,dy,RGB_BACK);
                    pDC->FillSolidRect(x+dx2-2,y+dy2-2, 4, 4,RGB_BULLET);
                }
                else if ((msg.arena.cell(x0,y0) & BS::ECell::Blue) ||
                         (msg.arena.cell(x0,y0) & BS::ECell::Red)  )
                {
                    if (msg.arena.cell(x0,y0) & BS::ECell::Blue)
                    {
                        pDC->FillSolidRect(x,y,dx,dy,RGB_BLUE);
                    }
                    else
                    {
                        pDC->FillSolidRect(x,y,dx,dy,RGB_RED);
                    }

					int botdx=0;
					int botdy=0;

                    msg.arena.orientation(x0,y0,botdx,botdy);

					pDC->FillSolidRect(x+dx4+botdx*dx4, y+dy4+botdy*dy4, dx2, dy2, RGB(0,0,0));
                }
                else if (msg.arena.cell(x0,y0) & BS::ECell::Box)
                {
                    pDC->FillSolidRect(x,y,dx,dy,RGB_BOX);
                }
                else  if (msg.arena.cell(x0,y0) & BS::ECell::Cadavre)
                {
                    pDC->FillSolidRect(x,y,dx,dy,RGB_DEAD);
                }
                else
                {
                    pDC->FillSolidRect(x,y,dx,dy,RGB_BACK);
                }
            }

            if (msg.str && strlen(msg.str)>0)
            {
                if (chat.size() > CHAT_SIZE) chat.pop_front();
                chat.push_back(msg.str);
            }

            linerect.top    = text_y0;
            linerect.bottom = text_y0+text_dy;

            for (std::list<std::string>::iterator it=chat.begin(); it!=chat.end(); ++it)
            {
                pDC->FillSolidRect(&linerect, RGB(255,255,255));
                pDC->DrawText(it->c_str(), &linerect, DT_LEFT);

                linerect.top    += text_dy;
                linerect.bottom += text_dy;
            }

			//Sleep(50);

            break;
        }
    }

    if (theApp.m_pMainWnd)
    {
        theApp.m_pMainWnd->SetActiveWindow();
        theApp.m_pMainWnd->ShowWindow(SW_SHOW);
        theApp.m_pMainWnd->UpdateWindow();
    }
}

/**************************************************************************************************************************************************************/
