#include "perfmon.h"
#include "status.h"  // External declarations for this file
#include <stdio.h>   // for sprintf.
#include <stdarg.h>  // For ANSI variable args. Dont use UNIX <varargs.h>

#include "log.h"        // for LogCollecting
#include "perfmops.h"   // for SmallFileSizeString
#include "playback.h"   // for PlayingBackLog
#include "utils.h"

//================================//
// Options for PaintStatusBar     //
//================================//
#define     PaintText         1
#define     PaintIcons        2
#define     PaintBoundary     4
#define     PaintAll          (PaintText + PaintIcons + PaintBoundary)

//==========================================================================//
//                                  Constants                               //
//==========================================================================//

#define szStatusClass          TEXT("PerfmonStatusClass")
#define dwStatusClassStyle     (CS_HREDRAW | CS_VREDRAW | CS_OWNDC)
#define iStatusClassExtra      (0)
#define iStatusWindowExtra     (0)
#define dwStatusWindowStyle    (WS_CHILD | WS_VISIBLE) 


#define szAlertMax            TEXT(" 99 ")
#define szAlertFormat         TEXT(" %2d ")
#define szAlertOverflow       TEXT(" ++")

#define szLogMax              TEXT(" 9,999.9M ")

//==========================================================================//
//                                Local Data                                //
//==========================================================================//


HDC            hStatusDC ;                   // for OWN_DC

HDC            hLogBitmapDC ;
int            xLogBitmapWidth ;     
int            yLogBitmapHeight ;

HDC            hAlertBitmapDC ;
int            xAlertBitmapWidth ;     
int            yAlertBitmapHeight ;     

int            yStatusHeight ;
int            xStatusAlertWidth ;           // of alert bm and num alerts
int            xStatusLogWidth ;             // of log bitmap and file size

int            szStatusLineLen ;             // no. of char. in szStatusLine
TCHAR          szStatusLine [MessageLen+ResourceStringLen] ;
TCHAR          szCurrentActivity [ResourceStringLen] ;
TCHAR          szStatusFormat  [ResourceStringLen] ;
TCHAR          szStatusFormat2 [ResourceStringLen] ;

HBITMAP        hBitmapAlertStatus ;
HBITMAP        hBitmapLogStatus ;



//==========================================================================//
//                                   Macros                                 //
//==========================================================================//


#define StatusTopMargin()     (2)
#define StatusLeftMargin()    (2)


//==========================================================================//
//                              Local Functions                             //
//==========================================================================//


void DrawAlerts (HDC hDC,
                 LPRECT lpRect)
   {
   TCHAR          szText [10] ;
   RECT           rectText ;
   int            yBitmapTop ;     

   if (!iUnviewedAlerts)
      return ;

   yBitmapTop = lpRect->top +
                (lpRect->bottom - 
                 lpRect->top - 
                 yAlertBitmapHeight) / 2 ;

   SetTextColor (hDC, crLastUnviewedAlert) ;

   BitBlt (hDC,                           // DC for Destination surface
      lpRect->right - xStatusAlertWidth,  // x pos for Destination surface
      yBitmapTop,                         // y for Destination surface
      xAlertBitmapWidth,                  // width of bitmap
      yAlertBitmapHeight,                 // height of bitmap
      hAlertBitmapDC,                     // DC for source surface
      0, 0,                               // location in source surface
      SRCCOPY) ;                          // ROP code
   
   SetTextColor (hDC, crBlack) ;

   if (iUnviewedAlerts > 99)
      lstrcpy (szText, szAlertOverflow) ;
   else
      TSPRINTF (szText, szAlertFormat, iUnviewedAlerts) ;

   rectText.left = lpRect->right - xStatusAlertWidth + xAlertBitmapWidth ;
   rectText.top = lpRect->top + 1 ;
   rectText.right = lpRect->right - 1 ;
   rectText.bottom = lpRect->bottom - 1 ;

   ExtTextOut (hDC, rectText.left, rectText.top, ETO_CLIPPED | ETO_OPAQUE,
      &rectText, szText, lstrlen (szText), NULL) ;

   lpRect->right -= (xStatusAlertWidth + (xAlertBitmapWidth >> 2)) ;
   }  // DrawAlerts


void DrawLog (HDC hDC,
              LPRECT lpRect)
   {
   TCHAR          szText [10] ;
   RECT           rectText ;
   int            yBitmapTop ;     

   if (!LogCollecting (hWndLog))
      return ;

   yBitmapTop = lpRect->top +
                (lpRect->bottom - 
                 lpRect->top - 
                 yLogBitmapHeight) / 2 ;
   BitBlt (hDC,                           // DC for Destination surface
      lpRect->right - xStatusLogWidth,    // x pos for Destination surface
      yBitmapTop,                         // y for Destination surface
      xLogBitmapWidth,                    // width of bitmap
      yLogBitmapHeight,                   // height of bitmap
      hLogBitmapDC,                       // DC for source surface
      0, 0,                               // location in source surface
      SRCCOPY) ;                          // ROP code


   SmallFileSizeString (LogFileSize (hWndLog), szText) ;

   rectText.left = lpRect->right - xStatusLogWidth +
      xLogBitmapWidth + 1 ;
   rectText.top = lpRect->top + 1 ;
   rectText.right = lpRect->right - 1 ;
   rectText.bottom = lpRect->bottom - 1 ;

   ExtTextOut (hDC, rectText.left, rectText.top, ETO_CLIPPED | ETO_OPAQUE,
      &rectText, szText, lstrlen (szText), NULL) ;

   lpRect->right -= xStatusLogWidth ;
   }  // DrawLog


//==========================================================================//
//                              Message Handlers                            //
//==========================================================================//


void static OnCreate (HWND hWnd)
/*
   Effect:        Perform any actions needed when a status window is created.
                  In particular, set the instance data to initial values,
                  determine the size and placement of the various elements
                  of the status display.

   Called By:     StatusWndProc only, in response to a WM_CREATE message.
*/
   {  // OnCreate
   HDC            hDC ;


   hBitmapAlertStatus = LoadBitmap (hInstance, idBitmapAlertStatus) ;
   hBitmapLogStatus = LoadBitmap (hInstance, idBitmapLogStatus) ;

   hDC = hStatusDC = GetDC (hWnd) ;
   SelectFont (hDC, hFontScales) ;
   SetBkColor (hDC, ColorBtnFace) ;
   SetTextAlign (hDC, TA_LEFT) ;
   SetBkMode (hDC, OPAQUE) ;

   yStatusHeight = 2 * StatusTopMargin () + 
                   FontHeight (hDC, TRUE) +
                   2 * ThreeDPad ;
   
   // pre-load the log and alert bitmaps for perfmormance
   xLogBitmapWidth = BitmapWidth (hBitmapLogStatus) ;
   yLogBitmapHeight = BitmapHeight (hBitmapLogStatus) ;
   xAlertBitmapWidth = BitmapWidth (hBitmapAlertStatus) ;
   yAlertBitmapHeight = BitmapHeight (hBitmapAlertStatus) ;

   hLogBitmapDC = CreateCompatibleDC (hDC) ;
   SelectObject (hLogBitmapDC, hBitmapLogStatus) ;

   hAlertBitmapDC = CreateCompatibleDC (hDC) ;
   SelectObject (hAlertBitmapDC, hBitmapAlertStatus) ;


   xStatusAlertWidth = xAlertBitmapWidth + 1 +
                       TextWidth (hDC, szAlertMax) ;
   xStatusLogWidth = xLogBitmapWidth +
                     TextWidth (hDC, szLogMax) ;


   StringLoad (IDS_CURRENTACTIVITY, szCurrentActivity) ;
   StringLoad (IDS_STATUSFORMAT, szStatusFormat) ;
   StringLoad (IDS_STATUSFORMAT2, szStatusFormat2) ;

   StatusLineReady (hWnd) ;
   }  // OnCreate

void static OnDestroy (HWND hWnd)
   {
   if (hBitmapAlertStatus)
      {
      DeleteObject (hBitmapAlertStatus) ;
      hBitmapAlertStatus = 0 ;
      }

   if (hBitmapLogStatus)
      {
      DeleteObject (hBitmapLogStatus) ;
      hBitmapLogStatus = 0 ;
      }
   ReleaseDC (hWnd, hStatusDC) ;

   }  // OnDestroy

void static PaintStatusBar (HWND hWnd, HDC hDC, int PaintOptions)
/*
   Effect:        Paint the invalid surface of hWnd. Draw each label, each
                  recessed value box, and each value.

   Called By:     StatusWndProc only, in response to a WM_PAINT message.
*/
   {
   RECT           rectClient ;

   if (bPerfmonIconic)
      {
      // no need to draw anything if iconic
      return ;
      }

   GetClientRect (hWnd, &rectClient) ;

   RectContract (&rectClient, StatusTopMargin (), StatusLeftMargin ()) ;
   
   if (PaintOptions == PaintAll)
      {
      ThreeDConcave1 (hDC,
                     rectClient.left, rectClient.top,
                     rectClient.right, rectClient.bottom) ;
      }

   rectClient.left += StatusLeftMargin () ;

   // Always draw the icons and need to draw log before Alerts!
   DrawLog (hDC, &rectClient) ;
   DrawAlerts (hDC, &rectClient) ;

   if (PaintOptions & PaintText)
      {
      rectClient.left += 1 ;
      rectClient.top += 1 ;
      rectClient.right -= 1 ;
      rectClient.bottom -= 1 ;
      ExtTextOut (hDC, rectClient.left, rectClient.top, ETO_CLIPPED | ETO_OPAQUE,
         &rectClient, szStatusLine, szStatusLineLen, NULL) ;
      }

   }  // PaintStatusBar




LRESULT APIENTRY StatusWndProc (HWND hWnd,
                                WORD wMsg,
                                WPARAM wParam,
                                LPARAM lParam)
   {  // StatusWndProc
   BOOL           bCallDefProc ;
   LRESULT        lReturnValue ;
   HDC            hDC ;
   PAINTSTRUCT    ps ;


   bCallDefProc = FALSE ;
   lReturnValue = 0L ;

   switch (wMsg)
      {  // switch
      case WM_PAINT:
         hDC = BeginPaint (hWnd, &ps) ;
         PaintStatusBar (hWnd, hDC, PaintAll) ;
         EndPaint (hWnd, &ps) ;
         break ;

      case WM_CREATE:
         OnCreate (hWnd) ;
         break ;

      case WM_DESTROY:
         OnDestroy (hWnd) ;
         break ;

      default:
         bCallDefProc = TRUE ;
      }  // switch


   if (bCallDefProc)
      lReturnValue = DefWindowProc (hWnd, wMsg, wParam, lParam) ;

   return (lReturnValue);
   }  // StatusWndProc


int StatusHeight (HWND hWnd)
/*
   Effect:        A status window has a preferred height, based on the font
                  used in its display. Return the preferred height, determined
                  when the window was created.

   Assert:        OnCreate has already been called, and it set 
                  StatusData.yHeight.
*/  
   {
   return (yStatusHeight) ;
   }




HWND CreatePMStatusWindow (HWND hWnd)
   {
   return (CreateWindow (szStatusClass,       // class
                         NULL,                // caption
                         dwStatusWindowStyle, // window style
                         0, 0,                // position
                         0, 0,                // size
                         hWnd,                // parent window
                         NULL,                // menu
                         hInstance,           // program instance
                         NULL)) ;             // user-supplied data
   }  // CreateStatusWindow




BOOL StatusInitializeApplication (void)
/*
   Called By:     InitializeApplication only
*/
   {
   WNDCLASS       wc ;

   wc.style          = dwStatusClassStyle ;
   wc.lpfnWndProc    = (WNDPROC) StatusWndProc ;
   wc.hInstance      = hInstance ;
   wc.cbClsExtra     = iStatusClassExtra ;
   wc.cbWndExtra     = iStatusWindowExtra ;
   wc.hIcon          = NULL ;
   wc.hCursor        = LoadCursor (NULL, IDC_ARROW) ;
   wc.hbrBackground  = hbLightGray ;
   wc.lpszMenuName   = NULL ;
   wc.lpszClassName  = szStatusClass ;

   return (RegisterClass (&wc)) ;
   }
   
BOOL _cdecl StatusLine (HWND hWnd,
                        WORD wStringID, ...)
   {
   TCHAR          szFormat [MessageLen] ;
   va_list        vaList ;

   if (wStringID == 0)
      {
      return (TRUE) ;
      }

   strclr (szStatusLine) ;

   if (LoadString (hInstance, wStringID, szFormat, MessageLen))
      {
      va_start (vaList, wStringID) ;
      wvsprintf (szStatusLine, szFormat, vaList) ;
      va_end (vaList) ;
      dwCurrentMenuID = MenuIDToHelpID (wStringID) ;
      szStatusLineLen = lstrlen (szStatusLine) ;
      }
   else
      {
      dwCurrentMenuID = 0 ;
      szStatusLineLen = 0 ;
      }
   PaintStatusBar (hWndStatus, hStatusDC, PaintText + PaintIcons) ;

   return (TRUE) ;
   }  // StatusLine



void StatusLineReady (HWND hWnd)
   {
   int         stringLen ;
   LPTSTR      pFileName = NULL ;

   TSPRINTF (szStatusLine, szStatusFormat, 
             PlayingBackLog () ? 
               PlaybackLog.szFileTitle : szCurrentActivity) ;

   switch (iPerfmonView)
      {
      case IDM_VIEWCHART:
         pFileName = pChartFileName ;
         break ;

      case IDM_VIEWALERT:
         pFileName = pAlertFileName ;
         break ;

      case IDM_VIEWLOG:
         pFileName = pLogFileName ;
         break ;

      case IDM_VIEWREPORT:
         pFileName = pReportFileName ;
         break ;
      }

   if (pFileName)
      {
      stringLen = lstrlen (szStatusLine) ;
      TSPRINTF (&szStatusLine[stringLen], szStatusFormat2, pFileName) ;
      }

   szStatusLineLen = lstrlen (szStatusLine) ;

   PaintStatusBar (hWndStatus, hStatusDC, PaintText + PaintIcons) ;
   }


void StatusUpdateIcons (HWND hWndStatus)
   {  
   PaintStatusBar (hWndStatus, hStatusDC, PaintIcons) ;
   }

