#include <GDI.h>
#include <math.h>
#include <aygshell.h>
#include <stdlib.h>
#include <strtool.h>
#include <graphics/bitmap.h>

#include "MainFrm.h"
#include "resource.h"

CMainFrame::CMainFrame()
{
    // Set the Resource IDs for the toolbar buttons
    m_ToolbarData.clear();
    m_ToolbarData.push_back(0);         // Separator
    gps = NULL;
    log = NULL;
    dp = NULL;
    currTrap = NULL;
    showInfo = false;
    lastD = 10000;
    simGPS = NULL;
}

CMainFrame::~CMainFrame()
{
    if (timerId > 0)
        KillTimer(m_hWnd, timerId);
    if (simGPS)
        fclose(simGPS);
    
    if (dp)
        dp->close();
    if (gps)
        delete gps;
    gps = NULL;
    if (log)
    {
        fflush(log);
        fclose(log);
    }
}

BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM /*lParam*/)
{
    switch (LOWORD(wParam))
    {
        case IDM_HELP_ABOUT:
        {
            CDialog HelpDialog(IDW_ABOUT, m_hWnd);
            HelpDialog.DoModal();
        }
        break;

        // Respond to the accelerator key
        case IDW_QUIT:
            ::SendMessage(m_hWnd, WM_CLOSE, 0, 0);
            break;
    }

    return 0;
}

void CMainFrame::startGPS()
{
    log = fopen("\\Storage Card\\gpslog.txt", "wt");
    fprintf(log, "Start\n");
    gps = new GPS("COM4", 9600);
    gps->setNotifyWindow(m_hWnd);
    gps->setLogFile(log);
    timerId = 0;
    if (!gps->OpenConnection())
    {
        MessageBox(m_hWnd, L"Cannot open GPS port", L"Error", MB_OK | MB_ICONSTOP);
        
        simGPS = fopen("\\Storage Card\\in.gps", "rt");
        timerId = 1000;
        SetTimer(m_hWnd, timerId, 500, NULL);
        //::PostQuitMessage(0);
    }
}

void CMainFrame::OnInitialUpdate()
{
    SHFullScreen(m_hWnd, SHFS_HIDESIPBUTTON);
    startGPS();
    dp = &DataProvider::getInstance();
    dp->setLog(log);
}

void CMainFrame::setFont(CDC& dc, WCHAR* face, int ptsize, bool bold, bool italic)
{
    LOGFONT font;
    font.lfHeight = (-ptsize * GetDeviceCaps(dc, LOGPIXELSY)) / 72; 
    font.lfWidth = 0; 
    font.lfEscapement = 0; 
    font.lfOrientation = 0; 
    font.lfWeight = bold ? FW_BOLD : FW_NORMAL; 
    font.lfItalic = italic; 
    font.lfUnderline = false; 
    font.lfStrikeOut = false; 
    font.lfCharSet = DEFAULT_CHARSET; 
    font.lfOutPrecision = OUT_DEFAULT_PRECIS; 
    font.lfClipPrecision = CLIP_DEFAULT_PRECIS; 
    font.lfQuality = ANTIALIASED_QUALITY; 
    font.lfPitchAndFamily = FF_SWISS | DEFAULT_PITCH; 
    wcscpy(font.lfFaceName, face);
    dc.CreateFontIndirect(&font);
}

int CMainFrame::getIconId(int type, int speed)
{
    int id = 0;
    
    if (type == CT_SPEEDCTRL)
    {
        switch (speed)
        {
            case 20:
                id = IDB_SPEED20;
                break;
            case 30:
                id = IDB_SPEED30;
                break;
            case 40:
                id = IDB_SPEED40;
                break;
            case 50:
                id = IDB_SPEED50;
                break;
            case 60:
                id = IDB_SPEED60;
                break;
            case 70:
                id = IDB_SPEED70;
                break;
            case 80:
                id = IDB_SPEED80;
                break;
            case 90:
                id = IDB_SPEED90;
                break;
            case 100:
                id = IDB_SPEED100;
                break;
            case 110:
                id = IDB_SPEED110;
                break;
            case 120:
                id = IDB_SPEED120;
                break;
            case 130:
                id = IDB_SPEED130;
                break;
        }
    }
    else if (type == CT_REDLIGHTCTRL)
        id = IDB_REDLIGHT;
    else if (type == CT_BUSLANECTRL)
        id = IDB_BUSLANE;
    
    return id;
}

void CMainFrame::drawSpeedTrapInfo(CDC& dc, int w)
{
    wchar_t tmp[32];
    
    CRect vr = GetViewRect();
    
    CRect sar = CRect(w/2 - 100, vr.top + 16, w/2 + 100, vr.top + 64);
    Win32xx::SolidFill(dc, RGB(128, 128, 128), &sar);
    if (currTrap && showInfo)
    {
        Graphics::Bitmap bkg(m_hWnd, vr.left + 24, vr.top + 20, 40, 40);
        
        int iconId = getIconId(currTrap->getType(), currTrap->getSpeed());
        if (iconId)
        {
            Graphics::Bitmap sign(LoadBitmap(MAKEINTRESOURCE(iconId)));
            bkg.getBits();
            bkg.blend(sign, 0, 0, 254, 0x00808080);
            bkg.drawBits(dc, vr.left + 24, vr.top + 20);
        }        
        setFont(dc, TEXT("Arial"), 20, false, false);
        SetTextColor(dc, RGB(255, 255, 255));
        SetBkMode(dc, TRANSPARENT);
        CRect dr = CRect(vr.left + 68, vr.top + 22, w/2 + 100 - 4, vr.top + 58);
        wsprintf(tmp, L"%d m", (int)lastD);
        ::DrawText(dc, tmp, wcslen(tmp), &dr, DT_LEFT | DT_TOP);

        HFONT hFont = dc.DetachFont();
        DeleteObject(hFont);
    }
}

void CMainFrame::OnPaint(HDC hDC)
{
    WCHAR temp[256];
    Win32xx::GradientFill(hDC, RGB(0, 0, 128), RGB(0, 128, 255), GetViewRect(), true);
    
    CRect vr = GetViewRect();
    CDC dc(hDC);
    int w = vr.right - vr.left;
    
    drawSpeedTrapInfo(dc, w);
        
    Graphics::Bitmap bkg(m_hWnd, w/2 - 100, vr.top + 70, 200, 64);
    Graphics::Bitmap sbkg(LoadBitmap(MAKEINTRESOURCE(IDB_SPEEDBKG)));
    bkg.getBits();
    bkg.blend(sbkg, 0, 0, 80, 0x00000000);
    bkg.drawBits(hDC, w/2 - 100, vr.top + 70);
    
    setFont(dc, TEXT("Arial"), 40, true, false);
    
    int lh = 60;
    int cy = vr.top + 70;
    
    SetBkMode(hDC, TRANSPARENT);
    if (currTrap != NULL && currTrap->getType() == CT_SPEEDCTRL && 
        currTrap->getSpeed() < gpsInfo.speed)
        SetTextColor(hDC, RGB(255, 0, 0));
    else
        SetTextColor(hDC, RGB(255, 255, 255));
    
    CRect dr = CRect(w/2 - 100 + 8, cy, w/2 + 20 - 8, cy + lh);
    wsprintf(temp, L"%d", (int)(gpsInfo.speed + 0.5));
    ::DrawText(hDC, temp, wcslen(temp), &dr, DT_RIGHT | DT_TOP);

    HFONT hFont = dc.DetachFont();
    DeleteObject(hFont);

    setFont(dc, TEXT("Arial"), 20, false, false);

    SetTextColor(hDC, RGB(255, 255, 255));
    dr = CRect(w/2 + 20 + 8, cy + 26, vr.right - 8, cy + lh);
    ::DrawText(hDC, L"km/h", 4, &dr, DT_LEFT | DT_TOP);
       
    hFont = dc.DetachFont();
    DeleteObject(hFont);
}

LRESULT CMainFrame::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    // handle left mouse button up/down and mouse move messages
    // a seperate function for each case keeps the code tidy.
    switch (uMsg)
    {
        case WM_GPS:
    	    updateGPS();
            break;
        case WM_TIMER:
            simulateGPSInput();
            break;
    }

    // Pass unhandled messages on to WndProcDefault
    return WndProcDefault(hwnd, uMsg, wParam, lParam);
}

void CMainFrame::simulateGPSInput()
{
    char s[256];
    
    if (fgets(s, sizeof(s), simGPS))
    {
        gps->simulateInput(s);
        if (gps->getDataValid())
            SendMessage(m_hWnd, WM_GPS, 0, 0);
    }
    else
    {
        KillTimer(m_hWnd, timerId);
        fclose(simGPS);
        simGPS = NULL;
        timerId = 0;
    }
}

void CMainFrame::updateGPS()
{
    static int lastId = -1;
    static float prevD = 10000;

    float lon = gps->getLongitude();
    float lat = gps->getLatitude();
    float d;

    currTrap = dp->getNearestSpeedTrap(lon, lat, 500, d);
    
    if (currTrap != NULL)
    {
        if (currTrap->getId() != lastId)
        {
            lastId = currTrap->getId();
            showInfo = true;
        }
        else
        {
            showInfo = d <= prevD;
        }
        prevD = lastD;
        lastD = d;
        if (log)
            fprintf(log, "Spped trap %d (%d km/h), in %d m\n", currTrap->getId(), 
                currTrap->getSpeed(), (int)d);
    }
    else
    {
        lastD = 10000;
        lastId = -1;
    }

    gpsInfo.speed = gps->getVelocity();
    gpsInfo.course = gps->getCourse();

    InvalidateRect((LPRECT)GetClientRect(), FALSE);
}

