/*


    ========== licence begin GPL
    Copyright (C) 2002-2003 SAP AG

    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
    of the License, 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; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end


*/

package com.sap.dbtech.powertoys;

import java.sql.SQLException;
import java.util.Properties;

import com.sap.dbtech.jdbc.DriverSapDB;
import com.sap.dbtech.rte.comm.JdbcCommFactory;
import com.sap.dbtech.rte.comm.JdbcCommunication;
import com.sap.dbtech.rte.comm.NativeComm;
import com.sap.dbtech.rte.comm.RTEException;
import com.sap.dbtech.rte.comm.SocketComm;
import com.sap.dbtech.util.MessageKey;
import com.sap.dbtech.util.MessageTranslator;
import com.sap.dbtech.util.StructuredMem;
import com.sap.dbtech.util.Tracer;
/**
 * Executes loader commands for SAP DB
 */
public class Loader
{
    public static final String hostKeyC = "host";
    private static final String hostDefaultC = "";
    public static final String dbnameKeyC = "dbname";
    private static final String dbnameDefaultC = "";
    public static final String dbrootKeyC = "dbroot";
    private static final String dbrootDefaultC = "";
    public static final String userKeyC = "user";
    private static final String pgmNameC = "lserver";
    private static final String transportC = "transport";
    private static final int alignSizeC = 8;
    static final int indicatorLengthC = 4;

    private JdbcCommunication connection;
    private boolean inCommunication;
    /**
       creates a new Loader.

       The following properties are used by this class:
        <UL>
        <LI>"host": start lserver on this host
        <LI>"dbname": start lserver for this database
        <LI>"dbroot": start dbmserver for this release/diretory
        <LI>"user": user,pwd implicit lserver connect (not yet implemented)
        <UL>
     */
    public Loader(Properties properties) throws RTEException {
        String host = properties.getProperty(hostKeyC, hostDefaultC);
        String dbname = properties.getProperty(dbnameKeyC, dbnameDefaultC);
        String dbroot = properties.getProperty(dbrootKeyC, dbrootDefaultC);
        String transport = properties.getProperty(transportC, "socket");

        JdbcCommFactory factory = null;
        try {
	        try {
	            if (DriverSapDB.loadNativeCommunication() == DriverSapDB.nativeCommunication_enabled) {
	                factory = NativeComm.factory;
	            } else {
	                factory = SocketComm.factory;
//	                if native communication is available on all platforms the
//	                following should be uncomment
//	                throw new RTEException(MessageTranslator.translate(
//	                        MessageKey.ERROR_LIBRARYNOTLOADED,
//	                        DriverSapDB.nativeCommunication_dllName_C, ""), -10899);
	            }
	            DriverSapDB.openTrace("",properties);
	            Tracer.print ("new Loader Connection ", properties);
	            this.connection = factory.xopen(host, dbname, dbroot, pgmNameC,
	                    properties);
	
	        } catch (Error linkErr) {
	            factory = SocketComm.factory;
	            this.connection = factory.xopen(host, dbname,
	                                            dbroot, pgmNameC, properties);
	//          if native communication is available on all platforms the
	//          following should be uncomment
//	            throw new RTEException(MessageTranslator.translate(
//	                    MessageKey.ERROR_LIBRARYNOTLOADED,
//	                    DriverSapDB.nativeCommunication_dllName_C, linkErr
//	                            .toString()), -10899);
	        }
        }catch (RTEException rteExc) {
            Tracer.println ("using "+factory);
            Tracer.println ("=> FAILED");
            throw rteExc;
        }
        Tracer.println ("using "+this.connection);
        Tracer.println ("=> " + this);
 }
    
    /**
     * closes the connection
     */
    public void release ()
        throws RTEException
    {
        Tracer.println (this+"->release ()");
        if (this.connection != null) {
            try {
              try {
                this.cmd("release");
              }
              catch (Exception ignore) {}
              this.connection.release ();
            }
            finally {
                this.connection = null;
            }
        }
    }
    /**
     *
     */
    public void finalize ()
        throws RTEException
    {
        this.release ();
    }
    /**
     * executes <i>cmdString</i> in the current lserver session.
     *
     * @exception LoaderException
     * @exception RTEException
     */
    public String cmd(String cmdString) throws RTEException, LoaderException {
        Tracer.println(this + "->cmd (" + cmdString + ")");
        StructuredMem request;
        int alignedLen;
        StructuredMem reply;
        String result;

        try {
            /*
             * send request
             */
            request = this.connection.getRequestPacket();
            if (cmdString.length() == 0) {
                request.putBytes(new byte[]{0x00}, 0);
                alignedLen = (1+ alignSizeC - 1) / alignSizeC * alignSizeC;
            } else {
                request.putString(cmdString, 0);
                alignedLen = (cmdString.length() + alignSizeC - 1) / alignSizeC * alignSizeC;
            }
            this.connection.request(request, alignedLen);
            this.inCommunication = true;
            reply = this.connection.receive();
            this.inCommunication = false;
            /*
             * parse result and throw exception
             */
            String errorIndicator = reply.getString(0, Math.min(
                    indicatorLengthC, reply.size()));
            if (errorIndicator.startsWith("OK")) {
                int dataStart = errorIndicator.indexOf('\n') + 1;
                result = reply.getString(dataStart, reply.size() - dataStart);
            } else {
                throw LoaderException.create(reply);
            }
            Tracer.println("=> "+result);
            return result;
        } catch (LoaderException e) {
            Tracer.println(" <-!");
            Tracer.traceException(e);
            throw e;
        } catch (RTEException err) {
            Tracer.println(" <-!");
            Tracer.traceException(err);
            throw err;
        } finally {
        	this.inCommunication = false;
        }
    }
    
    public void cancel() throws SQLException 
    {
    	if(inCommunication) {
    		this.connection.cancel();
    	}
    }
    /**
     * creates a new Loader by specifying the host and the dbname
     */
    public static Loader dbLoader (String host, String dbname)
        throws RTEException
    {
        Properties props = new Properties ();

        if (host != null) {
            props.put (hostKeyC, host);
        }
        if (dbname != null) {
            props.put (dbnameKeyC, dbname);
        }
        return new Loader (props);
    }
    /**
     * create a new Loader by specifying the host and the dbroot
     */
    public static Loader dbrootLoader (String host, String dbroot)
        throws RTEException
    {
        Properties props = new Properties ();

        if (host != null) {
            props.put (hostKeyC, host);
        }
        props.put (dbrootKeyC, dbroot);
        return new Loader (props);
    }

}
