// ListView.cpp : Implementation of cListView
#include "stdafx.h"
#include "DecalControls.h"
#include "ListView.h"

#include "List.h"

/////////////////////////////////////////////////////////////////////////////
// cListView

cListView::cListView()
: m_nRowHeight( 20 ),
m_nRowCache( 0 ),
m_nValidFrom( 0 ),
m_nValidTo( 0 )
{
}

STDMETHODIMP cListView::put_Area(LPSIZE newVal)
{
   RECT rc = { 0, 0, newVal->cx, newVal->cy };
   m_pSite->put_Position( &rc );

	return S_OK;
}

STDMETHODIMP cListView::SetCacheInfo(long nRowHeight, long nRowsToCache)
{
   m_nRowHeight = nRowHeight;
   m_nRowCache = nRowsToCache;

   m_pSite->Reformat();

	return S_OK;
}

void cListView::onCreate()
{
   CComPtr< IPluginSite > pPlugin;
   m_pSite->get_PluginSite( &pPlugin );

   pPlugin->LoadBitmapPortal( 0x0600128A, &m_pBackground );

   m_pSite->put_Transparent( VARIANT_FALSE );
}

void cListView::onDestroy()
{
   m_pBackground.Release();

   if( m_pCache.p != NULL )
      m_pCache.Release();
}

STDMETHODIMP cListView::Reformat()
{
   RECT rcPos;
   m_pSite->get_Position( &rcPos );

   SIZE szCache = { rcPos.right - rcPos.left, m_nRowHeight * m_nRowCache };

   if( m_pCache.p != NULL )
      m_pCache->put_Size( &szCache );
   else
   {
      CComPtr< IPluginSite > pPlugin;
      m_pSite->get_PluginSite( &pPlugin );

      pPlugin->CreateCanvas( &szCache, &m_pCache );
   }

   _ASSERTMEM( _CrtCheckMemory( ) );

   return S_OK;
}

STDMETHODIMP cListView::Render(ICanvas *pCanvas)
{
   _ASSERTMEM( _CrtCheckMemory( ) );

   // First, draw the Background pattern
   VARIANT_BOOL bLost;
   m_pCache->get_WasLost( &bLost );

   if( bLost )
      // There is no valid range - we must redraw
      // the entire rowset
      m_nValidFrom = m_nValidTo;

   ClipParams cp;
   pCanvas->GetClipParams( &cp );

   SIZE szCache;
   m_pCache->get_Size( &szCache );

   // We have the clipping rectangle now - calculate the range
   // of rows we want to draw
   long nDrawFrom = cp.org.y / m_nRowHeight,
      nDrawTo = nDrawFrom + m_nRowCache,
      nRowCount = m_pList->m_rows.size();

   // Ok, now draw all of the rows either out of range
   // or invalid
   for( long nDraw = nDrawFrom; nDraw < nDrawTo; ++ nDraw )
   {
      // Determine how much we need to draw
      bool bHasData = ( nDraw >= 0 && nDraw < nRowCount );

      if( nDraw < m_nValidFrom || nDraw >= m_nValidTo || ( bHasData && m_pList->m_rows[ nDraw ].m_bInvalid ) )
      {
         // Redraw this row
         long nRowPos = nDraw % m_nRowCache;
         RECT rcRow = { 0, nRowPos * m_nRowHeight, szCache.cx, ( nRowPos + 1 ) * m_nRowHeight };

         // Fill the background with the background image
         POINT ptBackgroundOrg = { 0, nDraw * m_nRowHeight };
         m_pBackground->PatBlt( m_pCache, &rcRow, &ptBackgroundOrg );

         if( bHasData )
         {
            // This row is visible and there's data - so use the
            // column objects to render the data
            for( cList::cColumnList::iterator i_col = m_pList->m_cols.begin(); i_col != m_pList->m_cols.end(); ++ i_col )
            {
               RECT rcCell = { i_col->m_nLeft, rcRow.top, i_col->m_nRight, rcRow.bottom };
               VARIANT_BOOL bVisible;
               m_pCache->PushClipRect( &rcCell, &bVisible );

               // All our clippings should be completely visible
               _ASSERTE( bVisible );
					
					long nColor;
					POINT ptCell = { i_col - m_pList->m_cols.begin(), nDraw };

					get_Color(ptCell.x, ptCell.y, &nColor);
               i_col->m_pColumn->Render( m_pCache, &ptCell, nColor);
               m_pCache->PopClipRect();

               _ASSERTMEM( _CrtCheckMemory( ) );
            }

            m_pList->m_rows[ nDraw ].m_bInvalid = false;
         }
      }
   }

   // Now that our cache is updated, we can tranfer it to the surface
   m_nValidFrom = nDrawFrom;
   m_nValidTo = nDrawTo;

   long nBltFrom = nDrawFrom % m_nRowCache;

   RECT rcTop = { 0, nBltFrom * m_nRowHeight, szCache.cx, m_nRowHeight * m_nRowCache };
   POINT ptDest = { 0, nDrawFrom * m_nRowHeight };
   pCanvas->Blt( &rcTop, m_pCache, &ptDest );

   if( nBltFrom != 0 )
   {
      // Transfer the bottom part
      RECT rcBottom = { 0, 0, szCache.cx, nBltFrom * m_nRowHeight };
      POINT ptDestBottom = { 0, ( nDrawFrom + m_nRowCache - nBltFrom ) * m_nRowHeight };

      pCanvas->Blt( &rcBottom, m_pCache, &ptDestBottom );
   }

   _ASSERTMEM( _CrtCheckMemory( ) );

   return S_OK;
}

STDMETHODIMP cListView::MouseDown( MouseState *pMS )
{
   // Hit test to find what cell
   POINT ptHit = { 0, pMS->client.y / m_nRowHeight };
   if( ptHit.y >= m_pList->m_rows.size() )
      // We did not hit any rows
      return S_OK;

   for( cList::cColumnList::iterator i_col = m_pList->m_cols.begin(); i_col != m_pList->m_cols.end(); ++ i_col )
   {
      if( pMS->client.x >= i_col->m_nLeft && pMS->client.x < i_col->m_nRight )
      {
         ptHit.x = ( i_col - m_pList->m_cols.begin() );

         i_col->m_pColumn->Activate( &ptHit );

         long nID;
         m_pList->m_pSite->get_ID( &nID );
		 
		 m_pList->Fire_Change( nID, ptHit.x, ptHit.y );

         break;
      }
   }

   return S_OK;
}

STDMETHODIMP cListView::InvalidateFrom(long nRow)
{
   if( nRow < m_nValidTo )
      m_nValidTo = nRow;

   if( nRow < m_nValidFrom )
      m_nValidFrom = nRow;

	return S_OK;
}

STDMETHODIMP cListView::get_Color(long nCol, long nRow, long *pVal)
{
	m_pList->get_Color(nCol, nRow, pVal);
	return S_OK;
}

STDMETHODIMP cListView::put_Color(long nCol, long nRow, long newVal)
{
	m_pList->put_Color(nCol, nRow, newVal);
	return S_OK;
}
