/*************************************************************************
** 
**    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;

char ErrMsgNameTable[] = "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;

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

    SendMessage(
            lpOutlineNameTable->m_hWndListBox,
            LB_GETTEXT,
            nIndex,
            (LPARAM)(LPCSTR)&lpOutlineName
    );
    return lpOutlineName;
}


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

    for (i = 0; i < lpOutlineNameTable->m_nCount; i++) {
        lpOutlineName = OutlineNameTable_GetName(lpOutlineNameTable, i);
        if (lstrcmp(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, LPSTORAGE lpDestStg)
{
    HRESULT hrErr;
    IStream FAR* lpNTStm;
    ULONG nWritten;
    LPOUTLINENAME lpOutlineName;
    ULONG nNameCount = 0;
    BOOL fNameSaved;
    BOOL fStatus;
    int i;
    LARGE_INTEGER dlibZeroOffset;
    LISet32( dlibZeroOffset, 0 );

    hrErr = lpDestStg->lpVtbl->CreateStream(
            lpDestStg, 
            "NameTable", 
            STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
            0,
            0,
            &lpNTStm
    );

    if (! OleDbgVerifySz(hrErr == NOERROR, 
                                    "Could not create NameTable stream")) {
        OleDbgOutHResult("NameTable CreateStream returned", hrErr);
        goto error;
    }

    /* 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,
            (int FAR*)&nNameCount, 
            sizeof(int),
            &nWritten
    );
    
    if (! OleDbgVerifySz(hrErr == NOERROR,
                                "Could not write header to NameTable stream"))
        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 (! OleDbgVerifySz(hrErr == NOERROR, "Error writing NameTable header")) 
        goto error;

    hrErr = lpNTStm->lpVtbl->Write(
            lpNTStm,
            (int FAR*)&nNameCount, 
            sizeof(int),
            &nWritten
    );
    if (! OleDbgVerifySz(hrErr == NOERROR, "Error writing NameTable header")) 
        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;
    int nCount;
    LPOUTLINENAME lpOutlineName;
    BOOL fStatus;
    int i;

    hrErr = lpSrcStg->lpVtbl->OpenStream(
            lpSrcStg, 
            "NameTable",
            NULL,
            STGM_READ | STGM_SHARE_EXCLUSIVE,
            0,
            &lpNTStm
    );

    if (! OleDbgVerifySz(hrErr == NOERROR, "Could not open NameTable stream"))
        goto error;

    hrErr = lpNTStm->lpVtbl->Read(lpNTStm,&nCount,sizeof(nCount),&nRead);

    if (! OleDbgVerifySz(hrErr == NOERROR, 
                            "Could not read header from NameTable stream")) 
        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;
}
