/* CheckUtils.cpp 0.05               UTF-8                    dh:2007-01-19
 *
 * Library of Utilities for the OdmNative100 test\Check confirmation
 * programs.
 *
 */

#include <stdio.h>
    /* For FILE, fputs, stdout, ... */

#include <stdlib.h>
    /* For the system command. */

#include <string.h>
    /* for strncmp in verification of docID and docLocation results
       and for strncpy in exchanging in new docId and docLocation
       values after a commitChanges. */

#include <windows.h>

#include "Odma32types100.h"

#include "OdmWorking100.hpp"

#include "OdmPending100.hpp"

#include "CheckUtils.hpp"


const char* hResultName(HRESULT rc)
{   /* Return the names of the known HRESULT values */

    switch (rc)
    {   case S_OK:
            return "S_OK";
        case E_NOINTERFACE:
            return "E_NOINTERFACE";
        case E_INVALIDARG:
            return "E_INVALIDARG";
        case E_POINTER:
            return "E_POINTER";
        case E_FAIL:
            return "E_FAIL";
        case E_OUTOFMEMORY:
            return "E_OUTOFMEMORY";
        case E_UNEXPECTED:
            return "E_UNEXPECTED";
        case E_NOTIMPL:
            return "E_NOTIMPL";
        case E_HANDLE:
            return "E_HANDLE";
        }

    return "unknown";

    } /* hResultName */



const char* odmStatusName(ODMSTATUS rc)
{   /* Return the names of the known ODMSTATUS values */

    switch (rc)
    {   case ODM_SUCCESS:
            return "ODM_SUCCESS";
        case ODM_E_FAIL:
            return "ODM_E_FAIL";
        case ODM_E_CANCEL:
            return "ODM_E_CANCEL";
        case ODM_E_NODMS:
            return "ODM_E_NODMS";
        case ODM_E_CANTINIT:
            return "ODM_E_CANTINIT";
        case ODM_E_VERSION:
            return "ODM_E_VERSION";
        case ODM_E_APPSELECT:
            return "ODM_E_APPSELECT";
        case ODM_E_USERINT:
            return "ODME_E_USERINT";
        case ODM_E_HANDLE:
            return "ODM_E_HANDLE";
        case ODM_E_ACCESS:
            return "ODM_E_ACCESS";
        case ODM_E_INUSE:
            return "ODM_E_INUSE";
        case ODM_E_DOCID:
            return "ODM_E_DOCID";
        case ODM_E_OPENMODE:
            return "ODM_E_OPENMODE";
        case ODM_E_NOOPEN:
            return "ODM_E_NOOPEN";
        case ODM_E_ITEM:
            return "ODM_E_ITEM";
        case ODM_E_OTHERAPP:
            return "ODM_E_OTHERAPP";
            /* Symbols below here are not defined in Odma32types100.h */
        case 16:
            return "ODM_E_NOMOREDATA (ODMA 1.5 feature)";
        case 17:
            return "ODM_E_PARTIALSUCCESS (ODMA 1.5 feature)";
        case 18:
            return "ODM_E_REQARG (ODMA 2.0 feature)";
        case 19:
            return "ODM_E_NOSUPPORT (ODMA 2.0 feature)";
        case 20:
            return "ODM_E_TRUNCATED (ODMA 2.0 feature)";
        case 21:
            return "ODM_E_INVARG (ODMA 2.0 feature)";
        case 22:
            return "ODM_E_OFFLINE (ODMA 2.0 feature)";
        case 23:
            return "ODM_E_ARCHIVED (ODMA 2.0 UNSPECIFIED)";
        case 24:
            return "ODM_E_ALREADYOPENED (ODMA 2.0 UNSPECIFIED)";
        case 25:
            return "ODM_E_FILELOCKED (ODMA 2.0 UNSPECIFIED)";
        case 26:
            return "ODM_E_REFUSED (ODMA 2.0 UNSPECIFIED)";
        case 27:
            return "ODM_W_NOACTION (ODMA 2.0 UNSPECIFIED)";
        case 28:
            return "ODM_E_NORELATION (ODMA 2.0 UNSPECIFIED)";
        }

    return "(not defined)";

    } /* odmStatusName */



void reportIface(        FILE *out,
                          const char indent[],
                          const char ifaceName[],
                             HRESULT rc,
                                void *pIface
                          )
{   /* Present a Query Interface or similar result */

    fprintf(out, "%s%08p  p%s, ",
                 indent, pIface, ifaceName );

    fprintf(out, "rc = %08X (%s)\n",
                 rc, hResultName(rc) );

    } /* reportIface */


void reportIfaceVersion(     FILE  *out,
                           LPCSTR  indent,
                           LPCSTR  pszText
                           )
{   /* Present the version text nicely below the interface-acquired report.
       The text has '\n' codes and those should be brought to the same
       indentation on subsequent lines.
       */

    if (pszText == NULL) return;

    fputs(indent, out);

    fputs(pszText, out);
        /* FIXME: The lines need to be broken up and indented.
           ***************************************************
           This can be a bonus activity when cleaning up after
           beta release.
           */

    fputs("\n", out);

    } /* reportIfaceVersion */


void reportDocProp(          FILE  *out,
                           LPCSTR  indent,
                   IodmWorking100  *pIodmWrk,
                           LPCSTR  propName,
                             WORD  propNum
                   )

{   /* Report the specified Document Property value, if available. */

    char propVal[300] = {'\0'};
        /* Choose a respectably-large value that will hold whatever we
           can expect to get */

    fputs(indent, out);
    fputs(propName, out);

    ODMSTATUS odmResult
        = pIodmWrk -> docProperty(propNum, propVal, sizeof(propVal) );

    if (propVal[0] == '\0' || odmResult != ODM_SUCCESS)
         {  /* For any null result, say so and translate the result code.
               */

            fputs(" is null (", out);
            fputs(odmStatusName(odmResult), out);
            fputs("\n", out);

            }

    else {  /* Show the value as well as we are able */

            fputs(" = |", out);
            fputs(propVal, out);
            fputs("|\n", out);

                }

    } /* reportDocProp */


void workWork(FILE *out, LPCSTR docIndent,
              LPSTR theDocId, LPSTR theDocLoc,
              IodmWorking100 *pIodmWrk)

{   /* report the Working Document and the any commitChanges cycles.
       The SaveAs cycle does not occur in here, because of issues about
       holding interface pointers.  This just deals with a working
       document and its cycle of commitChanges.  When commit is
       declned, this procedure exits.
       */


    if (pIodmWrk != NULL)
         reportIfaceVersion(  out, docIndent,
                              pIodmWrk -> interfaceImplementation()
                              );

    if (pIodmWrk != NULL)
         {  /* Report the viewOnly setting */

            fputs("\n", out);
            fputs(docIndent, out);
            fputs("viewOnly = ", out);
            fputs( (pIodmWrk -> viewOnly() ? "TRUE" : "FALSE"),
                   out);
            fputs("\n", out);

            }

    LPCSTR dmsDocId = NULL;
    BOOL proceedOK = (pIodmWrk != NULL);

    while (proceedOK)

        {   /* Describe the current document, view the content if
               possible, and check for wanting to commit any changes.
               */

            if (pIodmWrk != NULL)
                 {   /* Verify that docId matches theDocId and report. */

                     dmsDocId = pIodmWrk -> docID();

                     if (strncmp(theDocId, dmsDocId, ODM_DOCID_MAX) )
                          {  /* Oh Oh, the DocIds don't match.
                                */
                             fputs(docIndent, out);
                             fputs("DIFFERENT DOCID VALUE:\n", out);
                             fputs(docIndent, out);
                             fputs(dmsDocId, out);
                             fputs("\n", out);
                             }
                     else {  fputs(docIndent, out);
                             fputs(  "docID matches the selected docID.\n",
                                     out
                                     );
                             }

                     /* Make ours match dmsDocId */

                     strncpy_s(theDocId, ODM_DOCID_MAX,
                               dmsDocId, _TRUNCATE);
                            /* Don't let new Document ID over-run */

                     }

            LPCSTR dmsDocLoc = NULL;

            if (pIodmWrk != NULL)
                 {   /* Verify that docLocation matches theDocLoc. */

                     dmsDocLoc = pIodmWrk -> docLocation();

                     if (strncmp(theDocLoc, dmsDocLoc, ODM_FILENAME_MAX) )
                          {  /* Oh Oh, the DocLocs don't match.
                                */
                             fputs(docIndent, out);
                             fputs("DIFFERENT DOCLOC VALUE:\n", out);
                             fputs(docIndent, out);
                             fputs(dmsDocLoc, out);
                             fputs("\n", out);
                             }
                     else {  fputs(docIndent, out);
                             fputs(  "docLocation matches"
                                     " the opened docLocation.\n",
                                     out
                                     );
                             }

                     /* Make ours match dmsDocLoc */

                     strncpy_s(theDocLoc, ODM_FILENAME_MAX,
                               dmsDocLoc, _TRUNCATE);
                            /* Don't let new Document Location over-run */

                     }


            if (pIodmWrk != NULL)
                 {  /* Report all of the Document Properties */

                    reportDocProp(out, docIndent,
                                  pIodmWrk, "ODM_NAME", ODM_NAME);

                    reportDocProp(out, docIndent,
                                  pIodmWrk, "ODM_AUTHOR", ODM_AUTHOR);

                    reportDocProp(out, docIndent,
                                  pIodmWrk, "ODM_TYPE", ODM_TYPE);

                    reportDocProp(out, docIndent,
                                  pIodmWrk, "ODM_CONTENTFORMAT",
                                  ODM_CONTENTFORMAT);

                    reportDocProp(out, docIndent,
                                  pIodmWrk, "ODM_TITLETEXT", ODM_TITLETEXT);

                    fputs("\n", out);
                    }

            /* Launch the document */

            char cmd[ODM_FILENAME_MAX + sizeof("start ")] = "start ";

            char response[10] = {'\0'};

            strncat_s(cmd, sizeof(cmd),
                      theDocLoc, _TRUNCATE);

            fputs("\n", out);

            if( system(cmd) )
                 {  /* The document did not launch */
                    fputs(docIndent, out);
                    fputs( "*** The Document Failed to Launch ***\n",
                           out);
                    proceedOK = FALSE;
                    }
            else {  /* The document launched.  Let's confirm */
                    fputs(docIndent, out);
                    fputs("Launching the document at docLocation:\n",
                          out);
                    fputs(docIndent, out);
                    fputs(theDocLoc, out);
                    fputs("\n\n", out);
                    fputs(docIndent, out);
                    fputs("Commit Changes? (y/N): ", out);
                    fflush(out);

                    fgets(response, sizeof(response), stdin);
                    if (response[0] == 'N' || response[0] == 'n')
                         proceedOK = FALSE;
                    }

            if (proceedOK && pIodmWrk != NULL)
                 {   /* OK, let's commit the changes */
                     proceedOK = pIodmWrk -> commitChanges();
                     fputs("\n\n", out);
                     fputs(docIndent, out);
                     if (proceedOK)
                          {  fputs("Commit Changes succeeded.\n",
                                   out);
                             }
                     else {  fputs("Commit Changes *** FAILED ***\n",
                                   out);
                             }

                     }

            } /* proceedOK */

    } /* workWork */



BOOL workPending(FILE *out, LPCSTR docIndent,
                 LPSTR theDocLoc,
                 IodmPending100 *pIodmPend)

{   /* Procedure to report the pending document interface, describe the
       state of the pending document, and for an operating interface,
       launch a content editor if possible, find out if the user wants
       to commit content, returning TRUE in that case, FALSE for
       everything else.
       */

    if (pIodmPend != NULL)
         reportIfaceVersion(  out, docIndent,
                              pIodmPend -> interfaceImplementation()
                              );


    BOOL proceedOK = (pIodmPend != NULL);

    LPCSTR dmsDocLoc = NULL;

    if (proceedOK)
         {   /* Verify that docLocation matches theDocLoc. */

             dmsDocLoc = pIodmPend -> docLocation();

             if (strncmp(theDocLoc, dmsDocLoc, ODM_FILENAME_MAX) )
                  {  /* Oh Oh, the DocLocs don't match.
                        */
                     fputs(docIndent, out);
                     fputs("DIFFERENT DOCLOC VALUE:\n", out);
                     fputs(docIndent, out);
                     fputs(dmsDocLoc, out);
                     fputs("\n", out);
                     }
             else {  fputs(docIndent, out);
                     fputs(  "docLocation matches"
                             " the opened docLocation.\n",
                             out);
                     }

             /* Make ours match dmsDocLoc */

             strncpy_s(theDocLoc, ODM_FILENAME_MAX,
                       dmsDocLoc, _TRUNCATE);
                          /* Don't let new Document Location over-run */
             }


    if (proceedOK)
         {  /* Launch the document */

            char cmd[ODM_FILENAME_MAX + sizeof("start notepad ")]
                        = "start notepad ";

            char response[10] = {'\0'};

            strncat_s(cmd, sizeof(cmd),
                      dmsDocLoc, _TRUNCATE);

            fputs("\n", out);

            if( system(cmd) )
                 {  /* The document did not launch */
                    fputs(docIndent, out);
                    fputs( "*** The Document Failed to Launch ***\n",
                           out);
                    proceedOK = FALSE;
                    }
            else {  /* The document launched.  Let's confirm */
                    fputs(docIndent, out);
                    fputs("Launching the document at docLocation:\n",
                          out);
                    fputs(docIndent, out);
                    fputs(theDocLoc, out);
                    fputs("\n\n", out);
                    fputs(docIndent, out);
                    fputs("Commit Content? (y/N): ", out);
                    fflush(out);
                    fgets(response, sizeof(response), stdin);
                    if (response[0] == 'N' || response[0] == 'n')
                         proceedOK = FALSE;
                    }
            }

    return proceedOK;

    } /* workPending */


/* 0.05 2007-01-19-23:05 Instead of running notepad in workPending,
        start notepad on the document.  This should provide for smoother
        operation.

   0.04 2007-01-18-15:35 Correct the workWork and workPending functions to
        input lines and use the response without leaving anything in
        the buffer.

   0.03 2007-01-18-15:08 Correct workPending to launch Notepad explicitly
        because we don't have a document that we can launch from just yet.

   0.02 2007-01-18-13:50 Add workPending to provide a simpler exercise of
        a new IodmPending100 implementation, taking it up through asking
        if commitContent is desired.

   0.01 2007-01-17-19:30 Add workWork for exercising Working Documents
        after they are first produced.  This works through the cycle of
        changes and reporting about it.

   0.00 2007-01-17-17:58 Make initial skeleton and start with the
        utility functions hResultName, odmStatusName, reportIface,
        reportIfaceVersion, reportDocProp.

   $Header: /ODMdev/info/odma/OdmNative100/test/Check06/CheckUtils.cpp 4     07-01-19 23:21 Orcmid $
   */

/*                        *** end of CheckUtils.cpp ***               */
