/*************************************************************************
**
**    OLE 2 Sample Code
**
**    outlntbl.c
**
**    This file contains OutlineNameTable functions.
**
**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved
**
*************************************************************************/


#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP g_lpApp;

OLECHAR ErrMsgNameTable[] = OLESTR("Can't create NameTable!");


/* OutlineNameTable_Init
 * ---------------------
 *
 *      initialize a name table.
 */
BOOL OutlineNameTable_Init(LPOUTLINENAMETABLE lpOutlineNameTable, LPOUTLINEDOC lpOutlineDoc)
{
   HWND lpParent = OutlineDoc_GetWindow(lpOutlineDoc);

   lpOutlineNameTable->m_nCount = 0;

   /* We will use an OwnerDraw listbox as our data structure to
   **    maintain the table of Names. this listbox will never be made
   **    visible. the listbox is just a convenient data structure to
   **    manage a collection.
   */
   lpOutlineNameTable->m_hWndListBox = CreateWindow(
               "listbox",              /* Window class name           */
               NULL,                   /* Window's title              */
               WS_CHILDWINDOW |
               LBS_OWNERDRAWFIXED,
               0, 0,                   /* Use default X, Y            */
               0, 0,                   /* Use default X, Y            */
               lpParent,               /* Parent window's handle      */
               (HMENU)IDC_NAMETABLE,   /* Child Window ID             */
               g_lpApp->m_hInst,       /* Instance of window          */
               NULL);                  /* Create struct for WM_CREATE */

   if (! lpOutlineNameTable->m_hWndListBox) {
      OutlineApp_ErrorMessage(g_lpApp, ErrMsgNameTable);
      return FALSE;
   }

   return TRUE;
}


/* OutlineNameTable_Destroy
 * ------------------------
 *
 *      Free memory used by the name table.
 */
void OutlineNameTable_Destroy(LPOUTLINENAMETABLE lpOutlineNameTable)
{
   // Delete all names
   OutlineNameTable_ClearAll(lpOutlineNameTable);

   DestroyWindow(lpOutlineNameTable->m_hWndListBox);
   Delete(lpOutlineNameTable);
}


/* OutlineNameTable_AddName
 * ------------------------
 *
 *      Add a name to the table
 */
void OutlineNameTable_AddName(LPOUTLINENAMETABLE lpOutlineNameTable, LPOUTLINENAME lpOutlineName)
{
   SendMessage(
         lpOutlineNameTable->m_hWndListBox,
         LB_ADDSTRING,
         0,
         (DWORD)lpOutlineName
   );
   lpOutlineNameTable->m_nCount++;
}


/* OutlineNameTable_DeleteName
 * ---------------------------
 *
 *      Delete a name from table
 */
void OutlineNameTable_DeleteName(LPOUTLINENAMETABLE lpOutlineNameTable,int nIndex)
{
   LPOUTLINENAME lpOutlineName = OutlineNameTable_GetName(lpOutlineNameTable, nIndex);

#if defined( OLE_SERVER )
   /* OLE2NOTE: if there is a pseudo object attached to this name, it
   **    must first be closed before deleting the Name. this will
   **    cause OnClose notification to be sent to all linking clients.
   */
   ServerName_ClosePseudoObj((LPSERVERNAME)lpOutlineName);
#endif

   if (lpOutlineName)
      Delete(lpOutlineName);      // free memory for name

   SendMessage(
         lpOutlineNameTable->m_hWndListBox,
         LB_DELETESTRING,
         (WPARAM)nIndex,
         0L
   );
   lpOutlineNameTable->m_nCount--;
}


/* OutlineNameTable_GetNameIndex
 * -----------------------------
 *
 *      Return the index of the Name given a pointer to the Name.
 *      Return -1 if the Name is not found.
 */
int OutlineNameTable_GetNameIndex(LPOUTLINENAMETABLE lpOutlineNameTable, LPOUTLINENAME lpOutlineName)
{
   LRESULT lReturn;

   if (! lpOutlineName) return -1;

   lReturn = SendMessage(
         lpOutlineNameTable->m_hWndListBox,
         LB_FINDSTRING,
         (WPARAM)-1,
         (LPARAM)(LPCSTR)lpOutlineName
      );

   return ((lReturn == LB_ERR) ? -1 : (int)lReturn);
}


/* OutlineNameTable_GetName
 * ------------------------
 *
 *      Retrieve the pointer to the Name given its index in the NameTable
 */
LPOUTLINENAME OutlineNameTable_GetName(LPOUTLINENAMETABLE lpOutlineNameTable, int nIndex)
{
   LPOUTLINENAME lpOutlineName = NULL;
    LRESULT lResult;

   if (lpOutlineNameTable->m_nCount == 0 ||
      nIndex > lpOutlineNameTable->m_nCount ||
      nIndex < 0) {
      return NULL;
   }

   lResult = SendMessage(
         lpOutlineNameTable->m_hWndListBox,
         LB_GETTEXT,
         nIndex,
         (LPARAM)(LPCSTR)&lpOutlineName
   );
    OleDbgAssert(lResult != LB_ERR);
   return lpOutlineName;
}


/* OutlineNameTable_FindName
 * -------------------------
 *
 *      Find a name in the name table given a string.
 */
LPOUTLINENAME OutlineNameTable_FindName(LPOUTLINENAMETABLE lpOutlineNameTable, LPOLESTR lpszName)
{
   LPOUTLINENAME lpOutlineName;
   BOOL fFound = FALSE;
   int i;

   for (i = 0; i < lpOutlineNameTable->m_nCount; i++) {
      lpOutlineName = OutlineNameTable_GetName(lpOutlineNameTable, i);
      if (OLESTRCPY(lpOutlineName->m_szName, lpszName) == 0) {
         fFound = TRUE;
         break;      // FOUND MATCH!
      }
   }

   return (fFound ? lpOutlineName : NULL);
}


/* OutlineNameTable_FindNamedRange
 * -------------------------------
 *
 *      Find a name in the name table which matches a given line range.
 */
LPOUTLINENAME OutlineNameTable_FindNamedRange(LPOUTLINENAMETABLE lpOutlineNameTable, LPLINERANGE lplrSel)
{
   LPOUTLINENAME lpOutlineName;
   BOOL fFound = FALSE;
   int i;

   for (i = 0; i < lpOutlineNameTable->m_nCount; i++) {
      lpOutlineName = OutlineNameTable_GetName(lpOutlineNameTable, i);
      if ((lpOutlineName->m_nStartLine == lplrSel->m_nStartLine) &&
         (lpOutlineName->m_nEndLine == lplrSel->m_nEndLine) ) {
         fFound = TRUE;
         break;      // FOUND MATCH!
      }
   }

   return (fFound ? lpOutlineName : NULL);
}


/* OutlineNameTable_GetCount
 * -------------------------
 *
 * Return number of names in nametable
 */
int OutlineNameTable_GetCount(LPOUTLINENAMETABLE lpOutlineNameTable)
{
   if (!lpOutlineNameTable)
      return 0;

   return lpOutlineNameTable->m_nCount;
}


/* OutlineNameTable_ClearAll
 * -------------------------
 *
 *      Remove all names from table
 */
void OutlineNameTable_ClearAll(LPOUTLINENAMETABLE lpOutlineNameTable)
{
   LPOUTLINENAME lpOutlineName;
   int i;
   int nCount = lpOutlineNameTable->m_nCount;

   for (i = 0; i < nCount; i++) {
      lpOutlineName = OutlineNameTable_GetName(lpOutlineNameTable, i);
      Delete(lpOutlineName);      // free memory for name
   }

   lpOutlineNameTable->m_nCount = 0;
   SendMessage(lpOutlineNameTable->m_hWndListBox,LB_RESETCONTENT,0,0L);
}


/* OutlineNameTable_AddLineUpdate
 * ------------------------------
 *
 *      Update table when a new line is added at nAddIndex
 * The line used to be at nAddIndex is pushed down
 */
void OutlineNameTable_AddLineUpdate(LPOUTLINENAMETABLE lpOutlineNameTable, int nAddIndex)
{
   LPOUTLINENAME lpOutlineName;
   LINERANGE lrSel;
   int i;
   BOOL fRangeModified = FALSE;

   for(i = 0; i < lpOutlineNameTable->m_nCount; i++) {
      lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i);
      OutlineName_GetSel(lpOutlineName, &lrSel);

      if((int)lrSel.m_nStartLine > nAddIndex) {
         lrSel.m_nStartLine++;
         fRangeModified = !fRangeModified;
      }
      if((int)lrSel.m_nEndLine > nAddIndex) {
         lrSel.m_nEndLine++;
         fRangeModified = !fRangeModified;
      }

      OutlineName_SetSel(lpOutlineName, &lrSel, fRangeModified);
   }
}


/* OutlineNameTable_DeleteLineUpdate
 * ---------------------------------
 *
 *      Update the table when a line at nDeleteIndex is removed
 */
void OutlineNameTable_DeleteLineUpdate(LPOUTLINENAMETABLE lpOutlineNameTable, int nDeleteIndex)
{
   LPOUTLINENAME lpOutlineName;
   LINERANGE lrSel;
   int i;
   BOOL fRangeModified = FALSE;

   for(i = 0; i < lpOutlineNameTable->m_nCount; i++) {
      lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i);
      OutlineName_GetSel(lpOutlineName, &lrSel);

      if((int)lrSel.m_nStartLine > nDeleteIndex) {
         lrSel.m_nStartLine--;
         fRangeModified = !fRangeModified;
      }
      if((int)lrSel.m_nEndLine >= nDeleteIndex) {
         lrSel.m_nEndLine--;
         fRangeModified = !fRangeModified;
      }

      // delete the name if its entire range is deleted
      if(lrSel.m_nStartLine > lrSel.m_nEndLine) {
         OutlineNameTable_DeleteName(lpOutlineNameTable, i);
         i--;  // re-examine this name
      } else {
         OutlineName_SetSel(lpOutlineName, &lrSel, fRangeModified);
      }
   }
}


/* OutlineNameTable_SaveSelToStg
 * -----------------------------
 *
 *      Save only the names that refer to lines completely contained in the
 * specified selection range.
 */
BOOL OutlineNameTable_SaveSelToStg(
      LPOUTLINENAMETABLE      lpOutlineNameTable,
      LPLINERANGE             lplrSel,
      UINT                    uFormat,
      LPSTREAM                lpNTStm
)
{
   HRESULT hrErr;
   ULONG nWritten;
   LPOUTLINENAME lpOutlineName;
   short nNameCount = 0;
   BOOL fNameSaved;
   BOOL fStatus;
   int i;
   LARGE_INTEGER dlibZeroOffset;
   LISet32( dlibZeroOffset, 0 );

   /* initially write 0 for count of names. the correct count will be
   **    written at the end when we know how many names qualified to
   **    be written (within the selection).
   */
   hrErr = lpNTStm->lpVtbl->Write(
         lpNTStm,
         (short FAR*)&nNameCount,
         sizeof(nNameCount),
         &nWritten
   );
   if (hrErr != NOERROR) {
      OleDbgOutHResult("Write NameTable header returned", hrErr);
      goto error;
    }

   for(i = 0; i < lpOutlineNameTable->m_nCount; i++) {
      lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i);
      fStatus = OutlineName_SaveToStg(
            lpOutlineName,
            lplrSel,
            uFormat,
            lpNTStm,
            (BOOL FAR*)&fNameSaved
      );
      if (! fStatus) goto error;
      if (fNameSaved) nNameCount++;
   }

   /* write the final count of names written. */
   hrErr = lpNTStm->lpVtbl->Seek(
         lpNTStm,
         dlibZeroOffset,
         STREAM_SEEK_SET,
         NULL
   );
   if (hrErr != NOERROR) {
      OleDbgOutHResult("Seek to NameTable header returned", hrErr);
      goto error;
    }

   hrErr = lpNTStm->lpVtbl->Write(
         lpNTStm,
         (short FAR*)&nNameCount,
         sizeof(nNameCount),
         &nWritten
   );
   if (hrErr != NOERROR) {
      OleDbgOutHResult("Write NameTable count in header returned", hrErr);
      goto error;
    }

   OleStdRelease((LPUNKNOWN)lpNTStm);
   return TRUE;

error:
   if (lpNTStm)
      OleStdRelease((LPUNKNOWN)lpNTStm);

   return FALSE;
}


/* OutlineNameTable_LoadFromStg
 * ----------------------------
 *
 *      Load Name Table from file
 *
 *      Return TRUE if ok, FALSE if error
 */
BOOL OutlineNameTable_LoadFromStg(LPOUTLINENAMETABLE lpOutlineNameTable, LPSTORAGE lpSrcStg)
{
   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;
   HRESULT hrErr;
   IStream FAR* lpNTStm;
   ULONG nRead;
   short nCount;
   LPOUTLINENAME lpOutlineName;
   BOOL fStatus;
   short i;

   hrErr = lpSrcStg->lpVtbl->OpenStream(
         lpSrcStg,
         OLESTR("NameTable"),
         NULL,
         STGM_READ | STGM_SHARE_EXCLUSIVE,
         0,
         &lpNTStm
   );
   if (hrErr != NOERROR) {
      OleDbgOutHResult("OpenStream NameTable returned", hrErr);
      goto error;
    }

   hrErr = lpNTStm->lpVtbl->Read(lpNTStm,&nCount,sizeof(nCount),&nRead);
   if (hrErr != NOERROR) {
      OleDbgOutHResult("Read NameTable header returned", hrErr);
      goto error;
    }

   for (i = 0; i < nCount; i++) {
      lpOutlineName = OutlineApp_CreateName(lpOutlineApp);
      if (! lpOutlineName) goto error;
      fStatus = OutlineName_LoadFromStg(lpOutlineName, lpNTStm);
      if (! fStatus) goto error;
      OutlineNameTable_AddName(lpOutlineNameTable, lpOutlineName);
   }

   OleStdRelease((LPUNKNOWN)lpNTStm);
   return TRUE;

error:
   if (lpNTStm)
      OleStdRelease((LPUNKNOWN)lpNTStm);

   return FALSE;
}
