// PWSChart.cpp : implementation file
//

#include "stdafx.h"
#include "PWSChart.h"

#include <pwsdata.hxx>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CPWSChart

CPWSChart::CPWSChart():
    m_pData( NULL ),
    m_period( PWS_CHART_HOURLY ),
    m_dataType( PWS_CHART_SESSIONS )
    {
    }

CPWSChart::~CPWSChart()
    {
    }

BEGIN_MESSAGE_MAP(CPWSChart, CStatic)
    //{{AFX_MSG_MAP(CPWSChart)
    ON_WM_PAINT()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

//------------------------------------------------------------------
void CPWSChart::DrawChart()
    {
    CDC* dc = GetDC();
    DrawChart( dc );
    ReleaseDC( dc );
    }

//------------------------------------------------------------------
void CPWSChart::OnPaint()
    {
    CPaintDC dc(this); // device context for painting

    // draw the chart
    DrawChart( &dc );
    }

#define NUM_ROWS        4

//------------------------------------------------------------------
DWORD CPWSChart::GetDataValue( DWORD i )
    {
    PPWS_DATA   pData = (PPWS_DATA)m_pData;
    // get the right thing
    switch( m_period )
        {
        case PWS_CHART_HOURLY:
            switch( m_dataType )
                {
                case PWS_CHART_SESSIONS:
                    return pData->rgbHourData[i].nTotalSessions;
                case PWS_CHART_HITS:
                    return pData->rgbHourData[i].nHits;
                case PWS_CHART_KB:
                    return pData->rgbHourData[i].nBytesSent;
                case PWS_CHART_HITS_PER_USER:
                    if ( !pData->rgbHourData[i].nTotalSessions )
                        return 0;
                    else
                        return pData->rgbHourData[i].nHits / pData->rgbHourData[i].nTotalSessions;
                case PWS_CHART_KB_PER_USER:
                    if ( !pData->rgbHourData[i].nTotalSessions )
                        return 0;
                    else
                        return pData->rgbHourData[i].nBytesSent / pData->rgbHourData[i].nTotalSessions;
                default:
                    return 0;
                };
            break;
        case PWS_CHART_DAILY:
            switch( m_dataType )
                {
                case PWS_CHART_SESSIONS:
                    return pData->rgbDayData[i].nTotalSessions;
                case PWS_CHART_HITS:
                    return pData->rgbDayData[i].nHits;
                case PWS_CHART_KB:
                    return pData->rgbDayData[i].nBytesSent;
                case PWS_CHART_HITS_PER_USER:
                    if ( !pData->rgbHourData[i].nTotalSessions )
                        return 0;
                    else
                        return pData->rgbDayData[i].nHits / pData->rgbDayData[i].nTotalSessions;
                case PWS_CHART_KB_PER_USER:
                    if ( !pData->rgbHourData[i].nTotalSessions )
                        return 0;
                    else
                        return pData->rgbDayData[i].nBytesSent / pData->rgbDayData[i].nTotalSessions;
                default:
                    return 0;
                };
            break;
        default:
            return 0;
        };
    return 0;
    }

//------------------------------------------------------------------
void CPWSChart::DrawChart( CDC* dc )
    {
    CRect   rectWindow, rectChart;
    CDC*    dcDraw = dc;
    DWORD   value;

    int     cpColWidth;
    int     cpRowHeight;
    int     xErr, xLeftover;
    CRect   rect, rectInterior;

    int     nNumColumns, i;

    if ( !m_pData ) 
    {
        return;
    }

    // cache the current time
    GetLocalTime( &m_timeCurrent );

    // prepare basic stuff
    GetClientRect( &rectWindow );
    rectWindow.bottom--;
    rectWindow.right--;

    rectChart = rectWindow;
    rectChart.DeflateRect( 1, 0 );
    rectChart.top += 1;

    //============= CALCULATIONS
    // now we calculate scale factors and the like

    // first, the period-based stuff
    switch( m_period )
        {
        case PWS_CHART_HOURLY:
            nNumColumns = 24;
            break;
        case PWS_CHART_DAILY:
            nNumColumns = 7;
            break;
        default:
            return;
        };

    // generic stuff
    int cpWindowWidth = rectChart.right - rectChart.left + 1;
    cpColWidth = cpWindowWidth / nNumColumns;
    xLeftover = cpWindowWidth % nNumColumns;
    cpRowHeight = (rectChart.bottom - rectChart.top) / NUM_ROWS;

    // figure out the maximum value of the data
    m_max = 0;
    for ( i = 0; i < nNumColumns; i++ )
        {
        DWORD data = GetDataValue(i);
        if ( data > m_max )
            m_max = data;
        };

    // create a floating point scaling factor for the y value;
    float yFactor;
    if ( m_max )
        yFactor = (float)(rectChart.bottom - rectChart.top ) / m_max;

    //============= DRAWING!

    // start by blanking out the background of the chart
    dcDraw->FillSolidRect( &rectWindow, GetSysColor(COLOR_APPWORKSPACE) );

    // prepare the data rect
    rect.left = rectChart.left;
    rect.right = rect.left + cpColWidth;
    rect.bottom = rectChart.bottom;
    xErr = 0;

    // the bars
    if ( m_max )
        {
        for ( i = 0; i < nNumColumns; i++ )
            {
            // only draw something if there is a value there
            value = GetDataValue(i);
            if ( !value )
                {
                goto increment;
                }

            // build the rectangle to fill
            rect.top = (int)((float)rectWindow.bottom - 1.0 - ((float)GetDataValue(i) * yFactor));

            // draw the data bar
            dcDraw->Draw3dRect( rect, GetSysColor(COLOR_3DHILIGHT), GetSysColor(COLOR_3DSHADOW) );
            // fill in the data bar
            rectInterior = rect;
            rectInterior.DeflateRect( 1, 1 );
            dcDraw->FillSolidRect( rectInterior, GetSysColor(COLOR_3DFACE) );

            // increment stuff
    increment:
            rect.left = rect.right;
            // account for the error factor
            xErr += xLeftover;
            if ( xErr > nNumColumns )
                {
                rect.right++;
                xErr -= nNumColumns;
                }
            rect.right += cpColWidth;
            }
        }
    }