package com.sleepycat.dbxml.examples.gettingStarted;

import java.io.*;

import com.sleepycat.dbxml.examples.gettingStarted.myDbEnv;
import com.sleepycat.dbxml.examples.gettingStarted.myXmlContainer;

import com.sleepycat.dbxml.*;
import com.sleepycat.db.*;

class updateDocument
{
    
    private static String theContainer = "namespaceExampleData.dbxml";
    private static void usage()
    {
         String usageMessage = "\nThis program updates a document stored in a DB XML container.\n";
                usageMessage += "You should run exampleLoadContainer before running this example.\n";
                usageMessage += "You are only required to pass this command the path location of the\n";
                usageMessage += "database environment that you specified when you loaded the examples data:\n\n";

                usageMessage += "\t-h <dbenv directory>\n";

                usageMessage += "For example:\n";
                usageMessage += "\tjava com.sleepycat.dbxml.examples.gettingStarted.updateDocument -h examplesEnvironment\n";

         System.out.println(usageMessage);
         System.exit( -1 );
    }

    //Modifies an XML document that is stored in a DB XML container
    private static void doUpdateDocument( XmlContainer container, String XPath, 
                                          XmlQueryContext context, DbTxn txn ) throws Throwable
    {
           System.out.println("Updating documents for expression: '" + XPath + "'.");
           System.out.println("Return to continue: ");
           System.in.read();

           //query for all the documents that we want to update
           XmlResults results = container.queryWithXPath(txn, XPath, context, 0);
           System.out.println("Found " + results.size() + " matching the expression '" + XPath + "'.");

           XmlDocument document = new XmlDocument();
           while (results.next(document)) {
                //Retrieve the entire document as a single String object
                String docString = document.getContentAsString();
                System.out.println("Updating document: ");
                System.out.println(docString);

                //This next method just modifies the document string
                //in a small way.
                String newDocString = getNewDocument(document, context, docString);

                System.out.println("Updating document...");

                //Set the document's content to be the new document string
                document.setContent(newDocString);

                //Now replace the document in the container
                container.updateDocument(txn, document, null);
                System.out.println("Document updated.");

           }
    }

    private static String getNewDocument( XmlDocument document, XmlQueryContext context, String docString ) throws Throwable
    {
            //Get the substring that we want to replace
            String inventory = getValue(document, "/*/inventory/inventory/text()", context);
            String retVal = new String();

            //Find the substring in the original document string
            int pos = docString.indexOf(inventory);
            if (pos == -1) {
                System.err.println("Error: inventory string: '" + inventory + "' not found in document string:");
                System.err.println(docString);

            } else {
               //Convert the String representation of the inventory level to an integer,
               // increment by 1, and then convert back to a String for replacement on 
               // the document.
               int newInventory = Integer.parseInt(inventory) + 1;
               String newVal = Integer.toString(newInventory);

               int inventoryLength = inventory.length();
               int endPos = pos + inventoryLength;

               StringBuffer strbuff = new StringBuffer(document.getContentAsString());

               //Perform the replace
               strbuff.replace(pos, endPos, newVal);
               System.out.println("Inventory was " + inventory + ", it is now " + newVal + ".");
               retVal = strbuff.toString();
           }

           return retVal;
    }

    private static String getValue( XmlDocument theDocument, String XPath, XmlQueryContext context ) throws Throwable
    {
        /////////////////////////////////////////////////////////////////////////////////
        ///////////    Return specific information from a document. ///////////////////// 
        ///////////   !!!!!! Assumes a result set of size 1 !!!!!!! /////////////////////
        /////////////////////////////////////////////////////////////////////////////////


        //We don't want a document, we want a specific value. So set the
        //return type to Result Values
        context.setReturnType(XmlQueryContext.ResultValues);

        //Perform the query
        XmlResults result = theDocument.queryWithXPath(XPath, context);

        //We require a result set size of 1.
        if (result.size() != 1) {
             System.err.println("Error! XPath query '" + XPath + "' returned a result size size != 1");
             throw new Exception( "getValue found result set not equal to 1.");
        }

        //Get the value. If we allowed the result set to be larger than size 1,
        // we would have to loop through the results, processing each as is
        // required by our application.
        XmlValue value = result.next();

        //Set the result type back to Result Document
        context.setReturnType(XmlQueryContext.ResultDocuments);
        return value.asString(null);
    }


    public static void main(String args[]) throws Throwable
    {

       File path2DbEnv = null;
       for(int i = 0; i < args.length; ++i) 
       {
            if (args[i].startsWith("-")) {
               switch(args[i].charAt(1)) {
                    case 'h':
                         path2DbEnv = new File( args[++i] );
                         break;
                    default:
                    usage();
               }
            } 
       }


       if (path2DbEnv == null || ! path2DbEnv.isDirectory()) {
            usage();
       }


       myDbEnv theDBEnv = null;
       myXmlContainer openedContainer = null;
       DbTxn txn = null;
       try
       {
            theDBEnv = new myDbEnv(path2DbEnv);
            openedContainer = new myXmlContainer(theContainer, theDBEnv);

            //Get a transaction
            txn = theDBEnv.getDbEnv().txnBegin(null, 0);

            //Create a context and declare the namespaces
            XmlQueryContext context = new XmlQueryContext(XmlQueryContext.ResultDocuments, XmlQueryContext.Eager);
            context.setNamespace( "fruits", "http://groceryItem.dbxml/fruits");
            context.setNamespace( "vegetables", "http://groceryItem.dbxml/vegetables");
            context.setNamespace( "desserts", "http://groceryItem.dbxml/desserts");

	    //update the document that describes Zapote Blanco (a fruit)
            String query = "/fruits:item/product[text() = 'Zapote Blanco']";
            doUpdateDocument(openedContainer.getContainer(), query, context, txn);

            //Commit the writes. This causes the container write operations
            //  to be saved to the container.
            txn.commit(0);

       } catch (Exception e) {

           System.err.println("Error performing document update against " + theContainer);
           System.err.println("   Message: " + e.getMessage());
           //In the event of an error, we abort the operation
           // The database is left in the same state as it was in before
           // we started this operation.
           if ( txn != null ) {
              txn.abort();
           }
           throw e;

       } finally {
            if (openedContainer != null) {
               openedContainer.cleanup();
            }

            if (theDBEnv != null) {
               theDBEnv.cleanup();
            }
       }

    } //End main

}
