#include <fstream>
#include <cstdio>

#include "myDbEnv.hpp"
#include "myXmlContainer.hpp"

using namespace DbXml;

void usage()
{
     std::cerr <<    "This program replaces the index for a document node.  You should pre-load the\n"
               <<    "container using loadExamplesData.[sh|cmd]  before running this example. You\n"
               <<    "are only required to pass this command the path on of the database environment\n"
               <<    "that you specified when you pre-loaded the examples data:\n\n"

               <<     "\t-h <dbenv directory>\n\n"

               <<    "Also, for best results run addIndex before running this program.\n" << std::endl;
        exit( -1 );
}


void replaceIndex( XmlContainer &container, const std::string &URI, 
                   const std::string &nodeName, const std::string &indexType,
                   DbTxn *txnid)
{
    std::cout << "Replacing index on node: " << nodeName << std::endl;
    try
    {
        //Retrieve the XmlIndexSpecification from the container
        XmlIndexSpecification idxSpec=container.getIndexSpecification( txnid );

        //Lets see what indexes exist on this container
        std::string uri, name, index;
        int count = 0;
        std::cout << "Before index add." << std::endl;
        while( idxSpec.next(uri, name, index) )
        {
            // Obtain the value as a string and print it to the console
            std::cout << "\tFor node '" << name << "', found index: '" << index << "'." << std::endl;
            count ++;
        }

        std::cout << count << " indexes found." << std::endl;

        //Replace the indexes for the specified node
        idxSpec.replaceIndex( URI, nodeName, indexType );


        //Set the specification back to the container
        container.setIndexSpecification( txnid, idxSpec );

        //Look at the indexes again to make sure our replacement took.
        count = 0;
        idxSpec.reset();
        std::cout << "After index add." << std::endl;
        while( idxSpec.next(uri, name, index) )
        {
            // Obtain the value as a string and print it to the console
            std::cout << "\tFor node '" << name << "', found index: '" << index << "'." << std::endl;
            count ++;
        }

        std::cout << count << " indexes found." << std::endl;

    }
    //Catches XmlException
    catch(std::exception &e)
    {
        std::cerr << "Index replace failed: \n";
        std::cerr << e.what() << "\n";

        //Abort the transaction. All changes made to the database since the start
        //of this transaction are discarded.
        txnid->abort();

        exit( -1 );
    }
    std::cout << "Index replaced successfully." << std::endl;
    
}

int main(int argc, char **argv)
{

    std::string path2DbEnv;
    std::string theContainer = "namespaceExampleData.dbxml";
    for ( int i=1; i<argc; i++ )
    {
        if ( argv[i][0] == '-' )
        {
            switch(argv[i][1])
            {
              case 'h':
                path2DbEnv = argv[++i];
                break;
              default:
                usage();
            }
         }
     }

     if (! path2DbEnv.length() )
        usage();

    //Open the environment and the container
    myDbEnv theDBEnv( path2DbEnv ); 
    myXmlContainer openedContainer( theContainer, theDBEnv );


    //myDbEnv and myXmlContainer open with transactions. All subsequent
    //writes to them must also be performed inside a transaction.

    //Get a transaction
    DbTxn *txn;
    theDBEnv.getDbEnv().txn_begin(0, &txn, 0);


    //replace the index on the "product" node.
    replaceIndex( openedContainer.getContainer(), "", "product", 
                  "node-attribute-substring-string node-element-equality-string",
                  txn );

    txn->commit( 0 );


    return 0;


}

