// Notebook.cpp : Implementation of cNotebook
#include "stdafx.h"
#include "DecalControls.h"
#include "Notebook.h"

/////////////////////////////////////////////////////////////////////////////
// cNotebook

cNotebook::cNotebook():
m_nNextPageID( 1001 ),
m_nActiveTab( -1 ),
m_nCaptureTab( -1 ),
m_bHitCapture( false )
{
}

long cNotebook::hitTest( MouseState *pMS )
{
   if( pMS->over != this )
      // Not hitting us, therefore not hitting a tab
      return -1;

   // Yes for y boundaries
   if( pMS->client.y < 0 || pMS->client.y >= 16 )
      return -1;

   // Walk through the list of tabs
   for( cPageList::iterator i = m_pages.begin(); i != m_pages.end(); ++ i )
   {
      if( pMS->client.x >= i->m_nLeft && pMS->client.x < i->m_nRight )
         // Hit a tab!
         return ( i - m_pages.begin() );
   }

   // No tabs hit
   return -1;
}

void cNotebook::positionActiveTab()
{
   if( m_nActiveTab == -1 )
      return;

   RECT rcClient;
   m_pSite->get_Position( &rcClient );

   CComPtr< ILayerSite > pChild;
   m_pSite->get_Child( m_pages[ m_nActiveTab ].m_nPageID, ePositionByID, &pChild );

   RECT rcChild = { 0, 16, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top };
   pChild->put_Position( &rcChild );
}

STDMETHODIMP cNotebook::AddPage(BSTR strText, IControl *pClient)
{
   cPage p;
   p.m_strName = strText;
   p.m_nPageID = m_nNextPageID ++;

   CComPtr< ILayer > pClientLayer;
   pClient->QueryInterface( &pClientLayer );

   LayerParams lp = { p.m_nPageID, { 0, 0, 0, 0 }, eRenderClipped };
   m_pSite->CreateChild( &lp, pClientLayer );

   m_pages.push_back( p );

   if( m_nActiveTab == -1 )
      // Activate the page if it's the first one
      m_nActiveTab = 0;

   m_pSite->Reformat();

	return S_OK;
}

void cNotebook::onCreate()
{
   // Load the images
   CComPtr< IPluginSite > pPlugin;
   m_pSite->get_PluginSite( &pPlugin );

   pPlugin->LoadBitmapFile( _bstr_t( _T( "Tab-Active.bmp" ) ), &m_pActive );
   pPlugin->LoadBitmapFile( _bstr_t( _T( "Tab-Inactive.bmp" ) ), &m_pInactive );
   BSTR bstrFontName;
   pPlugin->get_FontName(&bstrFontName);
   pPlugin->CreateFont( bstrFontName /*_bstr_t( _T( "Times New Roman" ) )*/, 14, 0, &m_pFont );
}

void cNotebook::onDestroy()
{
   m_pActive.Release();
   m_pInactive.Release();
}

#define TEXT_LR_MARGIN 5

STDMETHODIMP cNotebook::Reformat()
{
   // Walk through the tabs and position the graphics
   long nTabPos = 0;
   for( cPageList::iterator i = m_pages.begin(); i != m_pages.end(); ++ i )
   {
      // Calculate the text length
      SIZE sz;
      m_pFont->MeasureText( i->m_strName, &sz );

      long nWidth = sz.cx + TEXT_LR_MARGIN * 2;

      i->m_nLeft = nTabPos;
      i->m_nRight = nTabPos + nWidth;
      nTabPos += nWidth;
   }

   if( m_nActiveTab != -1 )
      positionActiveTab();

   _ASSERTMEM( _CrtCheckMemory( ) );

   return S_OK;
}

STDMETHODIMP cNotebook::Render( ICanvas *pCanvas )
{
   for( cPageList::iterator i = m_pages.begin(); i != m_pages.end(); ++ i )
   {
      POINT ptTab = { i->m_nLeft, 0 };
      long nWidth = i->m_nRight - i->m_nLeft;
      long nIndex = i - m_pages.begin();

      bool bActive = ( ( nIndex == m_nActiveTab ) || ( m_nCaptureTab != -1 && m_bHitCapture && nIndex == m_nCaptureTab ) );
      if( bActive )
         m_pActive->StretchBlt( pCanvas, &ptTab, nWidth, 7, 90 );
      else
         m_pInactive->StretchBlt( pCanvas, &ptTab, nWidth, 7, 90 );

      // Draw the text
      POINT ptText = { i->m_nLeft + TEXT_LR_MARGIN, 2 };
      m_pFont->DrawText( &ptText, i->m_strName, ( bActive ) ? RGB( 0, 0, 0 ) : RGB( 192, 192, 192 ), pCanvas );
   }

   _ASSERTMEM( _CrtCheckMemory( ) );

   return S_OK;
}

STDMETHODIMP cNotebook::MouseDown( MouseState *pMS )
{
   m_nCaptureTab = hitTest( pMS );

   if( m_nCaptureTab != -1 )
   {
      m_bHitCapture = true;
      m_pSite->Invalidate();
   }

   return S_OK;
}

STDMETHODIMP cNotebook::MouseUp( MouseState *pMS )
{
   _ASSERTMEM( _CrtCheckMemory( ) );

   if( m_nCaptureTab == -1 )
      return S_OK;

   if( hitTest( pMS ) == m_nCaptureTab )
      put_ActiveTab( m_nCaptureTab );

   _ASSERTMEM( _CrtCheckMemory( ) );

   m_nCaptureTab = -1;

   return S_OK;
}

STDMETHODIMP cNotebook::MouseMove( MouseState *pMS )
{
   if( m_nCaptureTab == -1 )
      // We are hitting in progress
      return S_OK;

   // Check for a hit
   bool bHitCapture = ( hitTest( pMS ) == m_nCaptureTab );
   if( bHitCapture != m_bHitCapture )
   {
      m_bHitCapture = bHitCapture;
      m_pSite->Invalidate();
   }

   return S_OK;
}

STDMETHODIMP cNotebook::get_ActiveTab(long *pVal)
{
   *pVal = m_nActiveTab;

	return S_OK;
}

STDMETHODIMP cNotebook::put_ActiveTab(long newVal)
{
   if( m_nActiveTab != -1 )
   {
      // Hide the current active view
      static RECT rcHide = { 0, 0, 0, 0 };
      CComPtr< ILayerSite > pChild;
      m_pSite->get_Child( m_pages[ m_nActiveTab ].m_nPageID, ePositionByID, &pChild );

      pChild->put_Position( &rcHide );
   }

   m_nActiveTab = newVal;

   if( m_nActiveTab != -1 )
      positionActiveTab();

   long nID;
   m_pSite->get_ID( &nID );
   Fire_Change( nID, m_nActiveTab );

   m_pSite->Invalidate();

	return S_OK;
}

STDMETHODIMP cNotebook::SchemaLoad(IView *pView, IUnknown *pSchema)
{
   MSXML::IXMLDOMElementPtr pElement = pSchema;

   MSXML::IXMLDOMElementPtr pPage;
   for( MSXML::IXMLDOMNodeListPtr pPages = pElement->selectNodes( _T( "page" ) ); ( pPage = pPages->nextNode() ).GetInterfacePtr() != NULL; )
   {
      // We have the page, get the text, then recurse and generate the control
      _variant_t vText = pPage->getAttribute( _T( "label" ) );

      _ASSERTE( vText.vt == VT_BSTR );

      cPage p;
      p.m_strName = vText.bstrVal;
      p.m_nPageID = m_nNextPageID ++;

      m_pages.push_back( p );

      MSXML::IXMLDOMElementPtr pControl = pPage->selectSingleNode( _T( "control" ) );

      _ASSERTE( pControl.GetInterfacePtr() != NULL );

      long nAssigned;
      pView->LoadControl( m_pSite, p.m_nPageID, pControl, &nAssigned );
   }

   if( m_nActiveTab == -1 && m_pages.size() > 0 )
      // Activate the page if it's the first one
      m_nActiveTab = 0;

   return S_OK;
}

STDMETHODIMP cNotebook::get_PageText(long nIndex, BSTR *pVal)
{
   _ASSERTE( pVal != NULL );
   _ASSERTE( nIndex >= 0 );
   _ASSERTE( nIndex < m_pages.size() );

   *pVal = OLE2BSTR( m_pages[ nIndex ].m_strName );

	return S_OK;
}

STDMETHODIMP cNotebook::put_PageText(long nIndex, BSTR newVal)
{
   _ASSERTE( newVal != NULL );
   _ASSERTE( nIndex >= 0 );
   _ASSERTE( nIndex < m_pages.size() );

   m_pages[ nIndex ].m_strName = newVal;
   m_pSite->Reformat();

	return S_OK;
}
