// BorderLayout.cpp : Implementation of cBorderLayout
#include "stdafx.h"
#include "DecalControls.h"
#include "BorderLayout.h"

/////////////////////////////////////////////////////////////////////////////
// cBorderLayout

void cBorderLayout::onSchemaLoad( IView *pView, MSXML::IXMLDOMElementPtr &pElement )
{
   static _bstr_t _strEdge = _T( "border" ),
      _strCenter = _T( "center" );
   static _variant_t
      _strLeft = _T( "left" ),
      _strRight = _T( "right" ),
      _strTop = _T( "top" ),
      _strBottom = _T( "bottom" );

   // Walk through the list of children - select all elements
   MSXML::IXMLDOMElementPtr pChild;
   for( MSXML::IXMLDOMNodeListPtr pChildren = pElement->selectNodes( _T( "*" ) );
      ( pChild = pChildren->nextNode() ).GetInterfacePtr() != NULL; )
   {
      if( pChild->tagName == _strEdge )
      {
         // Attempt to extract the edge indicator and the size indicator
         _variant_t vEdge = pChild->getAttribute( _T( "edge" ) ),
            vSize = pChild->getAttribute( _T( "size" ) );

         _ASSERTE( vEdge.vt != VT_NULL );
         _ASSERTE( vSize.vt != VT_NULL );

         // Got values, check if they're good
         eBorderEdge eEdge;

         if( _strLeft == vEdge )
            eEdge = eEdgeLeft;
         else if( vEdge == _strRight )
            eEdge = eEdgeRight;
         else if( vEdge == _strTop )
            eEdge = eEdgeTop;
         else if( vEdge == _strBottom )
            eEdge = eEdgeBottom;
#ifdef _DEBUG
         else
            // Invalid value here
            _ASSERTE( FALSE );
#endif

         // Convert the size
         try
         {
            long nSize = vSize;

            // Cannot have a 0 or negative edge size
            _ASSERTE( nSize > 0 );

            cEdgePlacement ep = { eEdge, nSize, loadChildControl( pView, pChild->selectSingleNode( _T( "control" ) ) ) };
            m_edges.push_back( ep );
         }
         catch( ... )
         {
            // The size could no be converted to a long value
            _ASSERTE( FALSE );
         }
      }
      else if( pChild->tagName == _strCenter )
      {
         // Make sure there isn't a center already created
         _ASSERTE( m_nCenterID == -1 );

         m_nCenterID = loadChildControl( pView, pChild->selectSingleNode( _T( "control" ) ) );
      }
#ifdef _DEBUG
      else
         // This is an invalid child element type
         _ASSERTE( FALSE );
#endif
   }
}

void cBorderLayout::onChildDestroy( long nID )
{
   // Check if this is the center
   if( nID == m_nCenterID )
   {
      m_nCenterID = -1;
      m_pSite->Reformat();
      return;
   }

   // Check if it on an edge
   for( cEdgePlacementList::iterator i = m_edges.begin(); i != m_edges.end(); ++ i )
   {
      if( i->m_nID == nID )
      {
         m_edges.erase( i );
         m_pSite->Reformat();

         break;
      }
   }
}

STDMETHODIMP cBorderLayout::CreateEdge(eBorderEdge eEdge, long nSize, ILayer *pSink)
{
   _ASSERTE( nSize > 0 );
   _ASSERTE( pSink != NULL );

   LayerParams lp = { dispenseID(), { 0, 0, 0, 0 }, eRenderClipped };
   m_pSite->CreateChild( &lp, pSink );

   cEdgePlacement ep = { eEdge, nSize, lp.ID };
   m_edges.push_back( ep );
   m_pSite->Reformat();

	return S_OK;
}

STDMETHODIMP cBorderLayout::CreateCenter(ILayer *pSink)
{
   _ASSERTE( m_nCenterID == -1 );

   LayerParams lp = { dispenseID(), { 0, 0, 0, 0 }, eRenderClipped };
   m_pSite->CreateChild( &lp, pSink );

   m_nCenterID = lp.ID;
   m_pSite->Reformat();

	return S_OK;
}

STDMETHODIMP cBorderLayout::Reformat()
{
   // Walk through the list of edges in order and
   // set their positions

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

   RECT rcClient = { 0, 0, rcLayer.right - rcLayer.left, rcLayer.bottom - rcLayer.top };

   for( cEdgePlacementList::iterator i = m_edges.begin(); i != m_edges.end(); ++ i )
   {
      RECT rcPosition = rcClient;

      switch( i->m_edge )
      {
      case eEdgeLeft:
         rcPosition.right = rcPosition.left + i->m_nSize;
         rcClient.left += i->m_nSize;
         break;

      case eEdgeTop:
         rcPosition.bottom = rcPosition.top + i->m_nSize;
         rcClient.top += i->m_nSize;
         break;

      case eEdgeRight:
         rcPosition.left = rcPosition.right - i->m_nSize;
         rcClient.right -= i->m_nSize;
         break;

      case eEdgeBottom:
         rcPosition.top = rcPosition.bottom - i->m_nSize;
         rcClient.bottom -= i->m_nSize;
         break;

      default:
         // Invalid edge value
         _ASSERTE( FALSE );
      }

      // Sanity checks to make sure we haven't overrun our area
      //_ASSERTE( rcClient.bottom > rcClient.top );
      _ASSERTE( rcClient.right > rcClient.left );
      _ASSERTE( rcPosition.bottom > rcPosition.top );
      _ASSERTE( rcPosition.right > rcPosition.left );

      CComPtr< ILayerSite > pChild;
      HRESULT hRes = m_pSite->get_Child( i->m_nID, ePositionByID, &pChild );
      _ASSERTE( SUCCEEDED( hRes ) );

      pChild->put_Position( &rcPosition );
   }

   if( m_nCenterID != -1 )
   {
      CComPtr< ILayerSite > pChild;
      HRESULT hRes = m_pSite->get_Child( m_nCenterID, ePositionByID, &pChild );
      _ASSERTE( SUCCEEDED( hRes ) );

      pChild->put_Position( &rcClient );
   }

   return S_OK;
}
