/*
 *  Copyright 1995,1996,1997 by the Association for Information and Image Management Int'l
 *                                             1100 Wayne Avenue
 *                                             Silver Spring, MD 20910-5603
 *                                             Tel: 301/587-8202
 *                                             Fax: 301/587-2711
 *      All Rights Reserved.
 *      DMA (Document Management Alliance) working group.
 *
 *  Code example: editing a document in DMA 1.0.
 *  
 */

#ifndef NULL
#define NULL    0
#endif

// ANSI C header file
#include <stddef.h>

// DMA header files
#include <dmatypes.h>
#include <dmastr.h>
#include <dmaenums.h>
#include <dmarc.h>  
#include <dmacom.h>
#include <dmaiface.h>
#include <dmaids.h>

#define  DMA_INIT_ID
#include <dmaidvar.h>

#define sampleProp_AuthorVal {0x0L, 0xBADL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}

DMA_DECL_ID(sampleProp_Author)

// Code example: editing a document in DMA 1.0.

// A completely artificial example that changes the "author" property
//  on an existing document and adds a new PDF rendition or replaces
//  the one that's there.

// Assumes that connections to system and doc space have already been
// made, that the doc id of the target document has been found
// (by search or navigation), and that documents are not versioned.

// Assumes the doc ver has a DmaString-valued property "author".

// forward refs to helper routines 
LPIdmaEditProperties MakeRendition(DmaWChar *,DmaWChar *);  
DmaRC                ReportError(DmaRC, char *msg);

// Utilities assumed to exist
extern DmaBoolean EqualDmaString(pDmaString, pDmaString);

// Assume these interface pointers have been initialized
LPMALLOC      iMalloc;
LPIdmaSystem   iSystem;    /* interface on system object */
LPIdmaDocSpace iDocSpace;  /* interface on the connected doc space */

Abort(DmaRC rc, char *msg)
{
return(rc);
}

// Procedure to do the edits.  Last argument is a URL giving path name 
//  to the PDF file that is to become the new rendition

EditStuff(pDmaString documentID, DmaWChar* newAuthor, DmaWChar* pdfFile)
{
DmaRC      rc;
IdmaEditProperties*    iDocProps = NULL;
IdmaEditProperties*    iRenditionObj = NULL;
IdmaListOfString*      iRenditionsPresent = NULL;
IdmaEditListOfObject*  iRenditions = NULL;
IdmaList*              iRendList = NULL;
IdmaConnection*        iDocConnection = NULL;
DmaIndex32             nRenditions;
pDmaString             authorString = NULL;
pDmaString             PDFTYPE = NULL; 
pDmaString             renditionType = NULL;

// Connect to the document version object.  This makes a snapshot
// of the persistent doc ver in the client's process space.

rc = iDocSpace->ConnectObject (documentID, IID_IdmaEditProperties,
                               (pDmapv) &iDocProps);
if (rc != DMARC_OK)
   Abort (rc, "Failed to connect to doc ver");

// NOTE: for brevity, further error checking is omitted.  All DMA calls
//   should be followed by code similar to the above

//  Change the author property
if (newAuthor != NULL)
    {
    DMA_CREATE_STRING (iMalloc->Alloc, 21, newAuthor, &authorString);
    rc = iDocProps->PutPropValStringById(&sampleProp_Author, authorString);
    }

// Make our PDF rendition file into a DMA rendition object.
DMA_CREATE_STRING (iMalloc->Alloc, 21, L"MIME::application/PDF", &PDFTYPE);
iRenditionObj = MakeRendition(pdfFile, PDFTYPE);
if (iRenditionObj == NULL)
    Abort(DMARC_NO_MEMORY , "MakeRendition Failed");

// Get the RenditionsPresent property and check to see if a PDF
// rendition is present.  Since IdmaListOfString inherits from
// IdmaList, it also has a GetCount method.
rc = iDocProps->GetPropValObjectById(&dmaProp_RenditionsPresent,
                    IID_IdmaListOfString, (pDmapv) iRenditionsPresent);
rc = iRenditionsPresent->GetElementCount(&nRenditions);

int noPDF = 1;
rc = iDocProps->GetPropValObjectById(&dmaProp_Renditions,
                IID_IdmaEditListOfObject, (pDmapv) iRenditions);
for (int i = 0; i < nRenditions; i++)
    {
    rc = iRenditionsPresent->GetString(i, &renditionType);
    if (EqualDmaString(renditionType, PDFTYPE))
        {
        rc =iRenditions->ReplaceObject(i, &iRenditionObj);
        noPDF = 0;
        }
    DMA_FREE_STRING(iMalloc->Free, renditionType);
    }
if (noPDF)
    {
    rc =iRenditions->InsertObject(nRenditions, &iRenditionObj);
    }
// Make the changes persistent

rc = iDocProps->QueryInterface(IID_IdmaConnection, (pDmapv)  &iDocConnection);
rc = iDocConnection->ExecuteChange(NULL,DMA_MODIFY_UNPROTECTED,DMA_FALSE);

// cleanup
if (iDocProps != NULL) iDocProps->Release();
if (iRenditionObj != NULL) iRenditionObj->Release();
if (iRenditions != NULL) iRenditions->Release();
if (iRenditionsPresent != NULL) iRenditionsPresent->Release();
if (iDocConnection != NULL) iDocConnection->Release();

DMA_FREE_STRING(iMalloc->Free, authorString);
DMA_FREE_STRING(iMalloc->Free, PDFTYPE);
return(DMARC_OK);
}

// Create a DMA rendition object of the indicated type.  The rendition
// will have one content transfer element, whose content is named by the URL 
// indicated by contentURL.

// Returns a pointer to the IdmaEditProperties interface on the new
// rendition, or NULL if the process failed for any reason.

// Ownership of the returned object and its content element and DMAStrings 
// passes to the caller.

IdmaEditProperties* MakeRendition(DmaWChar* contentURL, DmaWChar* renditionType)
{
IdmaEditProperties*     iContentEl  = NULL;
IdmaEditProperties*     iRenditionProps = NULL;
IdmaContentTransfer*    iContentTr = NULL;
IdmaEditListOfObject*   iContentEls = NULL;
IdmaObjectFactory*      iObjFactory = NULL;
pDmaString              contentURLString = NULL;
pDmaString              rendType = NULL;
pDmaString              componentType = NULL;

// check arguments and convert to DMAStrings
if ((contentURL == NULL) || (wcslen(contentURL) == 0) ||
   (renditionType == NULL) || (wcslen(renditionType) == 0))
    return (NULL);
else
    {
    DMA_CREATE_STRING (iMalloc->Alloc, wcslen(renditionType), renditionType, &rendType);
    DMA_CREATE_STRING (iMalloc->Alloc, wcslen(contentURL), contentURL, &contentURLString);
    }

//  Make content transfer element
DmaRC rc = iDocSpace->QueryInterface(IID_IdmaObjectFactory,
                                     (pDmapv) &iObjFactory);
if (rc != DMARC_OK)
   return (NULL);

// error checks omitted on following calls for brevity
rc = iObjFactory->CreateObject(&dmaClass_ContentTransfer,
                 IID_IdmaEditProperties, (pDmapv) &iContentEl);

//  Set properties of the content element.
DMA_CREATE_STRING (iMalloc->Alloc, 6, L"single", &componentType);
rc = iContentEl->PutPropValStringById(&dmaProp_ComponentType, componentType);
rc = iContentEl->QueryInterface(IID_IdmaContentTransfer, (pDmapv) &iContentTr);
rc = iContentTr->SetCaptureResource(contentURLString);

// Make a rendition and add the content element to it
rc = iObjFactory->CreateObject(&dmaClass_Rendition, IID_IdmaEditProperties,
                             (pDmapv)& iRenditionProps);
rc = iRenditionProps->PutPropValStringById(&dmaProp_RenditionType, rendType);
rc = iRenditionProps->GetPropValObjectById(&dmaProp_ContentElements,
                          IID_IdmaEditListOfObject, (pDmapv)&iContentEls); 
rc = iContentEls-> InsertObject(0, iContentEl);

// cleanup
if (iContentEl != NULL) iContentEl->Release();
if (iContentTr != NULL) iContentTr->Release();
if (iContentEls != NULL)  iContentEls->Release();
if (iRenditionProps != NULL) iRenditionProps->Release();
if (iObjFactory != NULL) iObjFactory->Release();

DMA_FREE_STRING(iMalloc->Free, rendType);
DMA_FREE_STRING(iMalloc->Free, componentType);
DMA_FREE_STRING(iMalloc->Free, contentURLString);
return (iRenditionProps);
}