///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoAdmin.cc
// -------------
// Cego admin console program
//
// Design and Implementation by Bjoern Lemke               
//                                                         
// (C)opyright 2000-2010 Bjoern Lemke                        
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; see the file COPYING.  If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
//
// IMPLEMENTATION MODULE
//
// Class: Main
// 
// Description: 
//
// Status: QG-2.6
//
///////////////////////////////////////////////////////////////////////////////

#include <lfc/Chain.h>
#include <lfc/Exception.h>
#include <lfc/GetLongOpt.h>
#include <lfc/File.h>
#include <lfc/Timer.h>
#include <lfc/Tokenizer.h>
#include <lfc/Net.h>

#include <lfc/Element.h>
#include <lfc/Document.h>
#include <lfc/XMLSuite.h>

#include "CegoDefs.h"
#include "CegoAdmAction.h"
#include "CegoAdmMon.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <readline/readline.h>
#include <readline/history.h>


#define USAGE "Usage: cgadm --user=<user>/<password>\n\
          [ --server=<host>]\n			      \
          [ --port=<port> ]\n			      \
          [ --batchfile=<batchfile> ]\n		      \
          [ --cmd=<command> ]\n			      \
          [ --logfile=<logfile> ]\n		      \
          [ --raw ]\n				      \
          [ --verbose ]\n			      \
          [ --mon ]\n				      \
          [ --ignore ]\n			      \
          [ --debug ] [ --version  ] [ --help ]"


#define DEFAULTSERVER "localhost"
#define DEFAULTPORT 2000
#define DEFPITFORMAT "%Y-%m-%d %H:%M:%S"

#define HISTFILE ".cgadm_history"
#define PROMPT "CGADM > "
#define PROMPT2 "> "

enum RunMode { INTERACTIVE, BATCH, COMMAND, MONITOR };

bool dispatchCmd(CegoAdmAction* pAdm, const Chain& cmd);
void showMonitor(CegoAdminHandler *pAH);

void printHelp(const Chain& cs);

void helpOverview();
void helpTopic(const Chain& topic);

extern char __lfcVersionString[];
extern char __lfcxmlVersionString[];

int main(int argc, char **argv)
{	    
    GetLongOpt longOpt(argc, argv);
    
    longOpt.addOpt("version");
    longOpt.addOpt("help");
    longOpt.addOpt("logfile");
    longOpt.addOpt("user");
    longOpt.addOpt("cmd");
    longOpt.addOpt("batchfile");
    longOpt.addOpt("debug");
    longOpt.addOpt("raw");
    longOpt.addOpt("verbose");
    longOpt.addOpt("mon");
    longOpt.addOpt("ignore");
    longOpt.addOpt("server", DEFAULTSERVER);
    longOpt.addOpt("port", Chain(DEFAULTPORT));
    longOpt.addOpt("simulate");

    try
    {
	longOpt.parseOpt(); 
    }
    catch ( Exception e )
    {
	Chain msg;
	e.pop(msg);
	cerr << msg << endl;
	cerr << USAGE << endl;
	exit(1);	
    }
    
    Chain user;
    Chain password;
    

#ifdef HAVE_MINGW32
    Chain homeDir(getenv("HOMEPATH"));
    Chain histPath = homeDir + "\\" + Chain(HISTFILE);
#else
    Chain homeDir(getenv("HOME"));
    Chain histPath = homeDir + "/" + Chain(HISTFILE);
#endif
    
    RunMode runMode = INTERACTIVE;

    bool debug=false;
    if ( longOpt.isSet("debug") )
	debug=true;

    bool rawMode = false;
    if ( longOpt.isSet("raw") )
	rawMode=true;

    CegoAdmAction::ResultMode resultMode = CegoAdmAction::NORMAL;
    if ( longOpt.isSet("verbose") )
	resultMode=CegoAdmAction::VERBOSE;
    
    bool ignoreError = false;
    if ( longOpt.isSet("ignore") )
	ignoreError=true;
    
    if ( longOpt.isSet( Chain("help") ) )
    {	
	cerr << USAGE << endl;
	exit(0);
    }

    if ( longOpt.isSet( Chain("version") ) )
    {
	cout << CEGO_PRODUCT << " (" << sizeof(long) * 8 << " bit), Version " << CEGO_VERSION 
	     << " [ lfc : " << __lfcVersionString  
	     << ", lfcxml : " <<  __lfcxmlVersionString << " ]" << endl;
	cout << CEGO_COPYRIGHT << endl;
	exit(0);
    }

    Chain logFile = longOpt.getOptValue("logfile");
    Chain serverName = longOpt.getOptValue("server");
    int portNo = longOpt.getOptValue("port").asInteger();

    Chain batchFileName;
    Chain command;

    if ( longOpt.isSet("batchfile") )
    {
	runMode = BATCH;
	batchFileName = longOpt.getOptValue("batchfile");
    }
    else if ( longOpt.isSet("cmd") )
    {
	runMode = COMMAND;
	command = longOpt.getOptValue("cmd");
    }

    else if ( longOpt.isSet("mon") )
    {
	runMode = MONITOR;
    }

    CegoModule *pModule = 0;
    CegoAdminHandler* pAH = 0;
    NetHandler* pN = 0;
    unsigned long modId = 0;

    try
    {
	Chain authString = longOpt.getOptValue("user");
	
	Tokenizer authTok(authString, Chain("/")); 
	authTok.nextToken(user);
	authTok.nextToken(password);
	
	if ( user.length() == 0 )
	    throw Exception(EXLOC, "User not set");
	if ( password.length() == 0 )
	    throw Exception(EXLOC, "Password not set");
	       
	if ( logFile.length() > 0 )
	    pModule = new CegoModule(logFile);
	else
	    pModule = new CegoModule();
		
	modId = pModule->getModId("CegoAdmin");
	
	if ( debug )
	    pModule->logModule(modId, "CegoAdmin", Logger::DEBUG);
	else
	    pModule->logModule(modId, "CegoAdmin", Logger::NOTICE);
		
	Net n (  NETMNG_MSG_BUFLEN, NETMNG_SIZEBUFLEN );
	
	pN = n.connect(serverName, portNo);
	pAH = new CegoAdminHandler( pModule, pN);
	
	CegoAdminHandler::ResultType res = pAH->requestSession(user, password);
	if ( res != CegoAdminHandler::ADM_OK )
	{
	    Chain msg;
	    pAH->getMsg(msg);
	    throw Exception(EXLOC, msg);
	}
    }
    catch ( Exception e)
    {
	Chain msg;
	e.pop(msg);
	cerr << msg << endl;
	exit(1);
    }

    pModule->log(modId, Logger::LOGERR, Chain("Got session... "));

    CegoAdmAction* pAdm = new CegoAdmAction(pAH, pModule, resultMode, rawMode);

    Chain pitFormat(DEFPITFORMAT);    
    char *pPF = getenv("CGPITFORMAT");
    if ( pPF )
    {
	pitFormat = Chain(pPF);
    }
    pAdm->setPitFormat(pitFormat);

    int exitCode = 0;

    try
    {

	switch ( runMode )
	{
	case MONITOR:
	{	    
	    CegoAdmMon mon(pAH);
	    mon.showMonitor();
	    break;	    	    
	}
	case BATCH:
	{
	    
	    int lineNo=0;
	    
	    
	    File batchFile(batchFileName);
	    
	    batchFile.open(File::READ);	    
	    
	    Chain cmd;
	    Chain line;
	    bool disableDelimiter=false;
	    bool doQuit = false;
	    
	    while (doQuit == false && batchFile.readLine(line))
	    {
		lineNo++;
		line = line.cutTrailing(" \t");
		
		bool isCommentLine = false;
		
		if ( line.length() >= 2 )
		{		    
		    if (line.cutTrailing(" \t").subChain(1, 2) == Chain("--"))
		    {
			isCommentLine = true;
		    }
		}
		if ( ! isCommentLine )
		{
		    
		    cmd = cmd + Chain(" ") + line;
		    cmd = cmd.cutTrailing(" \t");
		    
		    if ( cmd.length() > 0 )
		    {
			
			if (cmd.subChain(cmd.length()-1, cmd.length()) == Chain(";")) 
			{			
			    try
			    {
				doQuit = dispatchCmd(pAdm, cmd);
			    }
			    catch ( Exception e )
			    {
				cerr << "Line Number " + Chain(lineNo) + " : " << endl;
				Chain msg;
				e.pop(msg);
				cerr << msg << endl;
				exitCode = 1;
				
				pAdm->cleanUp();
				
				if ( ignoreError == true )
				    cerr << "Ignored" << endl;
				else
				    throw Exception(EXLOC, msg);
				
			    }
			    cmd = Chain("");			    
			}
		    }
		}
	    }
	    if ( cmd.length() > 1 )
	    {
		cout << "Incomplete command <" << cmd << ">"  << endl;
	    }
	    
	    batchFile.close();
	    
	    break;
	}
	case COMMAND:
	{		    
	    
	    Chain cmd = command.cutTrailing(" ;") + Chain(";");
	    dispatchCmd(pAdm, cmd);	    
	    break;
	}
	case INTERACTIVE:
	{
	    	    	
	    read_history((char*)histPath);
	    
	    bool doQuit = false;
	    
	    while ( doQuit == false )
	    {			    		
		
		char *pC = 0;
		
		bool isTerminated = false;
		Chain cs;
		
		pC = readline(PROMPT);
		
		if (pC)
		{
		    cs = Chain(pC);
		    
		    while (! isTerminated )
		    {		
			add_history(pC);	
			
			if (pC)
			    free(pC);	    
			
			cs = cs.cutTrailing(Chain(" \t"));
			
			if ( cs.length() > 1)
			{		
			    
			    if ( cs[cs.length()-2] == ';')
			    {
				
				try
				{
				    doQuit = dispatchCmd(pAdm, cs);
				}
				catch ( Exception e )
				{
				    Chain msg;
				    e.pop(msg);
				    cerr << "ERROR : " << msg << endl;
				}
				
				pAdm->cleanUp();
				
				write_history((char*)histPath);
				
				isTerminated = true;
			    }			    
			}
			
			if ( ! isTerminated )
			{
			    pC = readline(PROMPT2);
			    
			    if (pC)
			    {
				cs = cs + Chain(" ") + Chain(pC);
			    }
			}
		    }		  
		}
		else
		{
		    cout << "Bye" << endl;
		    doQuit=true;
		}
	    }    
	    break;
	}
	}
    }    
    catch ( Exception e)
    {
	Chain msg;
	e.pop(msg);
	cerr << "ERROR : " << msg << endl;
	exit(1);
    }
    
    pAH->closeSession();
    
    delete pAdm;
    delete pAH;
    delete pN;
    delete pModule;

    exit(exitCode);
}

bool dispatchCmd(CegoAdmAction *pAdm, const Chain& cmd)
{

    // check if help is requested
    Tokenizer tok(cmd, " ;");
    Chain hcheck;
    tok.nextToken(hcheck);
    if ( hcheck == Chain("help") )
    {
	Chain topic;
	tok.nextToken(topic);
	printHelp(topic);
	return false;
    }
   
    if ( cmd.cutTrailing(" ;") == Chain("quit") )
	return true;

    pAdm->setCommandChain( (char*)cmd);
    
    Timer t(6,3);
    t.start();
    		    		    
    pAdm->parse();
    
    t.stop();
    if ( pAdm->getRawMode() == false )
	cout << "ok ( " << t << " s )" << endl;

    return false;
}

void printHelp(const Chain &topic)
{
    if ( topic == Chain("all"))
    {
	helpOverview();
    }
    else 
    {
	helpTopic(topic);
    }
}

void helpOverview()
{
    cout << endl;
    cout << "+======================+" << endl;
    cout << "| cgadm admin commands |" << endl;
    cout << "+======================+" << endl;
    cout << endl;
    cout << "   Format commands" << endl;
    cout << "   ---------------" << endl;
    cout << "   [f1] rawmode < on | off >" << endl;
    cout << endl;
    cout << "   Database administration" << endl;
    cout << "   --------------------" << endl;
    cout << endl;
    cout << "   [d1] show pool" << endl;
    cout << "   [d2] list pool" << endl;
    cout << "   [d3] lockstat" << endl;
    cout << "   [d4] list < rec | rbrec | sysrec | tp | sp | dp | ix | rb| df | bp | ts > lock" << endl;
    cout << "   [d5] list node" << endl;
    cout << "   [d6] list session" << endl;
    cout << "   [d7] list copy" << endl;
    cout << "   [d8] threadinfo [ db [threadid] | adm | log ]" << endl;
    cout << "   [d9] abort db thread <tid>" << endl;
    
    cout << endl;
    cout << "   Tableset administration" << endl;
    cout << "   -----------------------" << endl;
    cout << endl;
    cout << "   [t0] list tableset" << endl;
    cout << "   [t1] retrieve tableset from '<hostname>'" << endl;
    cout << "   [t2] define tableset <tableset> <attr1>=<value1> <attr2=value2> ..." << endl;	
    cout << "   [t3] create tableset" << endl;
    cout << "   [t4] show tableset <tableset>" << endl;
    cout << "   [t5] start tableset <tableset> [ cleanup ] [ forceload ]" << endl;
    cout << "   [t6] stop tableset <tableset>" << endl;
    cout << "   [t7] copy tableset <tableset>" << endl;
    cout << "   [t8] switch tableset <tableset>" << endl;
    cout << "   [t9] switch secondary for <tableset>" << endl;
    cout << "   [t10] switch mediator for <tableset>" << endl;
    cout << "   [t11] relocate secondary for <tableset> to '<hostname>'" << endl;
    cout << "   [t12] relocate mediator for <tableset> to '<hostname>'" << endl;
    cout << "   [t13] drop tableset <tableset>" << endl;
    cout << "   [t14] remove tableset <tableset>" << endl;
    cout << "   [t15] add <app|sys|temp> datafile '<filename>' size <numpages> to <tableset>" << endl;
    cout << "   [t16] check tableset <tableset>" << endl;
    cout << "   [t17] verify tableset <tableset>" << endl;
    cout << "   [t18] correct tableset <tableset>" << endl;
    cout << "   [t19] set checkpoint <intval> for <tableset>" << endl;
    cout << "   [t20] set initfile '<initfile>' for <tableset>" << endl;
    cout << "   [t21] set syssize <intval> for <tableset>" << endl;
    cout << "   [t22] set tmpsize <intval> for <tableset>" << endl;
    cout << "   [t23] set tsroot '<root path>' for <tableset>" << endl;
    cout << "   [t24] set tsticket '<ticket path>' for <tableset>" << endl;
    cout << "   [t25] set lognum <intval> for <tableset>" << endl;
    cout << "   [t26] set logsize <intval> for <tableset>" << endl;
    cout << "   [t27] set sortareasize <intval> for <tableset>" << endl;
    cout << "   [t28] sync tableset <tableset> [ with '<command>' [ <timeout> ] ] [ message 'system message' ]" << endl;
    cout << "   [t39] list datafile for <tableset>" << endl;
    cout << "   [t30] list logfile for <tableset>" << endl;
    cout << "   [t31] list transaction for <tableset>" << endl;
    cout << "   [t32] list object for <tableset>" << endl;
    cout << "   [t33] reset tableset <tableset>" << endl;

    cout << endl;
    cout << "   User and role administration" << endl;
    cout << "   ----------------------------" << endl;
    cout << endl;
    cout << "   [u0] list user" << endl;
    cout << "   [u1] add user <userid> identified by '<passwd>'" << endl;
    cout << "   [u2] passwd user <userid> identified by '<passwd>'" << endl;
    cout << "   [u3] trace [ on | off ] user <userid>" << endl;
    cout << "   [u4] drop user <userid>" << endl;
    cout << "   [u5] list role" << endl;
    cout << "   [u6] create role <role>" << endl;
    cout << "   [u7] show role <role>" << endl;
    cout << "   [u8] set permission <perm> with <permlist> to role <role>" << endl;
    cout << "   [u9] assign role <role> to <userid>" << endl;
    cout << "   [u10] remove role <role> from user <userid>" << endl;
    cout << "   [u11] drop role <role>" << endl;

    cout << endl;
    cout << "   Backup and Recovery" << endl;
    cout << "   -------------------" << endl;
    cout << "   [b0] set logmng '<progname>' [ timeout <intval> ]" << endl;
    cout << "   [b1] list archlog for <tableset>" << endl;
    cout << "   [b2] enable archlog for <tableset>" << endl;
    cout << "   [b3] disable archlog for <tableset>" << endl;
    cout << "   [b4] add archlog <archid> path '<archpath>' to <tableset>" << endl;
    cout << "   [b5] remove archlog <archid> from <tableset>" << endl;
    cout << "   [b6] begin backup for <tableset> [ message 'system message' ]" << endl;
    cout << "   [b7] end backup for <tableset> [ message 'system message' ] [ keep ticket ]" << endl;
    cout << "   [b8] recover tableset <tableset> [ to <point in time> ]" << endl;
    cout << "   [b9] export [ xml | binary | plain ]  table <table> from <tableset> to '<filename>'" << endl;
    cout << "   [b10] export [ xml | binary | plain ] tableset [ structure ] <tableset> to '<filename>'" << endl;
    cout << "   [b11] import [ xml | binary | plain ] table <table> to <tableset> from '<filename>' [ nologging ]" << endl;
    cout << "   [b12] import [ xml | binary | plain ] tableset [ structure ] <tableset> from '<filename>' [ nologging ]" << endl;
    cout << "   [b13] list bustat for <tableset>" << endl;
    cout << "   [b14] reset bustat for <tableset>" << endl;
    cout << "   [b15] show logmng" << endl;
    cout << endl;
    cout << "   You can get a detailed help for each command by typing \"help <topic>\"," << endl;
    cout << "   where topic is the identifier in in the square brackets ( e.g. help t1; )" << endl;
    cout << endl;

}

void helpTopic(const Chain& topic)
{
    if ( topic == Chain("f1"))
    {	
	cout << endl;
	cout << "rawmode < on | off >" << endl;
	cout << "-------------------" << endl;
	cout << "   With enabled rawmode, no format characters are printed" << endl;
	cout << "   This might be usedful, if the command output should be parsed by another program" << endl;
	cout << endl;
    }
    else if ( topic == Chain("d1"))
    {
	cout << endl;
	cout << "show pool" << endl;
	cout << "---------" << endl;
	cout << endl;
	cout << "   The poolinfo lists the current status of the database buffer cache parameters." << endl;
	cout << "   This information may be helpful for performance optimization ( e.g. increase the buffer cache size)" << endl;
	cout << endl;
	cout << "   The following parameters are indicated : " << endl;
	cout << endl;
	cout << "   Page Size         - The size of each page in the buffercache." << endl;
	cout << "                       This parameter is specified at database creation time and can not be changed." << endl;
	cout << "                       All subsequent information is given in units of pages based on the given pagesize." << endl;
	cout << "   Total Pages       - The number of pages available in the bufferpool." << endl;
	cout << "                       There are no special regions in the buffercache for ordering, rollback segments, indices and so on." << endl;
	cout << "                       Page requests for any reasons are assigned using a modulo hash algorithm" << endl;
	cout << "                       by treating the corresponding fileId and pageId of the managed database file" << endl;
	cout << "   Used Pages        - The number of pages which are in use. Actual database information is cached in this pages." << endl;
	cout << "   Free Pages        - Pages which are still available and have not been filled with any valid data" << endl;
	cout << "   Dirty Pages       - Pages filled with valid and modified data." << endl;
	cout << "   Fixed Pages       - Pages, which are currently in use by any transaction." << endl;
	cout << "   Persistent Pages  - Pages, which can not be removed from the buffer pool."<< endl;
	cout << "                       Normally, thes pages contain database dictionary information" << endl;
	cout << "   No Sync Pages     - Forperformance reasones, sometimes pages are used which are not in sync with the transaction log." << endl;
	cout << "                       These  pages can be written to disk as required." << endl;
	cout << "                       E.g. for creation of indexes, no sync pages are used." << endl;
	cout << "   Stat Start        - Start point of statistics measurement. The following indicated values are collected since this time" << endl;
	cout << "   Disk Reads        - Performed disk database block read opertions since start of statistics measurement." << endl;
	cout << "   Disk Writes       - Performed disk database block write opertions since start of statistics measurement." << endl;
	cout << "   Read Delay        - Average delay of a disk database block read operation, measured since start of statistics." << endl;
	cout << "   Write Delay       - Average delay of a disk database block write operation, measured since start of statistics." << endl;
	cout << endl;     
    }
    else if ( topic == Chain("d2"))
    {
	cout << endl;
	cout << "list pool" << endl;
	cout << "---------" << endl;
	cout << endl;
	cout << "   Prints a detailed listing of each buffer pool page" << endl;
	cout << "   Attributes are : position, status, isdirty, number of fixes, tabsetid, fileid, pageid, fixstat" << endl;
	cout << "   Depending on the size of the buffercache, the output can be pretty long." << endl;
	cout << "   This command is rather useful for debugging reasons." << endl;
	cout << endl;
    }
    else if ( topic == Chain("d3"))
    {
	cout << endl;
	cout << "lockstat" << endl;
	cout << "---------" << endl;
	cout << endl;
	cout << "   The lockstat command shows a listing of all semaphores" << endl;
	cout << "   The following attributes are indicated :" <<endl;
	cout << endl;
	cout << "   LOCKID - The semaphore type. There are several semaphore arrays allocated for different purposes." << endl;
	cout << "            ADMQUEUE - Admin thread pool request queue" << endl;
	cout << "            DBQUEUE - DB thread pool request queue" << endl;
	cout << "            LOGQUEUE - Log thread pool request queue" << endl;
	cout << "            DBM - Database manager object usage management" << endl;
	cout << "            XML - XML database control file access" << endl;
	cout << "            RECLOCK - Data page record locks" << endl;
	cout << "            RBRECLOCK - Rollback page record locks" << endl;
	cout << "            SYSRECLOCK - System page record locks" << endl;
	cout << "            SYSPAGELOCK - System page locks" << endl;
	cout << "            DATAPAGELOCK - Data page locks" << endl;
	cout << "            IDXPAGELOCK - Index page locks" << endl;
	cout << "            RBPAGELOCK - Rollback page locks" << endl;
	cout << "            DATAFILELOCK - Datafile locks" << endl;
	cout << "            POOLLOCK - Pool locks" << endl;
	cout << endl;
	cout << "   NUMLOCK - The number of configured locks." << endl;
	cout << "             To achieve an appropriate lock distribution, a prime number should be configured." << endl;
	cout << endl;
	cout << "   LOCKCOUNT - The number of current threads waiting to achieve the lock." << endl;
	cout << endl;
	cout << "   RD HITS - Number of performed read lock operations." << endl;
	cout << endl;
	cout << "   RD DELAY - Lock delay for all performed read lock operations." << endl;
	cout << endl;
	cout << "   WR HITS - Number of performed write lock operations." << endl;
	cout << endl;
	cout << "   WR DELAY - Lock delay for all performed write lock operations." << endl;
	cout << endl;
    }
    else if ( topic == Chain("d4"))
    {
	cout << endl;
	cout << "list < rec | rbrec | sysrec | tp | sp | dp | ix | rb| df | bp | ts > lock" << endl;
	cout << "-------------------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   List statistics for specific lock types" << endl;
	cout << "   Lock type are" << endl;
	cout << "   rec    - data table record locks" << endl;
	cout << "   rbrec  - rollback table record locks" << endl;
	cout << "   sysrec - system table record locks" << endl;
	cout << "   tp     - thread pool locks" << endl;
	cout << "   sp     - system page locks" << endl;
	cout << "   dp     - data page locks" << endl;
	cout << "   ix     - index page locks" << endl;
	cout << "   rb     - rollback page locks" << endl;
	cout << "   df     - data file locks" << endl;
	cout << "   bp     - buffer pool locks" << endl;
	cout << "   ts     - table set locks" << endl;
	cout << endl;
    }
    else if ( topic == Chain("d5"))
    {
	cout << endl;
	cout << "list node" << endl;
	cout << "---------" << endl;
	cout << endl;
	cout << "   Lists all known nodes in the database configuration" << endl;
	cout << endl;

    }
    else if ( topic == Chain("d6"))
    {
	cout << endl;
	cout << "list session" << endl;
	cout << "---------" << endl;
	cout << endl;
	cout << "   Lists all established database session, build up to handle distributed queries" << endl;
	cout << endl;
    }
    else if ( topic == Chain("d7"))
    {
	cout << endl;
	cout << "list copy" << endl;
	cout << "---------" << endl;
	cout << endl;
	cout << "   Lists all active tableset copy jobs" << endl;
	cout << endl;
    }
    else if ( topic == Chain("d8"))
    {

	cout << endl;
	cout << "threadinfo [ db | adm | log]" << endl;
	cout << "----------------------------" << endl;
	cout << endl;
	cout << "   Without optinal argument, the threadinfo command lists all configured and current active threads in the database system." << endl;
	cout << "   The information is given for all three thread pools ( db, adm and log )." << endl;
	cout << endl;
	cout << "   More detailed information for each thread pool is given, if a pool id is specified with the command." << endl;
	cout << "   Valid pools id's are db, adm or log." << endl;
	cout << endl;
    }
    else if ( topic == Chain("d9"))
    {
	cout << endl;
	cout << "abort db thread <tid>" << endl;
	cout << "---------------------" << endl;
	cout << endl;
	cout << "   Aborting the actual running query of an active db thread" << endl;
	cout << endl;
    }
    else if ( topic == Chain("u0"))
    {
	cout << endl;
	cout << "list user" << endl;
	cout << "---------" << endl;
	cout << endl;
	cout << "   List all defined users in the database" << endl;
	cout << endl;
    }
    else if ( topic == Chain("u1"))
    {
	cout << endl;
	cout << "add user <userid> identified by '<passwd>'" << endl;
	cout << "------------------------------------------" << endl;
	cout << endl;
	cout << "   Adds a user with the specified password to the database" << endl;
	cout << endl;
    }
    else if ( topic == Chain("u2"))
    {	
	cout << endl;
	cout << "passwd user <userid> identified by '<passwd>'" << endl;    
	cout << "---------------------------------------------" << endl;
	cout << endl;
	cout << "   Set up the user passwd to the given value" << endl;
	cout << endl;
    }
    else if ( topic == Chain("u3"))
    {
	cout << endl;
	cout << "trace ( on | off ) user <userid>" << endl;    
	cout << "--------------------------------" << endl;
	cout << endl;
	cout << "   Enables or disables trace mode for a user" << endl;
	cout << endl;
    }
    else if ( topic == Chain("u4"))
    {
	cout << endl;
	cout << "remove user <userid>" << endl;    
	cout << "--------------------" << endl;
	cout << endl;
	cout << "   Removes the user from the database" << endl;
	cout << endl;
    }

    else if ( topic == Chain("u5"))
    {	
	cout << endl;
	cout << "list role" << endl;
	cout << "---------" << endl;
	cout << endl;
	cout << "   List all defined roles" << endl;
	cout << endl;
    }
    else if ( topic == Chain("u6"))
    {
	cout << endl;
	cout << "create role <role>" << endl;
	cout << "------------------" << endl;
	cout << endl;
	cout << "   Create the specified role" << endl;
	cout << endl;
    }

    else if ( topic == Chain("u7"))
    {
	cout << endl;
	cout << "show role <role>" << endl;
	cout << "----------------" << endl;
	cout << endl;
	cout << "   Show the definition of the specified role" << endl;
	cout << endl;
    }
    else if ( topic == Chain("u8"))
    {
	cout << endl;
	cout << "set permission <permid> with <permlist> to role <role>" << endl;
	cout << "----------------------------------------------------" << endl;
	cout << endl;
	cout << "   Sets a permission to the specified role" << endl;
	cout << "   The permission id (permid) is any valid identifier" << endl;
	cout << "   If the permid already exits for the specified role, an update is performed" << endl;
	cout << "   Otherwise, a new permission entry is created" << endl;
	cout << "   Permlist is a specification of the permission" << endl;
	cout << "   It consists of a triple describing tableset, filter and right" << endl;
	cout << "   The triple must be specified in a comma separated list" << endl;
	cout << endl;
	cout << "        Sample : set permission p1 with tableset=TS1,filter='*T',right=READ to role R1" << endl;
	cout << endl;
	cout << "    Valid right values are READ,WRITE,MODIFY,EXEC or ALL" << endl;
	cout << endl;
    }
    else if ( topic == Chain("u9"))
    {	
	cout << endl;
	cout << "assign role <role> to <userid>" << endl;
	cout << "------------------------------" << endl;
	cout << endl;
	cout << "   Assigns the given role to the user" << endl;
	cout << endl;
	
    }
    else if ( topic == Chain("u10"))
    {
	cout << endl;
	cout << "remove role <role> from <userid>" << endl;
	cout << "--------------------------------" << endl;
	cout << endl;
	cout << "   Removes the specified user role from user" << endl;
	cout << endl;
    }
    else if ( topic == Chain("u11"))
    {
	cout << endl;
	cout << "drop role <role>" << endl;
	cout << "----------------" << endl;
	cout << endl;
	cout << "   Drops the specified role" << endl;
	cout << endl;

    }
    else if ( topic == Chain("t0"))
    {
	cout << endl;
	cout << "list tableset" << endl;
	cout << "-------------" << endl;
	cout << endl;
	cout << "   List all known tablesets on the node." << endl;
	cout << "   The current status and assigned hosts ( mediator, primary, secondary) are also indicated." << endl;
	cout << endl;	
    }
    else if ( topic == Chain("t1"))
    {
	cout << endl;
	cout << "retrieve tableset from '<hostname>'" << endl;
	cout << "-----------------------------------" << endl;
	cout << endl;	
    }
    else if ( topic == Chain("t2"))
    {
	cout << endl;	
	cout << "define tableset <tableset> <attr1=val1> <attr2=val2> ..." << endl;
	cout << "--------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Define a new tableset. The following attributes must be specified:"<< endl;
	cout << endl;
	cout << "   tsroot          - Root directory of the database system and control files." << endl;
	cout << "   tsticket        - Name of the online backup tableset ticket." << endl;
	cout << "   syssize         - Size of the system space in number of pages." << endl;
	cout << "   tmpsize         - Size of the tempory space in number of pages." << endl;
	cout << "   logname         - Prefix of the configured redolog files." << endl;
	cout << "   logsize         - Size of a redolog file in bytes." << endl;
	cout << "   lognum          - Number of configured redolog files." << endl;
	cout << "   primary         - Name of the primary host." << endl;
	cout << "   secondary       - Name of the secondary host." << endl;
	cout << endl;
	cout << "   For a defintion statement the attributes syssize, tmpsize logsize and logname attributes are specified as integer values." << endl;
	cout << "   The attributes logfilename, meiator, primary and secondary  are specified as string values." << endl;
	cout << endl;
	cout << "   Sample:" << endl;
	cout << endl;
	cout << "      define tableset ts1 tsroot='/cego/ts1' syssize=100 tmpsize=100 logname='/cego/ts1/redolog'" << endl; 
	cout << "             logsize=100000 lognum=3 primary='geek' secondary='sam';" << endl;
	cout << endl;
    }
    else if ( topic == Chain("t3"))
    {
	cout << endl;
	cout << "create tableset <tableset>" << endl;
	cout << "--------------------------" << endl;
	cout << endl;
	cout << "   Creates the specified tableset as defined in the tableset description." << endl;
	cout << endl;
    }
    else if ( topic == Chain("t4"))
    {
	cout << endl;
	cout << "info tableset <tableset>" << endl;
	cout << "--------------------------" << endl;
	cout << endl;
	cout << "   Prints a detailed listing of the current tableset configuration values" << endl;
	cout << endl;
	cout << "   RunState        - Running state of the tableset ( ONLINE or OFFLINE )." << endl;
	cout << "   SyncState       - Syncing state of the tableset ( relevant for distribution mode )" << endl;
	cout << "   Primary         - Tableset primary host." << endl;
	cout << "   Secondary       - Tableset secondary host." << endl;
	cout << "   Mediator        - Tableset mediator host." << endl;
	cout << "   RootPath        - Tableset root path, all data files are located in this path." << endl;
	cout << "   Ticket          - Backup ticket file name." << endl;
	cout << "   InitFile        - Location of the tableset initfile." << endl;
	cout << "   Checkpoint      - Checkpoint interval in seconds ( forced checkpoint )." << endl;
	cout << "   SystemPageTotal - Total number of available system pages." << endl;
	cout << "   SystemPageUsed  - Number of current used system pages." << endl;
	cout << "   TempPageTotal   - Total number of available temp pages." << endl;
	cout << "   TempPageUsed    - Number of current used temp pages." << endl;
	cout << "   AppPageTotal    - Total number of available data pages." << endl;
	cout << "   AppPageUsed     - Number of current used data pages." << endl;
	cout << "   SortAreaSize    - Number of bytes, which can be allocated in the sort buffer." << endl;
	cout << "   Tid             - Current transaction id." << endl;
	cout << "   CLSN            - Committed log sequence number." << endl;
	cout << "   NLSN            - Next used log sequence number." << endl;
	cout << "   ArchMode        - Archmode enabled ( ON or OFF )." << endl;
	cout << endl;
    }
    else if ( topic == Chain("t5"))
    {
	cout << endl;
	cout << "start tableset <tableset>" << endl;
	cout << "-------------------------" << endl;
	cout << endl;
	cout << "   Starts the specified tableset on the configured primary node." << endl;
	cout << endl;
    }
    else if ( topic == Chain("t6"))
    {
	cout << endl;
	cout << "stop tableset <tableset>" << endl;
	cout << "------------------------" << endl;
	cout << endl;
	cout << "   Stops the specified tableset on the primary node." << endl;
	cout << endl;
    }
    else if ( topic == Chain("t7"))
    {
	cout << endl;
	cout << "copy tableset <tableset>" << endl;
	cout << "------------------------" << endl;
	cout << endl;
    }
    else if ( topic == Chain("t8"))
    {
	cout << endl;
	cout << "switch tableset <tableset>" << endl;
	cout << "--------------------------" << endl;
	cout << endl;
    }
    else if ( topic == Chain("t9"))
    {
	cout << endl;
	cout << "switch secondary for <tableset>" << endl;
	cout << "-------------------------------" << endl;
	cout << endl;
    }
    else if ( topic == Chain("t10"))
    {
	cout << endl;
	cout << "switch mediator for <tableset>" << endl;
	cout << "------------------------------" << endl;
	cout << endl;
    }
    else if ( topic == Chain("t11"))
    {
	cout << endl;
	cout << "relocate secondary for <tableset> to '<hostname>'" << endl;
	cout << "-------------------------------------------------" << endl;
	cout << endl;
	cout << "   Relocates the secondary role to the given hostname." << endl;
	cout << endl;
    }
    else if ( topic == Chain("t12"))
    {
	cout << endl;
	cout << "relocate mediator for <tableset> to '<hostname>'" << endl;
	cout << "------------------------------------------------" << endl;
	cout << endl;
	cout << "   Relocates the mediator role to the given hostname." << endl;
	cout << endl;
    }
    else if ( topic == Chain("t13"))
    {
	cout << endl;
	cout << "drop tableset <tableset>" << endl;
	cout << "------------------------" << endl;
	cout << endl;
	cout << "   Drops the specified tableset." << endl;
	cout << endl;
    }
    else if ( topic == Chain("t14"))
    {
	cout << endl;
	cout << "remove tableset <tableset>" << endl;
	cout << "--------------------------" << endl;
	cout << endl;
	cout << "   Removes the tableset defintion for the specified tableset." << endl;
	cout << endl;
    }
    else if ( topic == Chain("t15"))
    {
	cout << endl;
	cout << "add <app|sys|temp> datafile '<filename>' size <numpages> to <tableset>" << endl;
	cout << "----------------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Adds a new datafile with the specified size to the given tableset" << endl;
	cout << endl;
    }

    else if ( topic == Chain("t16"))
    {
	cout << endl;
	cout << "check tableset <tableset>" << endl;
	cout << "-------------------------" << endl;
	cout << endl;
    }
    else if ( topic == Chain("17"))
    {
	cout << endl;
	cout << "verify tableset <tableset>" << endl;
	cout << "--------------------------" << endl;
	cout << endl;
	cout << "   Perform a consistency check for the given tableset" << endl;
	cout << endl;
    }
    else if ( topic == Chain("t18"))
    {
	cout << endl;
	cout << "correct tableset <tableset>" << endl;
	cout << "---------------------------" << endl;
	cout << endl;
    }
    else if ( topic == Chain("t19"))
    {
	cout << endl;
	cout << "set checkpoint interval <intval> for <tableset>" << endl;
	cout << "-----------------------------------------------" << endl;
	cout << endl;
    }
    else if ( topic == Chain("t20"))
    {
	cout << endl;
	cout << "set initfile '<initfile>' for <tableset>" << endl;
	cout << "----------------------------------------" << endl;
	cout << endl;
	cout << "   Sets the specified init file for the corresponding tableset." << endl;
	cout << "   The init file must be an existing file containing database commands" << endl;
	cout << "   and must be specified with a full path." << endl;
	cout << endl;
	cout << "   The database commands of the init file are executed at tableset startup time." << endl;
	cout << "   In this sense, an init file can be used to perform cleanup" << endl;
	cout << "   or consistency operations on user level" << endl;
	cout << endl;
	cout << "   For example, counter values, which are not transaction safe can be adjusted" << endl;
	cout << "   to appropriate values" << endl;
	cout << endl;
    }
    else if ( topic == Chain("t21"))
    {
	cout << endl;
	cout << "set syssize <intval> for <tableset>" << endl;
	cout << "----------------------------------------" << endl;
	cout << endl;
	cout << "   Sets the initial system page size." << endl;
	cout << "   To perform this operation, the corresponding tableset must be in status defined" << endl;
	cout << endl;
    }
    else if ( topic == Chain("t22"))
    {
	cout << endl;
	cout << "set tmpsize <intval> for <tableset>" << endl;
	cout << "----------------------------------------" << endl;
	cout << endl;
	cout << "   Sets the initial temp page size." << endl;
	cout << "   To perform this operation, the corresponding tableset must be in status defined" << endl;
	cout << endl;
    }
    else if ( topic == Chain("t23"))
    {
	cout << endl;
	cout << "set tsroot '<tableset root path>' for <tableset>" << endl;
	cout << "----------------------------------------" << endl;
	cout << endl;
	cout << "   Sets the tableset root path." << endl;
	cout << "   To perform this operation, the corresponding tableset must be in status defined" << endl;
	cout << endl;
    }
    else if ( topic == Chain("t24"))
    {
	cout << endl;
	cout << "set tsticket '<ticket file>' for <tableset>" << endl;
	cout << "----------------------------------------" << endl;
	cout << endl;
	cout << "   Sets the ticket file for the tableset online backup." << endl;
	cout << endl;
    }
    else if ( topic == Chain("t25"))
    {
	cout << endl;
	cout << "set lognum <intval> for <tableset>" << endl;
	cout << "----------------------------------------" << endl;
	cout << endl;
	cout << "   Sets the number of online redo log file for the correspoinding tableset." << endl;
	cout << "   To perform this operation, the corresponding tableset must be in status defined" << endl;
	cout << endl;
    }
    else if ( topic == Chain("t26"))
    {
	cout << endl;
	cout << "set logsize <intval> for <tableset>" << endl;
	cout << "----------------------------------------" << endl;
	cout << endl;
	cout << "   Sets the file size in bytes of the redo log files for the correspoinding tableset." << endl;
	cout << "   To perform this operation, the corresponding tableset must be in status defined" << endl;
	cout << endl;

    }
    else if ( topic == Chain("t27"))
    {
	cout << endl;
	cout << "set sortareasize <intval> for <tableset>" << endl;
	cout << "----------------------------------------" << endl;
	cout << endl;
	cout << "   Sets the sort area size in bytes for the corresponding tableset." << endl;
	cout << "   The sortareasize is the maximum sorting buffer, which can be allocated by a single sql query" << endl;
	cout << "   The new value ist activated when the tableset is restarted" << endl;
	cout << endl;
    }
    else if ( topic == Chain("t28"))
    {
	cout << endl;
	cout << "sync tableset <tableset> [ with '<command>' ] [ <timeout> ] ] [ message 'system message' ]" << endl;
	cout << "-------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Writes a checkpoint for the given tableset." << endl;
	cout << "   The optional given command is executed, during the tableset is synchronized and locked." << endl;
	cout << "   So this can be used to create a consistent snapshot for a tableset ( e.g. with ZFS snapshot commands )" << endl;
	cout << "   A comment can be added to the sync command, which is stored in the backup stat table" << endl;
	cout << endl;
    }
    else if ( topic == Chain("t29"))
    {
	cout << endl;
	cout << "list datafile for <tableset>" << endl;
	cout << "-------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   List all configured datafiles for the given tableset" << endl;
	cout << endl;	
    }

    else if ( topic == Chain("t30"))
    {
	cout << endl;
	cout << "list logfile for <tableset>" << endl;
	cout << "-------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   List all configured datafiles for the given tableset" << endl;
	cout << endl;	
    }
    else if ( topic == Chain("t31"))
    {	
	cout << endl;
	cout << "list transaction for <tableset>" << endl;
	cout << "-------------------------------------------------------------" << endl;
	cout << endl;
	cout << endl;	
    }
    else if ( topic == Chain("t32"))
    {
	cout << endl;
	cout << "list object for <tableset>" << endl;
	cout << "-------------------------------------------------------------" << endl;
	cout << endl;
	cout << endl;	
    }
    else if ( topic == Chain("t33"))
    {
	cout << endl;
	cout << "reset tableset <tableset>" << endl;
	cout << "-------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Tries to reset a tableset to a defined offline state on the primary node." << endl;
	cout << "   The command just should be executed in case of any undetermined exception." << endl;	
	cout << endl;	
    }

    else if ( topic == Chain("b0"))
    {
	cout << endl;
	cout << "set logmng '<progname>' [ timeout <intval> ]" << endl;
	cout << "-------------------------------------------------------------" << endl;
	cout << endl;
    }
    else if ( topic == Chain("b1"))
    {
	cout << endl;
	cout << "list archlog" << endl;
	cout << "-------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   List all configured archive log locations for the given tableset" << endl;
	cout << endl;
    }
    else if ( topic == Chain("b2"))
    {
	cout << endl;
	cout << "enable archlog for <tableset>" << endl;
	cout << "-------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Enables archive log mode for the given tableset." << endl;
	cout << "   At least one valid archive log location must be defined to enable archive log mode" << endl;
	cout << endl;
    }
    else if ( topic == Chain("b3"))
    {	
	cout << endl;
	cout << "disable archlog for <tableset>" << endl;
	cout << "-------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Disables archive log mode for the given tableset." << endl;
	cout << endl;
    }
    else if ( topic == Chain("b4"))
    {
	cout << endl;
	cout << "add archlog <archid> path '<archpath>' to <tableset>" << endl;
	cout << "-------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Adds the specified archlog destination to the given tableset" << endl;
	cout << endl;
    }
    else if ( topic == Chain("b5"))
    {
	cout << endl;
	cout << "remove archlog <archlog> from <tableset>" << endl;
	cout << "-------------------------------------------------------------" << endl;
	cout << "   Removes the specified archlog destination from the given tableset" << endl;
	cout << endl;
    }
    else if ( topic == Chain("b6"))
    {
	cout << endl;
	cout << "begin backup for <tableset>" << endl;
	cout << "-------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Starts online backup mode for the given tableset" << endl;
	cout << "   During backup mode, any datafile changes are detected" << endl;
	cout << "   If any recovery is required, the original page is restored during logfile recovery" << endl;
	cout << endl;
    }
    else if ( topic == Chain("b7"))
    {
	cout << endl;
	cout << "end backup for <tableset>" << endl;
	cout << "-------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Finishes online backup mode for the given tableset" << endl;
	cout << "   Normally this is done, after backup has been finished for all datafiles." << endl;
	cout << endl;
    }
    else if ( topic == Chain("b8"))
    {
	cout << endl;
	cout << "recover tableset <tableset> [ to <point in time>]" << endl;
	cout << "-------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Execute an up-to-crash or point in time recover for the given tableset." << endl;
	cout << "   The corresponding tableset must be in status offline perform this action." << endl;
	cout << "   All required backup datafiles and offline redo logs have to be provided in the appropriate locations." << endl;
	cout << "   If an online backup should be restored, a valid backup ticket file has to be provided." << endl;
	cout << endl;
	cout << "   If point-in-time is used, an appropriate time stamp has to be provided in the following format" << endl;
	cout << endl;
	cout << "      <YYYY-mm-dd> HH:MM:SS Z>" << endl;
	cout << endl;
	cout << "   Sample : recover tableset TS1 to '2007-08-12 08:12:34 CEST';" << endl;
	cout << endl;
	cout << "   After the ceovery has been finished, the corresponding tableset can be started up." << endl;
	cout << endl;
    }

    else if ( topic == Chain("b9"))
    {
	cout << endl;
	cout << "export [ xml | binary | plain ] table <tablename> from <tableset> to '<filename>'" << endl;
	cout << "---------------------------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Export of a single table from the given tableset to the given export file." << endl;
	cout << "   Either xml, binary or plain export mode can be used. If no mode is specified, xml mode is used." << endl;
	cout << endl;
    }
    else if ( topic == Chain("b10"))
    {
	cout << endl;
	cout << "export [ xml | binary | plain ] tableset [ structure ] <tableset> to '<filename>'" << endl;
	cout << "---------------------------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Export of the complete given tableset to an export file." << endl;
	cout << "   This includes all defined user objects of the tableset." << endl;
	cout << "   If the structure option is given, no table content is exported." << endl;
	cout << "   Either xml, binary or plain export mode can be used. If no mode is specified, xml mode is used." << endl;
	cout << endl;
	
    }
    else if ( topic == Chain("b11"))
    {
	cout << endl;
	cout << "import [ xml | binary | plain ] table <tablename> to <tableset> from '<filename>'" << endl;
	cout << "---------------------------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Import of a single table from the given export file to the given tableset ." << endl;
	cout << "   Either xml, binary or plain export mode can be used. If no mode is specified, xml mode is used." << endl;
	cout << endl;
    }
    else if ( topic == Chain("b12"))
    {
	cout << endl;
	cout << "import [ xml | binary | plain ] tableset [ structure ] <tableset> from '<filename>'" << endl;
	cout << "-----------------------------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Import of a tableset from an export file." << endl;
	cout << "   For consistency reasons, the name of the given tableset must match with the tableset in the import file." << endl;
	cout << "   If the structure option is given, no table content is imported." << endl;
	cout << "   Either xml, binary or plain export mode can be used. If no mode is specified, xml mode is used." << endl;
	cout << endl;
    }
    else if ( topic == Chain("b13"))
    {
	cout << endl;
	cout << "list bustat for <tableset>" << endl;
	cout << "-----------------------------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Lists the online backup statistics for the given tableset." << endl;
	cout << endl;
    }
    else if ( topic == Chain("b14"))
    {
	cout << endl;
	cout << "reset bustat for <tableset>" << endl;
	cout << "-----------------------------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Resets the online backup statistics for the given tableset." << endl;
	cout << endl;
    }
    else if ( topic == Chain("b15"))
    {
	cout << endl;
	cout << "show logmng" << endl;
	cout << "-----------------------------------------------------------------------------------" << endl;
	cout << endl;
	cout << "   Prints the current log manager configuration" << endl;
	cout << endl;
    }

    else
    {
	helpOverview();
    }
}


