/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: sitetext.cpp,v 1.4.34.2 2004/07/26 08:59:23 pankajgupta Exp $
 *
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 *
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 *
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 *
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 *
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 *
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 *
 * Contributor(s):
 *
 * ***** END LICENSE BLOCK ***** */

#ifndef _WINDOWS
#error This is the Windows platform specific implementation.
#endif

//#define XXXBHG_TRACE_CODE

#include "hxcom.h"
#include "hxtypes.h"
#include "hxwintyp.h"
#ifdef _WIN32
#include <vfw.h>
#else
#include <windows.h>
#include <drawdib.h>
#endif	/* _WIN32 */
#include "chxxtype.h"
#include "hxmap.h"
#include "carray.h"
#include "hxslist.h"
#include "hxevent.h"
#include "ihxpckts.h"
#include "hxwin.h"
#include "hxengin.h"
#include "hxvctrl.h"
#include "hxvsurf.h"
#include "surface.h"
#include "vidosurf.h"
#ifdef _WIN32
//#include "fullsurf.h"
//#include "ddraw.h"	// needed by windraw.h
//#include "windraw.h"	// needed by wdsurf.h

//#include "wdsurf.h"
#endif /* _WIN32 */
#include "hxsite2.h"
#include "sitetext.h"
#include "chxpckts.h"
#include "hxtick.h"
#include "hxprefs.h"


#include "dbgtimer.h" // for blit time debugging

#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE
static const char HX_THIS_FILE[] = __FILE__;
#endif


UINT32		CHXSiteStatusText::zm_nInstanceCount = 0;
CHXMapPtrToPtr	CHXSiteStatusText::zm_StatusWindowMap;



/************************************************************************
 *  Class:
 *    CHXSiteStatusText this class draws the status text information.
 */

CHXSiteStatusText::CHXSiteStatusText()
   :   m_hWnd(NULL)
   ,	m_parentWindow(NULL)
   ,	m_hBitMap(NULL)
   ,	m_backgroundBrush(0x00008000)
   ,	m_textColor(0x0000FF00)
{
   memset(&m_rect, 0, sizeof(RECT));
}

CHXSiteStatusText::~CHXSiteStatusText()
{
   if (m_hBitMap)
   {
      DeleteObject(m_hBitMap);
   }
}

LRESULT HXEXPORT CHXSiteStatusTextProc
(
   HWND hWnd,
   UINT message,
   WPARAM uParam,
   LPARAM lParam
   )
{
#ifdef XXX_TRACE_CODE
   if (message == WM_SIZE || message == WM_MOVE || message == WM_WINDOWPOSCHANGED)
   {
      OutputDebugString("NEW ONE!!! sizeing\n");
   }
#endif
   CHXSiteStatusText* pStatusWnd = NULL;
   if (CHXSiteStatusText::zm_StatusWindowMap.Lookup((void*)hWnd,(void*&)pStatusWnd))
   {
      if (pStatusWnd)
      {
         return pStatusWnd->HandleEvent(hWnd,message,uParam,lParam);
      }
   }


   return (DefWindowProc(hWnd, message, uParam, lParam));
}

void
CHXSiteStatusText::RegisterClass()
{
   if (0 == zm_nInstanceCount)
   {
      WNDCLASS wndClass;
      ATOM result;

      wndClass.style = 0;
      wndClass.lpfnWndProc = CHXSiteStatusTextProc;
      wndClass.cbClsExtra = 0;
      wndClass.cbWndExtra = 0;
      wndClass.hInstance = GetInstance();
      wndClass.hIcon = NULL;
      wndClass.hCursor = NULL;
      wndClass.hbrBackground = NULL;
      wndClass.lpszMenuName = NULL;
      wndClass.lpszClassName = "CHXSiteStatusText";

      result = ::RegisterClass(&wndClass);
      HX_ASSERT(result);
   }
   zm_nInstanceCount++;
}

void
CHXSiteStatusText::UnRegisterClass()
{
   HX_ASSERT(zm_nInstanceCount > 0);

   if (zm_nInstanceCount > 0)
   {
      zm_nInstanceCount--;
   }

   if (0 == zm_nInstanceCount)
   {
      BOOL result = ::UnregisterClass("CHXSiteStatusText",GetInstance());
      HX_ASSERT(result);
   }
}

void
CHXSiteStatusText::SetStatusText(const char* pText)
{
   if (!pText)
   {
      m_StatusText ="";
   }
   else
   {
      m_StatusText = pText;
   }
   if (m_StatusText.GetLength())
   {
      if (m_hWnd)
      {
         Show();
         InvalidateRect(m_hWnd,NULL,TRUE);
         UpdateWindow(m_hWnd);
      }
   }
   else
   {
      Hide();
   }
}

LRESULT
CHXSiteStatusText::HandleEvent
(
   HWND hWnd,
   UINT message,
   WPARAM uParam,
   LPARAM lParam
   )
{
   if (WM_PAINT == message)
   {
      PAINTSTRUCT	ps;
      HDC		hDC = ::BeginPaint(hWnd,&ps);

      // we are going to be writing to a memory DC so that the
      // text does not blink. So 1st we have to set up the DC

      RECT rect;
      ::GetWindowRect(hWnd, &rect);

      HDC hMemDC = CreateCompatibleDC(hDC);

      if ( (rect.left - rect.right != m_rect.left - m_rect.right)
           || (rect.top - rect.bottom != m_rect.top - m_rect.bottom)
           || !m_hBitMap)
      {
         if (m_hBitMap)
         {
            DeleteObject(m_hBitMap);
         }
         // this is a SLOW function we should avoid it like the plague.
         m_hBitMap = CreateCompatibleBitmap(hDC, rect.right - rect.left, rect.bottom -  rect.top);
         // copy the contents
         memcpy(&m_rect, &rect, sizeof(RECT)); /* Flawfinder: ignore */
      }

      RECT boundsRect;
      boundsRect.left	    = 0;
      boundsRect.right    = rect.right - rect.left;
      boundsRect.top	    = 0;
      boundsRect.bottom   = rect.bottom - rect.top;

      HBITMAP	hOldBitMap = (HBITMAP) SelectObject(hMemDC, m_hBitMap);

      // Now we will do the drawing

      // create the approperiate tools
      HBRUSH	hStatusBrush	= CreateSolidBrush(m_backgroundBrush);
      HPEN	hNullPen	= CreatePen(PS_NULL,0,0);
      HBRUSH	hOldBrush	= (HBRUSH)SelectObject(hMemDC, hStatusBrush);
      HPEN	hOldPen		= (HPEN)SelectObject(hMemDC, hNullPen);

      // draw the rectangle
      Rectangle(hMemDC,boundsRect.left,boundsRect.top,boundsRect.right+1,boundsRect.bottom+1);

      // Now we have to draw the text
      int nOldMode = SetBkMode(hMemDC,TRANSPARENT);
      SetTextColor(hMemDC, m_textColor);

      // Get the text extents ... if we go beyond the size of the window
      // then we should left justify the text and maybe add elipises (sp?).

      SIZE textSize;
      GetTextExtentPoint(hMemDC, (const char*)m_StatusText, m_StatusText.GetLength(), &textSize);
      if (textSize.cx > (boundsRect.right - boundsRect.left))
      {
         // we will loop to find out where to put the elipise
         for (int i = 1; i <= m_StatusText.GetLength(); i++)
         {
            GetTextExtentPoint(hMemDC, (const char*)m_StatusText, i, &textSize);
            if (textSize.cx > (boundsRect.right - boundsRect.left))
            {
               CHXString tempString;
               for(int j = i - 1; j > 0 ; j--)
               {
                  tempString = m_StatusText.Left(j);
                  tempString = tempString + "...";
                  GetTextExtentPoint(hMemDC, (const char*)tempString, tempString.GetLength(), &textSize);
                  if (textSize.cx > (boundsRect.right - boundsRect.left))
                  {
                     continue;
                  }
                  DrawText(hMemDC, tempString, tempString.GetLength(),&boundsRect, DT_LEFT | DT_SINGLELINE | DT_VCENTER);
                  break;
               }
            }
         }
      }
      else
      {
         DrawText(hMemDC, m_StatusText, m_StatusText.GetLength(),&boundsRect, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
      }

      SetBkMode(hMemDC,nOldMode);

      // finally Blt the bitmap back on to the window.
      BitBlt(hDC, 0, 0, boundsRect.right , boundsRect.bottom, hMemDC, 0, 0, SRCCOPY);

      // cleapup
      SelectObject(hMemDC,hOldBrush);
      SelectObject(hMemDC,hOldPen);
      SelectObject(hMemDC, hOldBitMap);
      DeleteObject(hStatusBrush);
      DeleteObject(hNullPen);
      DeleteDC(hMemDC);

      // finished
      ::EndPaint(hWnd,&ps);
      return 0;
   }
   return (DefWindowProc(hWnd, message, uParam, lParam));
}

/************************************************************************
 *  Function:
 *    GetInstance
 */
HINSTANCE
CHXSiteStatusText::GetInstance()
{
#ifndef _WIN32
   return (HINSTANCE)GetCurrentTask(); // 16bit version
#else
   return NULL;	    // NULL works for 32 bit.
#endif
}

HX_RESULT CHXSiteStatusText::Create(void* ParentWindow)
{

   /*
    * Make sure the window class is registered.
    */
   RegisterClass();

   m_hWnd = CreateWindow( "CHXSiteStatusText",
                          "",
                          WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD,
                          0,0,0,0,
                          (HWND)ParentWindow,
                          NULL,
                          GetInstance(),
                          NULL);
   m_parentWindow  = (HWND) ParentWindow;
   if (!m_hWnd)
      return HXR_FAIL;
   zm_StatusWindowMap.SetAt((void*)m_hWnd, (void*)this);
   if (m_StatusText.GetLength())
   {
      Show();
      InvalidateRect(m_hWnd,NULL,TRUE);
      UpdateWindow(m_hWnd);
   }
   ParentChangedSize();
   return HXR_OK;
}

HX_RESULT CHXSiteStatusText::Destroy()
{
   if (m_hWnd)
   {
      BOOL bDidDestroy = DestroyWindow(m_hWnd);
#ifdef _DEBUGGING_DESTROY_WINDOWS
      HX_ASSERT(bDidDestroy);
#endif
      m_hWnd = 0;
      UnRegisterClass();
      zm_StatusWindowMap.RemoveKey((void*)m_hWnd);
      return HXR_OK;
   }
   return HXR_FAIL;
}

HX_RESULT CHXSiteStatusText::Show()
{
   if (m_hWnd)
   {
      ShowWindowAsync(m_hWnd, SW_SHOW);
      return HXR_OK;
   }
   return HXR_FAIL;
}

HX_RESULT CHXSiteStatusText::Hide()
{
   if (m_hWnd)
   {
      ShowWindowAsync(m_hWnd, SW_HIDE);
      return HXR_OK;
   }
   return HXR_FAIL;
}

HX_RESULT CHXSiteStatusText::ParentChangedSize()
{
   if (!m_hWnd)
      return HXR_FAIL;

   // since our parent changed size we must also change size
   RECT rect;
   ::GetWindowRect(m_parentWindow, &rect);

   // figure out the size of the text
   HDC hdc = ::GetDC(m_hWnd);
   TEXTMETRIC tm;
   ::GetTextMetrics(hdc, &tm);
   LONG nStatusTextHeight = tm.tmHeight;
   ::ReleaseDC(m_hWnd, hdc);

   m_rect.left	    = 0;
   m_rect.right    = rect.right - rect.left;
   m_rect.top	    = rect.bottom - rect.top - (LONG) ((double) nStatusTextHeight * 1.2);
   m_rect.bottom   = rect.bottom - rect.top;
   BOOL retVal = ::SetWindowPos(   m_hWnd,
                                   HWND_TOP,
                                   m_rect.left,
                                   m_rect.top,
                                   m_rect.right,
                                   m_rect.bottom - m_rect.top,
                                   0 );

   // destroy the bitmap since we changed sizes; the bitmap will be
   // generated again on the next paint
   if (m_hBitMap)
   {
      DeleteObject(m_hBitMap);
      m_hBitMap = NULL;
   }

   return HXR_OK;
}

