package org.dbxml.tools;

/*
 * dbXML License, Version 1.0
 *
 *
 * Copyright (c) 1999-2001 The dbXML Group, L.L.C.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by
 *        The dbXML Group (http://www.dbxml.com/)."
 *    Alternately, this acknowledgment may appear in the software
 *    itself, if and wherever such third-party acknowledgments normally
 *    appear.
 *
 * 4. The names "dbXML" and "The dbXML Group" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    info@dbxml.com.
 *
 * 5. Products derived from this software may not be called "dbXML",
 *    nor may "dbXML" appear in their name, without prior written
 *    permission of The dbXML Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE DBXML GROUP OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id: XMLTools.java,v 1.33 2001/08/15 09:48:24 kstaken Exp $
 */

import org.xmldb.api.base.*;
import org.xmldb.api.DatabaseManager;
import org.dbxml.client.xmldb.*;

import org.dbxml.server.util.StringUtilities;
import org.dbxml.server.dbXMLException;
import org.dbxml.core.server.dbXML;

import org.dbxml.tools.command.Command;
import org.dbxml.xml.dom.DOMParser;

import org.w3c.dom.*;

import java.util.Hashtable;
import java.util.Properties;
import java.util.NoSuchElementException;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;


/**
 * XMLAdmin is designed to take command line arguments and give
 * user dbXML management flexibility within the current Database.
 */

abstract class XMLTools {


    public static final String COLLECTION = "collection";
    public static final String EXTENSION = "extension";
    public static final String FILE_PATH = "filePath";
    public static final String ACTION = "action";
    public static final String IMPL_CLASS = "implClass";
    public static final String NAME_OF = "nameOf";
    public static final String XML_OBJECT_URI = "xmlobjecturi";
    public static final String PATTERN = "pattern";
    public static final String QUERY = "query";
    public static final String URI = "uri";
    public static final String VERBOSE = "verbose";
    public static final String FORCE = "force";
    public static final String TYPE = "type";
    public static final String PAGE_SIZE = "pagesize";
    public static final String MAX_KEY_SIZE = "maxkeysize";
    public static final String DB_SERVER = "dbServ";
    public static final String PORT = "port";
    public static final String HOST = "host";
    public static final String USER = "user";
    public static final String PASSWORD = "password";
    public static final String AUTO_KEY = "autoKey";



   private Hashtable table;
   private static boolean verbose = false;
   protected String location = null;


   /** Constructor for XMLTools, includes default variables for the command line
     */
   public XMLTools() {
      table = new Hashtable();
      // defaults for command switches
      table.put( FILE_PATH, "" );
      table.put( EXTENSION, "" );
      table.put( QUERY, "" );
      table.put( AUTO_KEY, "" );
      table.put( FORCE, "" );
      table.put( VERBOSE, "false" );
   }


    private boolean initialized = false;
    /**
     * Carries out necessary initialization of this class.
     **/
    public void init() throws dbXMLException, FileNotFoundException {
       if ( !initialized ) {
           initCommandsDocument();
           initCommandsList();
           initialized = true;
       }
    }
    /**
     * Carries out the initialization of the Commands Document.
     **/
    protected void initCommandsDocument() throws dbXMLException, FileNotFoundException {
       // Absolute path to the commands.xml file, relative to $DBXML_HOME
       File dbxmlHome =  new File( System.getProperty( dbXML.PROP_DBXML_HOME ) );
       File commandsFile = new File( dbxmlHome, "config/commands.xml" );

       DOMParser parser = new DOMParser();
       commandsDocument = parser.toDocument( new FileInputStream( commandsFile ) );
    }
    /**
     * Carries out the initialization of the Commands List.
     **/
    protected abstract void initCommandsList();


    private Document commandsDocument = null;
    /**
     * Returns the Commands Document use for configuration.
     **/
    protected Document getCommandsDocument() {
       return commandsDocument;
    }


    protected NodeList commandsList = null;
    /**
     * Returns the <command> elements from the Commands Document this
     * tool can execute.
     **/
    protected NodeList getCommands() {
       return commandsList;
    }


    /**
     * Returns a boolean value stating if this class has admin access.
     **/
    public abstract boolean isAdmin();


   /**
    * The Process function is designed for the implementation of the
    * command line tools, as well as, making the command line easier
    * to use.
    **/
   public void process(String[] args) throws dbXMLException, Exception {
      try {
         init();
         // parsing arguments for the command tools
         ArgTokenizer at = new ArgTokenizer(args);

         // Action should always be the second token, if not there show help
         if ( at.hasMoreTokens() ) {
            table.put( ACTION , at.nextToken() );
         } else {
            printHelp();
           return;
         }

         // Loop over remaining command line arguments, populating hashtable
         while ( at.hasMoreTokens() ) {
            String token = at.nextToken();

            if ( token.equalsIgnoreCase("-c") || token.equalsIgnoreCase("--collection") ) {
                table.put( COLLECTION, at.nextSwitchToken() );
            } else if ( token.equalsIgnoreCase("-e") || token.equalsIgnoreCase("--extension") ) {
               table.put( EXTENSION, at.nextSwitchToken());
            } else if ( token.equalsIgnoreCase("-f") || token.equalsIgnoreCase("--filepath") ) {
               table.put( FILE_PATH, at.nextSwitchToken());
            } else if ( token.equalsIgnoreCase("-h") || token.equalsIgnoreCase("--help") ) {
               table.put( ACTION, "help");
            } else if ( token.equalsIgnoreCase("-i") || token.equalsIgnoreCase("--implementclass") ) {
               table.put( IMPL_CLASS, at.nextSwitchToken());
            } else if ( token.equalsIgnoreCase("-n") || token.equalsIgnoreCase("--nameOf") ) {
               table.put( NAME_OF, at.nextSwitchToken());
            } else if ( token.equalsIgnoreCase("-o") || token.equalsIgnoreCase("--xmlobjecturi") ) {
                table.put( XML_OBJECT_URI, at.nextSwitchToken());
            } else if ( token.equalsIgnoreCase("-p") || token.equalsIgnoreCase("--pattern") ) {
               table.put( PATTERN, at.nextSwitchToken());
            } else if ( token.equalsIgnoreCase("-q") || token.equalsIgnoreCase("--query") ) {
                table.put( QUERY, at.nextSwitchToken());
            } else if ( token.equalsIgnoreCase("-u") || token.equalsIgnoreCase("--uri") ) {
                table.put( URI, at.nextSwitchToken());
            } else if ( token.equalsIgnoreCase("-v") || token.equalsIgnoreCase("--verbose") ) {
               table.put( VERBOSE, "true");
            } else if ( token.equalsIgnoreCase("-y") || token.equalsIgnoreCase("--yes_force") ) {
               table.put( FORCE, "yes");
               // Index specific options
            } else if ( token.equalsIgnoreCase("-t") || token.equalsIgnoreCase("--type") ) {
               table.put( TYPE, at.nextSwitchToken());
            } else if ( token.equalsIgnoreCase("+trim") ) {
               if ( !table.containsKey( TYPE ) ) {
                   table.put( TYPE, "trimmed");
               }
            } else if ( token.equalsIgnoreCase("-trim") ) {
               if ( !table.containsKey( TYPE ) ) {
                   table.put( TYPE, "string");
               }
            } else if ( token.equalsIgnoreCase("--pagesize") ) {
                table.put( PAGE_SIZE, at.nextSwitchToken());
            } else if ( token.equalsIgnoreCase("--maxkeysize") ) {
                table.put( MAX_KEY_SIZE, at.nextSwitchToken());
            }
         } // End of while loop

        if ( !execute() ) {
            printHelp();
            return;
         }

      } catch (org.omg.CORBA.BAD_PARAM bp) {
         throw new org.omg.CORBA.BAD_PARAM(
            "ERROR : "+bp+" One or more parameters not found");

      } catch (org.omg.CORBA.COMM_FAILURE cf) {
         throw new org.omg.CORBA.COMM_FAILURE(
            "ERROR : "+cf+" Verify the dbXML server is running");

      } catch (org.omg.CORBA.UNKNOWN un) {
         throw new org.omg.CORBA.UNKNOWN(
            "ERROR : "+un+" Parameters were not entered correctly");

      } catch (org.omg.CORBA.MARSHAL m) {
         throw new org.omg.CORBA.MARSHAL(
            "ERROR : "+m+" One or more parameters not found");

      } catch (NoSuchElementException ne) {
         throw new NoSuchElementException(
            "ERROR : "+ne+" Switch found. Parameter missing.");

      } catch (NullPointerException np) {
            np.printStackTrace(System.out);
         throw new NullPointerException("ERROR : " + np);

      } catch (Exception e) {
            e.printStackTrace(System.out);
            throw new dbXMLException("ERROR : " + e);
      }
   }


    /**
     * This method is to carry out execution, after instance variables being setup by process( args )
     **/
    public boolean execute() throws ClassNotFoundException, InstantiationException, IllegalAccessException, Exception {
       init();
       String action = (String) table.get( ACTION );

       // get command class name
       String commandClass = null;
       if ( action != null ) {
           // search for the tool Class associated with the given action
           NodeList commands = getCommands();
           for ( int i = 0; i < commands.getLength(); i++ ) {
               Element e = (Element) commands.item( i );
               if ( action.equals( e.getAttribute( "switch" ) ) || action.equals( e.getAttribute( "name" ) ) ) {
                   commandClass = e.getAttribute( "class" );
               }
           }
       }

       if ( commandClass != null ) {
           {
               // register dbxml Database with xml:db
               Database dbxml = new DatabaseImpl();
               if ( table.containsKey( URI ) ) {
                   String dbURI = (String) table.get( URI );
                   dbxml.setProperty( "dbxml.naming.ior", dbURI + 
                     "/NamingService");
               }
               DatabaseManager.registerDatabase( dbxml );
           }

           {
               // execute command class
               Command command = (Command)Class.forName( commandClass ).newInstance();
               command.execute( table );
               return true;
           }
       }

       return false;
    }



   public boolean handleOption(String option, ArgTokenizer at) {
      return false;
   }

   /**
    * setAction sets the action type that will be passed to the command line.
    *
    * @param actionType The action value
    */
   public void setAction(String actionType) {
      table.put("action", actionType);
   }

   /**
    * getAction returns the action type that will be passed to the command line
    * tool.
    *
    * @return The action value
    */
   public String getAction() {
      return (String)table.get("action");
   }

   /**
    * setCollectionName sets the collection name that will be passed
    * to the command line.
    *
    * @param collectionName The collection value
    */
   public void setCollectionName(String collectionName) {
      table.put("collection", collectionName);
   }

   /**
    * getCollectionName returns the collection name that will be passed
    * to the command line tool.
    *
    * @return The collection value
    */
   public String getCollectionName() {
      return (String)table.get("collection");
   }

   /**
    * setDocumentName sets the document that will be passed to the
    * command line tool.
    *
    * @param documentName The docName value
    */
   public void setDocumentName(String documentName) {
      table.put("nameOf", documentName);
   }

   /**
    * getDocumentName returns the document that will be passed to the
    * command line tool.
    *
    * @return The docName value
    */
   public String getDocumentName() {
      return (String)table.get("nameOf");
   }

   /**
    * setQuery sets the Query variable for Document Query from the command line.
    *
    * @param query - The query string
    */
   public void setQuery(String query ) {
      table.put("query", query);
   }

   /**
    * getQuery returns the Query for Document passed to the command line tool.
    */
   public String getQuery() {
      return (String)table.get("query");
   }

   /**
    * setName sets the name for XMLObjects passed to the command line tool.
    *
    * @param name The docName value
    */
   public void setName(String name) {
      table.put("nameOf", name);
   }

   /**
    * getName returns the name for XMLObjects that will be passed to the
    * command line tool.
    *
    * @return The nameOf value
    */
   public String getName() {
      return (String)table.get("nameOf");
   }

   /**
    * setDatabaseServer sets the Database server name that will be
    * passed to the command line tool.
    *
    * @param appName The dbServ value
    */
   public void setDatabaseServer(String appName) {
      table.put("dbServ", appName);
   }

   /**
    * getDatabaseServer returns the Database server that will be
    * passed to the command line tool.
    *
    * @return The dbServ value
    */
   public String getDatabaseServer() {
      return (String)table.get("dbServ");
   }

   /**
    * setPort sets the port that will passed to the command line tool.
    *
    * @param portName The port value
    */
   public void setPort(String portName) {
      table.put("port", portName);
   }

   /**
    * getPort returns the port that will be passed to the command line tool.
    *
    * @return The port value
    */
   public String getPort() {
      return (String)table.get("port");
   }

   /**
    * setHost sets the host that will passed to the command line tool.
    *
    * @param hostName The host value
    */
   public void setHost(String hostName) {
      table.put("host", hostName);
   }

   /**
    * getPort returns the host that will be passed to the command line tool.
    *
    * @return The host value
    */
   public String getHost() {
      return (String)table.get("host");
   }

   /**
    * setFilePath sets the file path that will passed to the command line tool.
    *
    * @param fPath The filePath value
    */
   public void setFilePath(String fPath) {
      table.put("filePath", fPath);
   }

   /**
    * getFilePath returns the file path that will be passed to the command
    *
    * @return The filePath value
    */
   public String getFilePath() {
      return (String)table.get("filePath");
   }

   /**
    * setURI sets the database URI (protocol://host:port/name) that
    * will be passed to the command line
    *
    * @param URI The URI for the database
    */
   public void setURI(String URI) {
      table.put("uri", URI);
   }

   /**
    * getURI gets returns the database URI (protocol://host:port/name)
    * that will be passed to the command line tool
    *
    * @return The URI for the database
    */
   public String getURI() {
      return (String)table.get("uri");
   }

   /**
    * setImplementClass sets the implemented class path that will be passed
    * to the command line tool.
    *
    * @param imClassName The implClass value
    */
   public void setImplementClass(String imClassName) {
      table.put("implClass", imClassName);
   }

   /**
    * getImplementClass returns the implmented class path that will be passed
    * to the command line tool.
    *
    * @return The implClass value
    */
   public String getImplementClass() {
      return (String)table.get("implClass");
   }


   /**
    * The following Security methods are simply a starting point. User names and
    * their related passwords will not be this simple. Until Encryption for
    * Passwords are developed, and KeyStorage is set-up, this will do for now.
    * In the future, these methods will change as needed to be more efficient
    * for the dbXML-Core.
    */


   /**
    * setUser sets the user that will be passed to the command line tool and
    * will be used in Security issues.
    *
    * @param userName The user value
    */
   public void setUser(String userName) {
      table.put("user", userName);
   }

   /**
    * getUser returns the user that will be passed to the command line tool and
    * will be used in Security issues.
    *
    * @return The user value
    */
   public String getUser() {
      return (String)table.get("user");
   }

   /**
    * setPassword sets the password that will be passed to the command line tool
    * and will be used in conjunction with the userName value.
    *
    * @param pswd The passwrd value
    */
   public void setPassword(String pswd) {
      table.put("password", pswd);
   }

   /**
    * getPassword returns the password that will be passed to the command line
    * tool and will be used in conjunction with the userName value.
    *
    * @return The password value
    */
   public String getPassword() {
      return (String)table.get("password");
   }



    public void printHelp() {
       NodeList list = getCommands();

        // This method relies on two things to format the output for help
        //    Method isAdmin() - Tells us if this is an admin instance, used to hide certain output
        //    XML file Commands.xml attribute "helpclass" - used to order output

        String helpClass;  // Holds the helpclass for the current <command> node
        String desc;       // Holds the description for the current <command> node
        String cmdswitch;  // Holds the switch for the current <command> node



        // Show the header and switch commands
      System.out.println();
      System.out.println("dbXMLAdmin Command Tools v" + dbXML.Version);
      System.out.println();
      System.out.println("Format: dbxml action [switch] [parameter]");
      System.out.println();
      System.out.println("Where:  [switch]  implements:");
      System.out.println("    -c           " + "Collection context (must always be specified)");
      System.out.println("    -e           " + "File extension for multiple documents");
      System.out.println("    -f           " + "File path for document retrieval and storage");
      System.out.println("    -i           " + "Implementing Class for XMLObjects");
      System.out.println("    -n           " + "Name");
      System.out.println("    -o           " + "URI String for invocation of XMLObject");
      System.out.println("    -p           " + "Index pattern");
      System.out.println("    -q           " + "Query string");
      System.out.println("    -u           " + "Database URI");
      System.out.println("    -y           " + "Force Deletion process");
      System.out.println("    -t           " + "Specify the data type in collection index");
      System.out.println("    --pagesize   " + "Page size for Index Pages (default: 1024) ");
      System.out.println("    --maxkeysize " + "The max key size for values (default: 0=none )");
      System.out.println();

      System.out.println("\nActions:\n");
      System.out.println("    dbxml [parameter], etc...\n");

      // Show all elements with helpclass=document

      // Loop over the commands, printing test from description attribute
      for (int i=0; i < list.getLength(); i++) {
         helpClass = ((Element)list.item(i)).getAttribute("helpclass") ;

         if ( helpClass.equals("document") ) {
            desc = ((Element)list.item(i)).getAttribute("description");
            cmdswitch = ((Element)list.item(i)).getAttribute("switch");
            System.out.println("    " + StringUtilities.leftJustify(cmdswitch, 13) + desc );
         }
      }

      // Loop over the commands, printing text from description attribute
      for (int i=0; i < list.getLength(); i++) {
         helpClass = ((Element)list.item(i)).getAttribute("helpclass") ;

         if ( helpClass.equals("security") ) {
            desc = ((Element)list.item(i)).getAttribute("description");
            cmdswitch = ((Element)list.item(i)).getAttribute("switch");
            System.out.println("    " + StringUtilities.leftJustify(cmdswitch, 13) + desc );
         }
      }

      System.out.println("\nExamples:\n");

      System.out.println("    dbxml ad -c /db/test -f /tmp/xmldocument -n myxmldocument");
      System.out.println("    dbxml dd -c /db/test -n myxmldocument");
      System.out.println("    dbxml rd -c /db/test/ocs -f a:\\file.xml -n file.xml");
      System.out.println("    dbxml xpath -c /db/test/ocs -q test");
      System.out.println();
      System.out.println("For more information, please read the dbXML - Tools Reference Guide");
      System.out.println();
   }
}
