#include "stdafx.h"
#include "ProgressBar.h"

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

ProgressBar::ProgressBar()
    : m_error( false )
    , m_total( 0 )
    , m_progress( 0 ) 
    , m_progressX( 0 )
{
}


ProgressBar::~ProgressBar()
{
}


BEGIN_MESSAGE_MAP(ProgressBar, CWnd)
	//{{AFX_MSG_MAP(ProgressBar)
	ON_WM_PAINT()
	ON_WM_SIZE()
	ON_WM_ERASEBKGND()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


void 
ProgressBar::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
  paint( dc );
}


// Paint the progress bar in response to a paint message
void 
ProgressBar::paint( CDC &dc )
{
  paintBackground( dc );
  paintStatus( dc );
}


// Paint the background of the progress bar region
void 
ProgressBar::paintBackground( CDC &dc )
{
  CBrush brshBackground;
  CPen penGray( PS_SOLID, 1, RGB (128, 128, 128) );
  CPen penWhite( PS_SOLID, 1, RGB (255, 255, 255) );

  VERIFY( brshBackground.CreateSolidBrush( ::GetSysColor (COLOR_BTNFACE) ) );

  dc.FillRect( m_bounds, &brshBackground );
  
  CPen *pOldPen = dc.SelectObject( &penGray );
  int xRight = m_bounds.left + m_bounds.Width() -1;
  int yBottom = m_bounds.top + m_bounds.Height() -1;
  {
    dc.MoveTo( m_bounds.left, m_bounds.top );
    dc.LineTo( xRight, m_bounds.top );

    dc.MoveTo( m_bounds.left, m_bounds.top );
    dc.LineTo( m_bounds.left, yBottom );
  }

  dc.SelectObject( &penWhite );
  {
    dc.MoveTo( xRight, m_bounds.top );
    dc.LineTo( xRight, yBottom );

    dc.MoveTo( m_bounds.left, yBottom );
    dc.LineTo( xRight, yBottom );
  }

  dc.SelectObject( pOldPen );
}


// Paint the actual status of the progress bar
void 
ProgressBar::paintStatus( CDC &dc )
{
  if ( m_progress <= 0 )
    return;

  CBrush brshStatus;
  CRect rect( m_bounds.left, m_bounds.top, 
              m_bounds.left + m_progressX, m_bounds.bottom );

  COLORREF statusColor = getStatusColor();

  VERIFY( brshStatus.CreateSolidBrush( statusColor ) );

  rect.DeflateRect( 1, 1 );
  dc.FillRect( rect, &brshStatus );
}


// Paint the current step
void 
ProgressBar::paintStep( int startX, 
                        int endX )
{
  CRect redrawBounds( m_bounds.left + startX-1, m_bounds.top, 
                      m_bounds.left + endX, m_bounds.bottom );
  RedrawWindow( redrawBounds );
}


// Setup the progress bar for execution over a total number of steps
void 
ProgressBar::start( int total )
{
  m_total = total;
  reset ();
}


// Take one step, indicating whether it was a successful step
void 
ProgressBar::step( bool successful )
{
  m_progress++;

  int x = m_progressX;

  m_progressX = scale (m_progress);

  if ( !m_error  &&  !successful )
  {
    m_error = true;
    x = 1;
  }

  paintStep( x, m_progressX );
}


// Map from steps to display units
int 
ProgressBar::scale( int value )
{
  if ( m_total > 0 )
      return max( 1, value * (m_bounds.Width() - 1) / m_total );

  return value;
}


// Reset the progress bar
void 
ProgressBar::reset()
{
  m_progressX = 1;
  m_progress = 0;
  m_error = false;

  RedrawWindow( m_bounds );
  UpdateWindow( );
}


void 
ProgressBar::OnSize(UINT nType, int cx, int cy) 
{
	CWnd::OnSize(nType, cx, cy);

  GetClientRect( &m_bounds );
  m_progressX = scale (m_progress);
  Invalidate();
}


BOOL 
ProgressBar::OnEraseBkgnd( CDC *pDC )
{
  return FALSE;
}
