///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoCPlusTest.cc
// --------------
// Test and demo program for teh cego C++ API
//
// Design and Implementation by Bjoern Lemke               
//                                                         
// (C)opyright 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: XXX
//
///////////////////////////////////////////////////////////////////////////////

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

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

#include "CegoNet.h"

#define CGPLUSTEST_PRODUCT "CegoCPlusTest"
#define CGPLUSTEST_VERSION "1.0.0"
#define CGPLUSTEST_COPYRIGHT "Copyright (C) 2010 by Bjoern Lemke. All rights reserved"

#define USAGE "Usage: cgplustest --user=<user>/<password>\n\
          [ --server=<host>]\n\
          [ --port=<port> ]\n\
          [ --protocol={serial|xml} ]\n\
	  [ --tableset=<tableset> ]\n\
          [ --logfile=<logfile> ]\n\
          [ --debug ] [ --version  ] [ --help ]"


#define DEFAULTPORT 2200
#define DEFAULTSERVER "localhost"
#define DEFAULTMYSQLFILE "mysqldump.sql"
#define DEFAULTPROTOCOL "xml"

// size info buffer len
#define SIZEBUFLEN 10
#define MSGBUFLEN 500 

#define LANGUAGE_ENV "LANG"
#define LOCALE_CATEGORY LC_TIME

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("tableset");
    longOpt.addOpt("user");
    longOpt.addOpt("debug");
    longOpt.addOpt("server", DEFAULTSERVER);
    longOpt.addOpt("protocol", DEFAULTPROTOCOL);
    longOpt.addOpt("port", Chain(DEFAULTPORT));
    
    try
    {
	longOpt.parseOpt(); 
    }
    catch ( Exception e )
    {
	Chain msg;
	e.pop(msg);
	cerr << msg << endl;
	cerr << USAGE << endl;
	exit(1);	
    }
    
    Chain user;
    Chain password;

    int lineNo=0;
    
    CegoNet *pCegoNet = 0;
    
    try
    {
    
	bool debug=false;
	if ( longOpt.isSet("debug") )
	    debug=true;
		
	if ( longOpt.isSet( Chain("help") ) )
	{	
	    cerr << USAGE << endl;
	    exit(0);
	}
	
	if ( longOpt.isSet( Chain("version") ) )
	{
	    cout << CGPLUSTEST_PRODUCT << " (" << sizeof(long) * 8 << " bit), Version " << CGPLUSTEST_VERSION 
		 << " [ lfc : " << __lfcVersionString  
		 << ", lfcxml : " <<  __lfcxmlVersionString << " ]" << endl;
	    cout << CGPLUSTEST_COPYRIGHT << endl;
	    exit(0);
	}

	Chain logFile = longOpt.getOptValue("logfile");
	Chain serverName = longOpt.getOptValue("server");
	Chain tableSet = longOpt.getOptValue("tableset");
	int portNo = longOpt.getOptValue("port").asInteger();
	
	Chain authString = longOpt.getOptValue("user");
	
	Tokenizer authTok(authString, Chain("/")); 
	authTok.nextToken(user);
	authTok.nextToken(password);
	
	if ( user.length() == 0 )
	{
	    cerr << "User not set" << endl;
	    exit (1);
	}
	if ( password.length() == 0 )
	{
	    cerr << "Password not set" << endl;
	    exit (1);
	}
	if ( tableSet.length() == 0 )
	{
	    cerr << "Tableset not set" << endl;
	    exit (1);
	}

	CegoDbHandler::ProtocolType protType;
	Chain prot = longOpt.getOptValue("protocol");
	
	if ( prot == Chain("serial") )
	{
	    protType = CegoDbHandler::SERIAL;
	}
	else if ( prot == Chain("xml") )
	{
	    protType = CegoDbHandler::XML;
	}
	else
	{
	    cerr << "Invalid protocol " << prot;
	    exit (1);
	}

	
	// for localization
	char* lang = 0;
	if ( ( lang = getenv(LANGUAGE_ENV) ) != 0)
	{
	    if ( setlocale(LOCALE_CATEGORY, lang) == 0)
	    {
		Chain msg = Chain("Cannot set locale ") + Chain(lang);
		cerr << msg << endl;
		exit(1);
	    }
	}
    
	Chain logMode("notice");
	if ( debug ) 
	    logMode = Chain("debug");

	pCegoNet = new CegoNet( protType, logFile, logMode );	    
	pCegoNet->connect(serverName, portNo, tableSet, user, password);
	
	// sample query 1 : create table
	
	Chain stmt = Chain("create table t1 ( a int,  b string(10));");
	pCegoNet->doQuery(stmt);
	cout << "Result :" << pCegoNet->getMsg() << endl;

	// sample query 2 : create procedure

	stmt = Chain("create procedure p1 ( a in int) return int \
begin\
  var b int;\
  insert into t1 values ( :a, 'XXX');\
  :a = :a +1;\
  return :a;\
end;");
	cout << "ResultCode=" << pCegoNet->doQuery(stmt) << endl;
	cout << "ResultMsg=" << pCegoNet->getMsg() << endl;

	stmt = Chain("call p1(11);");
	cout << "ResultCode=" << pCegoNet->doQuery(stmt) << endl;
	cout << "ResultMsg=" << pCegoNet->getMsg() << endl;

	stmt = Chain("call p1(12);");
	cout << "ResultCode=" << pCegoNet->doQuery(stmt) << endl;
	cout << "ResultMsg=" << pCegoNet->getMsg() << endl;

	stmt = Chain("select * from t1;");
	cout << "ResultCode=" << pCegoNet->doQuery(stmt) << endl;
	cout << "ResultMsg=" << pCegoNet->getMsg() << endl;

	ListT<CegoField> schema;
	pCegoNet->getSchema(schema);
	
	ListT<CegoFieldValue> fvl;
	while ( pCegoNet->fetchData(schema, fvl)  )
	{
	    CegoFieldValue *pFV = fvl.First();
	    while ( pFV ) 
	    {
		cout << *pFV << "\t";
		pFV = fvl.Next();
	    }
	    cout << endl;
	    
	    fvl.Empty();
	}

	pCegoNet->disconnect();
	delete pCegoNet;
	
    }
    catch ( Exception e )
    {
	Chain msg;
	e.pop(msg);
	cout << "Exception occured : " << msg << endl;

	if ( pCegoNet )
	{
	    pCegoNet->disconnect();
	    delete pCegoNet;
	}

    }

    exit(0);
}


