#include "ctlspriv.h"

#define MAININSYS

#ifndef WIN32
/* This returns the index of a submenu in a parent menu.  The return is
 * < 0 if the submenu does not exist in the parent menu
 */
int NEAR PASCAL GetMenuIndex(HMENU hMenu, HMENU hSubMenu)
{
  int i;

  if (!hMenu || !hSubMenu)
      return(-1);

  for (i=GetMenuItemCount(hMenu)-1; i>=0; --i)
    {
      if (hSubMenu == GetSubMenu(hMenu, i))
          break;
    }

  return(i);
}
#endif // WIN32


BOOL NEAR PASCAL IsMaxedMDI(HMENU hMenu)
{
  return(GetMenuItemID(hMenu, GetMenuItemCount(hMenu)-1) == SC_RESTORE);
}


/* Note that if iMessage is WM_COMMAND, it is assumed to have come from
 * a header bar or toolbar; do not pass in WM_COMMAND messages from any
 * other controls.
 */

#define MS_ID           GET_WM_MENUSELECT_CMD
#define MS_FLAGS        GET_WM_MENUSELECT_FLAGS
#define MS_MENU         GET_WM_MENUSELECT_HMENU

#define CMD_NOTIFY      GET_WM_COMMAND_CMD
#define CMD_ID          GET_WM_COMMAND_ID
#define CMD_CTRL        GET_WM_COMMAND_HWND


void WINAPI MenuHelp(UINT iMessage, WPARAM wParam, LPARAM lParam,
      HMENU hMainMenu, HINSTANCE hAppInst, HWND hwndStatus, UINT FAR *lpwIDs)
{
  UINT wID;
  UINT FAR *lpwPopups;
  int i;
  TCHAR szString[256];
  BOOL bUpdateNow = TRUE;
#if defined(WINDOWS_ME)
  MENUITEMINFO mii;
//BugBug: this line should be in
//  BOOL         bByPos;
#endif

  switch (iMessage)
    {
      case WM_MENUSELECT:
        if ((WORD)MS_FLAGS(wParam, lParam)==(WORD)-1 && MS_MENU(wParam, lParam)==0)
          {
#ifndef WIN32
EndMenuHelp:
#endif
            SendMessage(hwndStatus, SB_SIMPLE, 0, 0L);
            break;
          }

          szString[0] = TEXT('\0');
#if defined(WINDOWS_ME)
          i = MS_ID(wParam, lParam);
//BugBug: this line should be in
          //bByPos = (MS_FLAGS(wParam, lParam) & MF_POPUP);

          memset(&mii, 0, SIZEOF(MENUITEMINFO ));
          mii.cbSize = sizeof(mii);
          mii.fMask = MIIM_TYPE;
          mii.cch = 0;  //If we ask for MIIM_TYPE, this must be set to zero!
                        //Otherwise, win95 attempts to copy the string too!
          if (GetMenuItemInfo((HMENU)MS_MENU(wParam, lParam), i, TRUE /*bByPos*/, &mii))
              mii.fState = mii.fType & MFT_RIGHTORDER ?SBT_RTLREADING :0;
#endif
        if (!(MS_FLAGS(wParam, lParam)&MF_SEPARATOR))
          {
            if (MS_FLAGS(wParam, lParam)&MF_POPUP)
              {
                /* We don't want to update immediately in case the menu is
                 * about to pop down, with an item selected.  This gets rid
                 * of some flashing text.
                 */
                bUpdateNow = FALSE;

                /* First check if this popup is in our list of popup menus
                 */
                for (lpwPopups=lpwIDs+2; *lpwPopups; lpwPopups+=2)
                  {
                    /* lpwPopups is a list of string ID/menu handle pairs
                     * and MS_ID(wParam, lParam) is the menu handle of the selected popup
                     */
                    if (*(lpwPopups+1) == (UINT)MS_ID(wParam, lParam))
                      {
                        wID = *lpwPopups;
                        goto LoadTheString;
                      }
                  }

                /* Check if the specified popup is in the main menu;
                 * note that if the "main" menu is in the system menu,
                 * we will be OK as long as the menu is passed in correctly.
                 * In fact, an app could handle all popups by just passing in
                 * the proper hMainMenu.
                 */
                if ((HMENU)MS_MENU(wParam, lParam) == hMainMenu)
                  {
#ifdef  WIN32
                    i = MS_ID(wParam, lParam);
#else   // WIN32
                    i = GetMenuIndex((HMENU)MS_MENU(wParam, lParam), (HMENU)MS_ID(wParam, lParam));
                    if (i >= 0)
#endif  // WIN32
                      {
                        if (IsMaxedMDI(hMainMenu))
                          {
                            if (!i)
                              {
                                wID = IDS_SYSMENU;
                                hAppInst = HINST_THISDLL;
                                goto LoadTheString;
                              }
                            else
                                --i;
                          }
                        wID = (UINT)(i + lpwIDs[1]);
                        goto LoadTheString;
                      }
                  }

                /* This assumes all app defined popups in the system menu
                 * have been listed above
                 */
                if ((MS_FLAGS(wParam, lParam)&MF_SYSMENU))
                  {
                    wID = IDS_SYSMENU;
                    hAppInst = HINST_THISDLL;
                    goto LoadTheString;
                  }

                goto NoString;
              }
            else if (MS_ID(wParam, lParam) >= MINSYSCOMMAND)
              {
                wID = (UINT)(MS_ID(wParam, lParam) + MH_SYSMENU);
                hAppInst = HINST_THISDLL;
              }
            else
              {
                wID = (UINT)(MS_ID(wParam, lParam) + lpwIDs[0]);
              }

LoadTheString:
            if (hAppInst == HINST_THISDLL)
                LocalizedLoadString(wID, szString, ARRAYSIZE(szString));
            else
                LoadString(hAppInst, wID, szString, ARRAYSIZE(szString));
          }

NoString:
#if defined(WINDOWS_ME)
        SendMessage(hwndStatus, SB_SETTEXT, mii.fState|SBT_NOBORDERS|255,
              (LPARAM)(LPSTR)szString);
#else
        SendMessage(hwndStatus, SB_SETTEXT, SBT_NOBORDERS|255,
              (LPARAM)(LPTSTR)szString);
#endif
        SendMessage(hwndStatus, SB_SIMPLE, 1, 0L);

        if (bUpdateNow)
            UpdateWindow(hwndStatus);
        break;

#ifndef WIN32

      case WM_COMMAND:
        switch (CMD_NOTIFY(wParam, lParam))
          {
#ifdef WANT_SUCKY_HEADER
      // BUGBUG: these are now WM_NOTIFY messages
            case HBN_BEGINDRAG:
              bUpdateNow = FALSE;
              wID = IDS_HEADER;
              goto BeginSomething;

            case HBN_BEGINADJUST:
              wID = IDS_HEADERADJ;
              goto BeginSomething;
#endif
            case TBN_BEGINADJUST:
              /* We don't want to update immediately in case the operation is
               * aborted immediately.
               */
              bUpdateNow = FALSE;
              wID = IDS_TOOLBARADJ;
              goto BeginSomething;

BeginSomething:
              SendMessage(hwndStatus, SB_SIMPLE, 1, 0L);
              hAppInst = HINST_THISDLL;
              goto LoadTheString;

            case TBN_BEGINDRAG:
              MenuHelp(WM_MENUSELECT, (WPARAM)CMD_CTRL(wParam, lParam), 0L,
                    hMainMenu, hAppInst, hwndStatus, lpwIDs);
              break;
#ifdef WANT_SUCKY_HEADER
            case HBN_ENDDRAG:
            case HBN_ENDADJUST:
#endif
            case TBN_ENDDRAG:
            case TBN_ENDADJUST:
              goto EndMenuHelp;

            default:
              break;
          }
        break;
#endif  // !WIN32

      default:
        break;
    }
}


BOOL WINAPI ShowHideMenuCtl(HWND hWnd, WPARAM wParam, LPINT lpInfo)
{
  HWND hCtl;
  UINT uTool, uShow = MF_UNCHECKED | MF_BYCOMMAND;
  HMENU hMainMenu;
  BOOL bRet = FALSE;

  hMainMenu = IntToPtr_(HMENU, lpInfo[1]);

  for (uTool=0; ; ++uTool, lpInfo+=2)
    {
      if ((WPARAM)lpInfo[0] == wParam)
          break;
      if (!lpInfo[0])
          goto DoTheCheck;
    }

  if (!(GetMenuState(hMainMenu, (UINT) wParam, MF_BYCOMMAND)&MF_CHECKED))
      uShow = MF_CHECKED | MF_BYCOMMAND;

  switch (uTool)
    {
      case 0:
        bRet = SetMenu(hWnd, (HMENU)((uShow&MF_CHECKED) ? hMainMenu : 0));
        break;

      default:
        hCtl = GetDlgItem(hWnd, lpInfo[1]);
        if (hCtl)
          {
            ShowWindow(hCtl, (uShow&MF_CHECKED) ? SW_SHOW : SW_HIDE);
            bRet = TRUE;
          }
        else
            uShow = MF_UNCHECKED | MF_BYCOMMAND;
        break;
    }

DoTheCheck:
  CheckMenuItem(hMainMenu, (UINT) wParam, uShow);

#ifdef MAININSYS
  hMainMenu = GetSubMenu(GetSystemMenu(hWnd, FALSE), 0);
  if (hMainMenu)
      CheckMenuItem(hMainMenu, (UINT) wParam, uShow);
#endif

  return(bRet);
}


void WINAPI GetEffectiveClientRect(HWND hWnd, LPRECT lprc, LPINT lpInfo)
{
  RECT rc;
  HWND hCtl;

  GetClientRect(hWnd, lprc);

  /* Get past the menu
   */
  for (lpInfo+=2; lpInfo[0]; lpInfo+=2)
    {
      hCtl = GetDlgItem(hWnd, lpInfo[1]);
      /* We check the style bit because the parent window may not be visible
       * yet (still in the create message)
       */
      if (!hCtl || !(GetWindowStyle(hCtl) & WS_VISIBLE))
          continue;

      GetWindowRect(hCtl, &rc);

      //
      // This will do the ScrrenToClient functionality, plus
      // it will return a good rect (left < right) when the
      // hWnd parent is RTL mirrored. [samera]
      //
      MapWindowPoints(HWND_DESKTOP, hWnd, (PPOINT)&rc, 2);

      SubtractRect(lprc, lprc, &rc);
    }
}

#if 0
// BUGBUG: nuke this stuff for WIN32

#define NibbleToChar(x) (N2C[x])
static char N2C[] =
  {
    '0', '1', '2', '3', '4', '5', '6', '7',
    '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
  } ;

BOOL WINAPI MyWritePrivateProfileStruct(LPCSTR szSection, LPCSTR szKey,
      LPVOID lpStruct, UINT uSizeStruct, LPCSTR szFile)
{
  PSTR pLocal, pTemp;
  BOOL bRet;
  BYTE FAR *lpByte;

  /* NULL lpStruct erases the the key */

  if (lpStruct == NULL) {
      if (szFile && *szFile)
          return WritePrivateProfileString(szSection, szKey, NULL, szFile);
      else
          WriteProfileString(szSection, szKey, NULL);
  }

  pLocal = (PSTR)LocalAlloc(LPTR, uSizeStruct*2 + 1);
  if (!pLocal)
      return(FALSE);

  lpByte = lpStruct;

  for (pTemp=pLocal; uSizeStruct>0; --uSizeStruct, ++lpByte)
    {
      BYTE bStruct;

      bStruct = *lpByte;
      *pTemp++ = NibbleToChar((bStruct>>4)&0x000f);
      *pTemp++ = NibbleToChar(bStruct&0x000f);
    }

  *pTemp = '\0';

  if (szFile && *szFile)
      bRet = WritePrivateProfileString(szSection, szKey, pLocal, szFile);
  else
      bRet = WriteProfileString(szSection, szKey, pLocal);

  LocalFree((HLOCAL)pLocal);
  return(bRet);
}

/* Note that the following works for both upper and lower case, and will
 * return valid values for garbage chars
 */
#define CharToNibble(x) ((x)>='0'&&(x)<='9' ? (x)-'0' : ((10+(x)-'A')&0x000f))

BOOL WINAPI MyGetPrivateProfileStruct(LPCSTR szSection, LPCSTR szKey,
      LPVOID lpStruct, UINT uSizeStruct, LPCSTR szFile)
{
  PSTR pLocal, pTemp;
  int nLen;
  BYTE FAR *lpByte;

  nLen = uSizeStruct*2 + 10;
  pLocal = (PSTR)LocalAlloc(LPTR, nLen);
  if (!pLocal)
      return(FALSE);

  if (szFile && *szFile)
      nLen = GetPrivateProfileString(szSection, szKey, c_szNULL, pLocal, nLen,
            szFile);
  else
      nLen = GetProfileString(szSection, szKey, c_szNULL, pLocal, nLen);
  if ((UINT)nLen != uSizeStruct*2)
    {
      LocalFree((HLOCAL)pLocal);
      return(FALSE);
    }

  lpByte = lpStruct;

  for (pTemp=pLocal; uSizeStruct>0; --uSizeStruct, ++lpByte)
    {
      BYTE bStruct;
      char cTemp;

      cTemp = *pTemp++;
      bStruct = (BYTE)CharToNibble(cTemp);
      cTemp = *pTemp++;
      bStruct = (BYTE)((bStruct<<4) | CharToNibble(cTemp));

      *lpByte = bStruct;
    }

  LocalFree((HLOCAL)pLocal);
  return(TRUE);
}

#endif