/*

    @author DanielD

    ========== 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.procserver;

import java.net.*;
import java.io.*;
import java.util.*;

/**
 *
 */
public class ProcServer
{
    private boolean isRunning;
    private Dictionary commandTable;
    /**
     * creates a new ProcServer
     */
    public
    ProcServer ()
    {
        this.installCommands ();
    }
    /**
     *
     */
    protected void
    installCommands ()
    {
        this.commandTable = new Hashtable ();
        /*
         * ping
         */
        Command ping = new Command () {
            public String run (String [] args) {
                return "";
            }
        };
        this.commandTable.put ("ping", ping);
        /*
         * stop
         */
        Command stop = new Command () {
            public String run (String [] args) {
                isRunning = false;
                return "";
            }
        };
        this.commandTable.put ("stop", stop);
        /*
         * newsession
         */
        Command newsession = new Command () {
            public String run(String[] args)
            throws ProcServerSession.Exception {
                new ProcServerSession (args [1]).run ();
                return "";
            }
        };
        this.commandTable.put ("newsession", newsession);
    }
    /**
     *
     */
    void
    run (
        int port)
    throws com.sap.dbtech.rte.comm.RTEException, IOException
    {
        SocketComm comm = new SocketComm (port, 8 * 1024);
        this.isRunning = true;
        while (this.isRunning) {
            String cmdLine = comm.recvString ();
            String [] args = this.parseCommand (cmdLine);
            Log.log ("cmd: " + cmdLine);
            Command cmd = (Command) this.commandTable.get (args [0]);
            if (cmd == null) {
                Log.logErr ("command " + args [0] + " not defined");
                comm.sendString ("ERR unknown command");
                continue;
            }
            try {
                String result = cmd.run (args);
                Log.log (" ==> '" + result + "'");
                comm.sendString ("OK  " + result);
            }
            catch (Throwable exc) {
                Log.traceException (exc);
                comm.sendString ("ERR Exception " + exc.toString ());
            }
        }
    }
    /**
     *
     */
    protected String []
    parseCommand (
        String source                            )
    {
        Vector tmpvec = new Vector (10);
        int pos = 0;
        int endPos = source.length ();
        String newval;
        String [] result;
        char [] chars = source.toCharArray ();
        char quoteChar = 0;
        final int inWS_C = 0;
        final int inWord_C = 1;
        int state = inWS_C;
        boolean inQuote = false;
        char current;
        int wordLen = 0;
        char [] word = new char [chars.length];

        while (pos < endPos) {
            current = chars [pos];
            if (Character.isWhitespace (current)) {
                switch (state) {
                    case inWS_C:
                        // simply skip
                        break;
                    case inWord_C:
                        if (inQuote) {
                            // inside word
                            word [wordLen] = current;
                            ++wordLen;
                        }
                        else {
                            // at end of word
                            newval = String.copyValueOf (word, 0, wordLen);
                            tmpvec.addElement (newval);
                            wordLen = 0;
                        }
                        break;
                }
            }
            else {
                switch (current) {
                    case '\'':
                    case '"':
                        if (inQuote) {
                            if (quoteChar == current) {
                                inQuote = false;
                            }
                            else {
                                word [wordLen] = current;
                                ++wordLen;
                            }
                        }
                        else {
                            inQuote = true;
                            quoteChar = current;
                            state = inWord_C;
                        }
                        break;
                    case '\\':
                        ++pos;
                        current = chars [pos];
                        word [wordLen] = current;
                        ++wordLen;
                        state = inWord_C;
                        break;
                    default:
                        word [wordLen] = current;
                        ++wordLen;
                        state = inWord_C;
                        break;
                }
            }
            ++pos;
        }
        if (state == inWord_C) {
            newval = String.copyValueOf (word, 0, wordLen);
            tmpvec.addElement (newval);
        }
        result = new String [tmpvec.size ()];
        for (int i = 0; i < result.length; ++i) {
            result [i] = (String) tmpvec.elementAt (i);
        }
        return result;
    }
    /**
     * used when called form the command line
     */
    public static void main (String [] args)
    throws IOException
    {
        Log.open ();
        try {
            int port = Integer.parseInt (args [0]);
            Log.log ("connecting to port " + port);
            Class.forName ("com.sap.dbtech.jdbc.DriverSapDB");
            new ProcServer ().run (port);
        }
        catch (Throwable exc) {
            Log.traceException (exc);
        }
        Log.close ();
    }
}
