/* OdmJniView.java 0.11              UTF-8                   dh:2007-01-25
 *
 * The OdmJniView class implements the the OdmWorkingDocument interface for
 * a view-only document.  This is the first document object implemented with
 * ODMJNI.
 *
 */

package info.odma.odmjni100;

class OdmJniView
        extends info.odma.practical100.OdmNullWorkingDocument
        implements info.odma.practical100.OdmViewingDocument,
                   info.odma.practical100.OdmWorkingDocument

{   /* Class instance construction */

    final info.odma.practical100.OdmNull nullDocument;
        /* A reference to the OdmNullCache provided by OdmApp
           for use by methods of this implementation.
           */

    long rNativeDocument;
        /* The disguised reference to a Native document interface that
           this OdmJniView instance will use as a handle to native methods
           that coordinate with the native class instance.
           */

    boolean isAvailable;
        /* Automatically true until the interface is released */

    private boolean isDmsAvailable;
        /* Automatically true until the interface is released */

    private boolean isOperationSucceeded;
        /* Automatically true until the interface is released */

    private boolean isLocalOperationRequested;
        /* Automatically false until the interface is released */

    boolean isViewOnly;
        /* For OdmJniView, true until the interface is released */

    private boolean knowDocId;
    private java.lang.String ourDocId;
        /* Cache for docID() */

    private boolean knowDocLocation;
    private java.lang.String ourDocLocation;
        /* Cache for docLocation() */

    private boolean knowWinTitle;
    private java.lang.String ourWinTitle;
        /* Cache for windowTitle() */

    private boolean knowDmsAuthor;
    private java.lang.String ourDmsAuthor;
        /* Cache for dmsAuthor() */

    private boolean knowDmsDocName;
    private java.lang.String ourDmsDocName;
        /* Cache for dmsDocName() */

    private boolean knowDmsDocType;
    private java.lang.String ourDmsDocType;
        /* Cache for dmsDocType() */

    private boolean knowDmsFormatName;
    private java.lang.String ourDmsFormatName;

    void resetProps()
    {   /* Internal method for resetting all of the document properties
           initially, on release, and any time where a change in document
           state may alter the previously-known values.
           XXX: The docLocation parameter is not expected to change when
                something like a commitChanges() occurs.  However, to be
                consistent we treat it as variable too, just to be
                consistent and just in case.
           */

        knowDocId = false;          ourDocId = null;
        knowDocLocation = false;    ourDocLocation = null;
        knowWinTitle = false;       ourWinTitle = null;
        knowDmsAuthor = false;      ourDmsAuthor = null;
        knowDmsDocName = false;     ourDmsDocName = null;
        knowDmsDocType = false;     ourDmsDocType = null;
        knowDmsFormatName = false;  ourDmsFormatName = null;

        } /* resetProps */



    OdmJniView(long rNativeDoc, info.odma.practical100.OdmNull nullDoc)
    {   /* We simply expand the OdmNullDocument operation */

        /* Preconditions:
                This constructor is never used unless rNativeDoc
                is a disguised interface pointer for a successfully-
                created Native document interface to an already-
                opened and only-viewable document.
                */

        super(0);
            /* Build atop a failed OdmNullWorkingDocument */

        nullDocument = nullDoc;

        rNativeDocument
          = info.odma.odmjni100.OdmJniBind.holdNativeInterface(rNativeDoc);

        isAvailable = true;
        isDmsAvailable = true;
        isOperationSucceeded = true;
        isLocalOperationRequested = false;
        isViewOnly = true;

        resetProps();

        } /* OdmJniView */


    /* OdmInterface Interface Method Implementations
     * ---------------------------------------------
     */

    public java.lang.String interfaceImplementation()
    {
        return "ODMJNI 1.0 OdmJniView 0.11 OdmWorkingDocument";
            /* Over-ride with our identification. */

        } /* interfaceImplementation */


    public boolean available()
    {   /* When this object is constructed, it must be because
           there is an available ODMA Connection Manager.
           */

        return isAvailable;

        /* When this object is released, isAvailable is set to
           false.
           */

        } /* available */


    public void release()
    {   /* Release all of our resources, setting ourselves for null
           responses.  Then release resources of the object we extend.

           XXX: This could be simplified a little by making the methods
                all key off of isOperationSucceeded and not have to
                initialize and re-initialize everything.  I like the
                idea of cutting down on the amount of decision making
                though, even though one must be more careful with the
                approach taken here and in the constructor.
           */

        resetProps();

        isAvailable = false;
        isDmsAvailable = false;
        isOperationSucceeded = false;
        isLocalOperationRequested = true;
        isViewOnly = false;

        info.odma.odmjni100.OdmJniBind.freeNativeInterface(rNativeDocument);
        rNativeDocument = 0;
            /* Ensures that the prop methods behave properly if used after
               a release. */

        super.release();

        } /* release */


    public void finalize()
                   throws Throwable
    {   /* We must do this, in case this object becomes inaccessible
           without release() having been performed.  This is how
           we intend to clean up after ourselves no matter what.

           The throw clause is required by finalize() inheritance from
           java.lang.Object.  No checked exceptions arise from the
           implementation here.
           */

        release();

        super.finalize();

        } /* finalize */



    /* OdmDocument Interface Method Implementations
     * --------------------------------------------
     *
     * These methods indicate that the operationSucceeded() or else we
     * wouldn't be here.  After release, the default localOperationRequested
     * condition will apply.  operationCancelled() is always false and
     * supplied by our parent class.
     */

    public boolean dmsAvailable()
    {   /* True for instances of this class until set false on release.
           The variable is only set in the constructor (true) and in
           the release method (false). */

        return isDmsAvailable;

        } /* dmsAvailable */


    public boolean operationSucceeded()
    {
        return isOperationSucceeded;

        } /* operationSucceeded */


    public boolean localOperationRequested()
    {
        return isLocalOperationRequested;

        } /* localOperationRequested */



    /* OdmViewingDocument Interface Method Implementations
     * ---------------------------------------------------
     */

    public boolean viewOnly()
    {   /* For OdmJniView, this method returns true until the
           implementation is released.
           */

        return isViewOnly;

        } /* viewOnly */



    public java.lang.String docID()
    {
        /* Cache the string if necessary, then return the same value
           until the cache is obsoleted for any reason.
           */

        if (!knowDocId)
             {  /* We will know it one way or the other now. */
                knowDocId = true;
                if (rNativeDocument == 0)
                     ourDocId = null;
                else ourDocId = jniDocID(rNativeDocument);
                }

        return ourDocId;

        } /* docID */


    private static native java.lang.String jniDocID(long rIface);
        /* The only place where we fish out docID results */



    public java.lang.String docLocation()
    {
        /* Cache the string if necessary, then return the same value
           until the cache is obsoleted for any reason.
           */

        if (!knowDocLocation)
             {  /* We will know it one way or the other now. */
                knowDocLocation = true;
                if (rNativeDocument == 0)
                     ourDocLocation = null;
                else ourDocLocation = jniDocLoc(rNativeDocument);
                }

        return ourDocLocation;

        } /* docLocation */


    private static native java.lang.String jniDocLoc(long rIface);
        /* The only place where we fish out docLoation results */


    private static native
        java.lang.String jniDocProp(long rIface, int itemNum);
            /* Uses an ODMA item number for the document property
               being requested:

                    ODM_TITLETEXT  4   windowTitle value
                       ODM_AUTHOR  1  dmsAuthor value
                         ODM_NAME  2  dmsDocName value
                         ODM_TYPE  3  dmsDocType value
                ODM_CONTENTFORMAT  6  dmsFormatName value

               These are the only cases supported by OdmNative100.
               Any of these can return a null string.

               */

    public java.lang.String windowTitle()
    {
        if (!knowWinTitle)
             {  /* We will know it one way or the other now. */
                knowWinTitle = true;
                if (rNativeDocument == 0)
                     ourWinTitle = null;
                else ourWinTitle = jniDocProp(rNativeDocument, 4);
                }

        return ourWinTitle;

        } /* windowTitle */



    public java.lang.String dmsAuthor()
    {
        if (!knowDmsAuthor)
             {  /* We will know it one way or the other now. */
                knowDmsAuthor = true;
                if (rNativeDocument == 0)
                     ourDmsAuthor = null;
                else ourDmsAuthor = jniDocProp(rNativeDocument, 1);
                }

        return ourDmsAuthor;

        } /* dmsAuthor */



    public java.lang.String dmsDocName()
    {
        if (!knowDmsDocName)
             {  /* We will know it one way or the other now. */
                knowDmsDocName = true;
                if (rNativeDocument == 0)
                     ourDmsDocName = null;
                else ourDmsDocName = jniDocProp(rNativeDocument, 2);
                }

        return ourDmsDocName;


        } /* dmsDocName */



    public java.lang.String dmsDocType()
    {
        if (!knowDmsDocType)
             {  /* We will know it one way or the other now. */
                knowDmsDocType = true;
                if (rNativeDocument == 0)
                     ourDmsDocType = null;
                else ourDmsDocType = jniDocProp(rNativeDocument, 3);
                }

        return ourDmsDocType;

        } /* dmsDocType */



    public java.lang.String dmsFormatName()
    {
        if (!knowDmsFormatName)
             {  /* We will know it one way or the other now. */
                knowDmsFormatName = true;
                if (rNativeDocument == 0)
                     ourDmsFormatName = null;
                else ourDmsFormatName = jniDocProp(rNativeDocument, 6);
                }

        return ourDmsFormatName;

        } /* dmsFormatName */



    public info.odma.practical100.OdmPendingDocument
                    transferToNewDocument(java.lang.String docFormatName)
                    throws info.odma.practical100.OdmError

    {   /* This is a valid operation here.

           If OdmJniView.operationSucceeded() is false, we will go to our
           null case.  Otherwise, we behave much the same as an
           acceptNewDocument, even though the native implementation is
           quite different.
           */

        /* FIXME: The docFormatName should be validated first and
                  that case thrown if appropriate.  Also, it looks as if
                  this should be part of an independent interface variant,
                  since one might want to deliver view capability to a
                  related function without empowering transferToNewDocument
                  any more than commitChanges.
           */

        if (!operationSucceeded())
             return super.transferToNewDocument(docFormatName);

        long rIpend = jniToNewDoc(rNativeDocument, docFormatName);

        int iStatus =
                info.odma.odmjni100.OdmJniBind.getInterfaceStatus(rIpend);

        if (rIpend == 0 || iStatus > 0)

             switch (iStatus)
             {  case(2):
                     return nullDocument.pendingCancelled();
                case(6):
                     return nullDocument.pendingLocalOperation();
                default:
                     return nullDocument.pendingFailed();
                }

        /* We have a successful result.  Deliver it to the application
           as an OdmJniPend OdmPendingDocument implementation.
           */

        info.odma.practical100.OdmPendingDocument odmPending = null;

        try
        {   odmPending = new info.odma.odmjni100.OdmJniPend
                                   (rIpend, nullDocument);
            }
        catch (java.lang.Throwable e) {  }

        info.odma.odmjni100.OdmJniBind.freeNativeInterface(rIpend);

        if (odmPending == null)
             return nullDocument.pendingFailed();

        return odmPending;

        } /* transferToNewDocument */


    private static native
        long jniToNewDoc(               long rIodmWorking,
                            java.lang.String docFormatName
                            );
            /* Return an IodmPending100 reference based on the result
               of the ODMSaveAs and related operation using IodmWorking100
               functions.  If creation of a pending document is
               unsuccessful, the status value will be one of the following:

                    0 ODM_SUCCESS (but non-null Interface reference)
                      there is a held IodmPending100 reference.

                    2 ODM_E_CANCEL
                      nullDocument.pendingCancelled() indicated

                    6 ODM_E_APPSELECT
                      nullDocument.pendingLocalOperation() called for

                other same as ODM_E_FAIL (1)
                      nullDocument.pendingFailed() called for
               */



    /* OdmWorkingDocument Interface Method Implementations
     * ---------------------------------------------------
     */


        /* The null commitChanges() operation applies here,
           and only OdmJniWrk needs to implement anything. */


    static

        {   /* Static initialization of this class specifies the
               loading of the only DLL used with odmjni100. */

            System.loadLibrary("odmjni100");

            } /* static initialization */

    } /* OdmJniView */


/* 0.11 2007-01-25-15:00 Correct failure to release a temporarily held
        rInative interface in transferToNewDocument.
   0.10 2007-01-22-21:45 Implement transferToNewDocument with a native
        method and the usual approach for continuing with a pending
        document.
   0.09 2007-01-13-21:04 Implement isDmsAvailable so that it can over-ride
        the OdmNullWorkingDocument always false case.  The variable was
        being set properly, the method to return it was omitted, defaulting
        to the null implementation.
   0.08 2007-01-09-21:39 Implement remaining 0.30alpha Document Properties.
   0.07 2007-01-09-21:32 Implement 0.30alpha windowTitle and confirm it.
   0.06 2007-01-09-21:22 Add and confirm 0.30alpha docLocation approach.
   0.05 2007-01-09-21:17 Add and confirm the 0.30alpha docID implementation.
   0.04 2007-01-09-18:20 Add the native methods that support viewing.  There
        are only three: jniDocID, jniDocLocation, and jniDocProp.  There
        will need to be another for transferToNewDocument and OdmJniWork
        will add one for commitChanges.
   0.03 2007-01-09-18:08 Add cache support for the document properties and
        confirm that there is no regression.
   0.02 2007-01-08-23:39 Additional cleanups and working with a cleaned-up
        approach to building classes that doesn't skip failed classes on
        rebuild of sort-of-successful ones.
   0.01 2007-01-07-22:48 Stage 2.4.3 cleanup so that instances can be
        constructed by OdmJniApp and we can then expand as we have more
        native functions for accessing the working-document instance.
   0.00 2006-12-20-21:48 Stage 2.1 version derived from
        OdmNullWorkingDocument and filled in with everything that we can
        provide without actually using any native methods that aren't
        already implemented.

   $Header: /ODMdev/info/odma/odmjni100/OdmJniView.java 18    07-01-25 15:57 Orcmid $
   */

/*        *** end of info.odma.practical100.OdmJniView.java ***         */