/*******************************************************************************
*
*  (C) COPYRIGHT MICROSOFT CORP., 1993-1995
*  TITLE:       FUELBAR.CPP
*  VERSION:     1.0
*  AUTHOR:      jsenior
*  DATE:        10/28/1998
*
********************************************************************************
*
*  CHANGE LOG:
*
*  DATE       REV     DESCRIPTION
*  ---------- ------- ----------------------------------------------------------
*  10/28/1998 jsenior Original implementation.
*
*******************************************************************************/
#include "FuelBar.h"
#include "debug.h"
#include <assert.h>

const int FuelBar::NoImage = -1;
const LPVOID FuelBar::NoID = (const LPVOID) -1;

FuelBar::FuelBar() : currentTotalValue(0), highlightID(NoID), 
    maxValue(100), calcRects(FALSE), hImageList(0)
{
    GetSysColors(); 
}

FuelBar::~FuelBar()
{
    Clear();
}

BOOL FuelBar::SubclassDlgItem( UINT nID, HWND hParent)
{
    hwnd = GetDlgItem(hParent, nID);

    FuelSetWindowLongPtr(hwnd, FUELGWLP_USERDATA, (FUELLONG_PTR) this);
    prevWndProc = (WNDPROC) FuelSetWindowLongPtr(hwnd, 
                                              FUELGWLP_WNDPROC,
                                              (FUELDWORD_PTR) StaticWndProc); 

    return TRUE;
}

UINT FuelBar::AddItem(UINT Value, LPVOID ID, int ImageIndex)
{
    FuelBarItem item;

    if (!Value)
        return 0;

    if (currentTotalValue + Value > maxValue)
        return 0;

    currentTotalValue += Value;
    
    item.value = Value;
    item.id = ID;
    item.imageIndex = ImageIndex;
    items.push_back(item);

    calcRects = TRUE;

    return currentTotalValue;
}

BOOL FuelBar::RemoveItem(LPVOID ID)
{
    if (highlightID == ID) {
        highlightID = (LPVOID) NoID;
    }

    FuelBarItem *item;

    for (item = items.begin(); item; item = items.next()) {
        if (item->id == ID) {
            items.eraseCurrent();
 
            return TRUE;
        }
    }

    return FALSE;
}

void FuelBar::ClearItems()
{
    Clear();
    InvalidateRect(hwnd, NULL, TRUE);
}

BOOL FuelBar::HighlightItem(LPVOID ID)
{
    // do nothing if the id is the same
    if (ID == highlightID)
        return TRUE;

    FuelBarItem *item;

    highlightID = 0;
    //
    // Make sure that ID is indeed a member
    //
    for (item = items.begin(); item; item = items.next()) {
        if (item->id == ID) {
            highlightID = ID;
            break;
        }
    }

    // the total redrawing of the ctrl will erase the old and draw the new
    InvalidateRect(hwnd, NULL, FALSE);
    
    if (ID != highlightID) {
        return FALSE;
    }

    return TRUE;
}

void FuelBar::Clear()
{
    items.clear();
    currentTotalValue = 0;
    calcRects = TRUE;
}

void FuelBar::CalculateRects(const RECT& ClientRect)
{
    FuelBarItem *item, *prevItem;

    if (items.empty()) {
        calcRects = FALSE;
        return;
    }

    item = items.begin();
    item->rect = ClientRect;
    item->rect.right = ClientRect.left + 1 +
                       (item->value * (ClientRect.right - ClientRect.left))/maxValue;

    prevItem = item;
    for (item = items.next(); item; item = items.next()) {

        item->rect.top = prevItem->rect.top;
        item->rect.bottom = prevItem->rect.bottom;
        item->rect.left = prevItem->rect.right;
        // Fill rect does not render the outside edge
        item->rect.right = item->rect.left  + 1 +
                           (item->value * (ClientRect.right - ClientRect.left))/maxValue;
    
        prevItem = item;
    }

    // make sure that if the bar is full, that the last item is rendered to
    // the edge of the entire bar
    if (currentTotalValue == maxValue)
        item->rect.right = ClientRect.right;

    calcRects = FALSE;
}

void FuelBar::SetImageList(HIMAGELIST ImageList)
{
    IMAGEINFO imageInfo;
    
    hImageList = ImageList;

    ZeroMemory(&imageInfo, sizeof(IMAGEINFO));
    
    if (ImageList_GetImageInfo(hImageList, 0, &imageInfo)) {
        imageWidth = imageInfo.rcImage.right - imageInfo.rcImage.left;
        imageHeight = imageInfo.rcImage.bottom - imageInfo.rcImage.top;
    }
    else {
        assert(FALSE);
    }

}

void FuelBar::GetSysColors()
{
    colorFace = GetSysColor(COLOR_3DFACE);
    colorLight = GetSysColor(COLOR_3DHILIGHT);
    colorDark = GetSysColor(COLOR_3DSHADOW);
    colorUnused = GetSysColor(COLOR_WINDOW);
}

/////////////////////////////////////////////////////////////////////////////
// FuelBar message handlers

void FillSolidRect(HDC dc,
                   LPCRECT rect,
                   COLORREF color)
{
    SetBkColor(dc, color);
    ExtTextOut(dc, 0, 0, ETO_OPAQUE, rect, NULL, 0, NULL);
}

void FillSolidRect(HDC dc, int x, int y, int cx, int cy, COLORREF color)
{
    RECT rect;

    rect.left = x;
    rect.right = x + cx;
    rect.top = y;
    rect.bottom = y + cy;

    SetBkColor(dc, color);
    ExtTextOut(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
}

void Draw3dRect(HDC dc, 
                int x, 
                int y, 
                int cx, 
                int cy,
                COLORREF clrTopLeft, 
                COLORREF clrBottomRight, 
                COLORREF clrFace)
{
    FillSolidRect(dc, x, y, cx - 1, 1, clrTopLeft);
    FillSolidRect(dc, x, y, 1, cy - 1, clrTopLeft);
    FillSolidRect(dc, x + cx, y, -1, cy, clrBottomRight);
    FillSolidRect(dc, x, y + cy, cx, -1, clrBottomRight);
    FillSolidRect(dc, x+1, y+1, cx-2, cy-2, clrFace) ;
}

void FuelBar::OnPaint() 
{
    HDC dc; 
    PAINTSTRUCT ps;
    RECT clientRect, *highlightRect, remainingRect;
    POINT pt;
    FuelBarItem *item, *prevItem;
    
    HBRUSH hBrush, hOldBrush;

    BOOL highlightFound = FALSE;

    dc = BeginPaint(hwnd, &ps);

    hBrush = CreateSolidBrush(colorFace);
    hOldBrush = (HBRUSH) SelectObject(dc, hBrush);

    GetClientRect(hwnd, &clientRect);

    FillSolidRect(dc, &clientRect, colorUnused);
    
    if (calcRects) {
        CalculateRects(clientRect);
//        FillSolidRect(dc, &clientRect, colorFace);
    }

    for (item = items.begin(); item; item = items.next()) {
        Draw3dRect(dc,
                   item->rect.left,
                   item->rect.top,
                   item->rect.right - item->rect.left,
                   item->rect.bottom - item->rect.top,
                   colorLight,
                   colorDark,
                   colorFace);

        if (item->imageIndex != NoImage && 
            (item->rect.right - item->rect.left) > imageWidth) {
            
            // render the image in the center of the rectangle
            pt.x = item->rect.left + 
                   (item->rect.right - item->rect.left)/2 - (imageWidth)/2;
            pt.y = (item->rect.bottom - item->rect.top)/2 - (imageHeight)/2;
            ImageList_Draw(hImageList, 
                           item->imageIndex, 
                           dc,
                           pt.x,
                           pt.y,
                           ILD_TRANSPARENT);
        }
         
        if (item->id == highlightID) {
            highlightRect = &item->rect;
            highlightFound = TRUE;
        }
        prevItem = item;
    }

    if (currentTotalValue < maxValue) {
        remainingRect = clientRect;
        if (!items.empty())
            remainingRect.left = prevItem->rect.right;

        FillSolidRect(dc, &remainingRect, colorUnused);
    }

    SelectObject(dc, hOldBrush);

    if (highlightFound) {

        // CPen pen(PS_SOLID, 1, RGB(0,0,0)), *oldPen;
        // oldPen = dc.SelectObject(&pen);
        HPEN hPen, hOldPen;
        
        hPen = CreatePen(PS_SOLID, 1, RGB(0,0,0));
        if (hPen) {
            hOldPen = (HPEN) SelectObject(dc, hPen);
            MoveToEx(dc, highlightRect->left, highlightRect->top, NULL);
            LineTo(dc, highlightRect->right-1, highlightRect->top);
            LineTo(dc, highlightRect->right-1, highlightRect->bottom-1);
            LineTo(dc, highlightRect->left, highlightRect->bottom-1);
            LineTo(dc, highlightRect->left, highlightRect->top);
            // dc.DrawFocusRect instead?

            SelectObject(dc, hOldPen);
            DeleteObject(hPen);
        }
    }

    EndPaint(hwnd, &ps);

    DeleteObject(hBrush);
    ValidateRect(hwnd, &clientRect);
}

BOOL FuelBar::OnToolTipNotify(UINT id, NMHDR * pNMHDR, LRESULT * pResult)
{    
    BOOL bHandledNotify = FALSE;
#ifdef TOOL
    CPoint cursorPos;
    CRect clientRect;
    VERIFY(::GetCursorPos(&cursorPos));
    
    ScreenToClient(&cursorPos);

    GetClientRect(clientRect);

    // Make certain that the cursor is in the client rect, because the
    // mainframe also wants these messages to provide tooltips for the
    // toolbar.
    if (clientRect.PtInRect(cursorPos)) {
        FuelItem* item;
        int i;

        for (i = 0; i < items.GetSize(); i++) {
            item = (FuelItem*) items[i];
        }
        bHandledNotify = TRUE;
    }
#endif 
    return bHandledNotify;
}

void FuelBar::OnSysColorChange() 
{
    GetSysColors();
}

BOOL APIENTRY FuelBar::StaticWndProc(IN HWND   hDlg,
                                     IN UINT   uMessage,
                                     IN WPARAM wParam,
                                     IN LPARAM lParam)
{
    FuelBar *that = (FuelBar*) FuelGetWindowLongPtr(hDlg, FUELGWLP_USERDATA);
    assert(that);

    switch (uMessage) {
    case WM_PAINT:
        that->OnPaint();
        break;
    }

    return (BOOL)CallWindowProc( (FUELPROC) that->prevWndProc,
                                     hDlg, 
                                     uMessage,
                                     wParam,
                                     lParam);
}

LPVOID FuelBar::GetHighlightedItem()
{
    return highlightID;
}