/*


    ========== 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.rte.comm;

import java.util.StringTokenizer;

import com.sap.dbtech.util.StructuredBytes;

/**
 * the layout used by SQL packets.
 */
class DbPacketLayout implements com.sap.dbtech.rte.comm.PacketLayout {
    private int maxDataLength;
    private int maxSegmentSize;
    private int minReplySize;
    private int packetSize;
    private int portNumber;
    private boolean supportsChallengeResponse = false;    
    public static final int safePacketSizeC = 0; //Integer.MAX_VALUE;
    /**
     * creates a new DbpacketLayout with dummy sizes.
     */
    DbPacketLayout ()
    {
        // this (Short.MAX_VALUE, Short.MAX_VALUE, -1, 0);
        this (safePacketSizeC, 1024 * 32, 0, safePacketSizeC);
    }
    /**
     * create a new DbPacketLayout.
     */
    DbPacketLayout (
            int maxData,
            int maxSegment,
            int minReply,
            int packetS
          )
    {
        this.maxDataLength = maxData;
        this.maxSegmentSize = maxSegment;
        this.minReplySize = minReply;
        this.packetSize = packetS;
    }
    DbPacketLayout (
            StructuredBytes reply,
            boolean trustReply, 
            boolean parseVarData
          ) 
    {
        getPacketLayoutFromReply (reply, trustReply, parseVarData); 
    }
    /**
     *
     */
    public void
    dumpOn (
        java.io.PrintStream out,
        String comment)
    {
        out.println ("DbPacketLayout: " + comment);
        out.println ("    packetSize: " + this.packetSize);
        out.println ("    maxSegmentSize: " + this.maxSegmentSize);
        out.println ("    maxDataLength: " + this.maxDataLength);
        out.println ("    minReplySize: " + this.minReplySize);
    }
    /**
     * the maximal size of a command the client can send to the server.
     * @return int
     */
    public int maxCmdDataLength () {
        return this.maxDataLength () - this.minReplySize ();
    }
    /**
     * the maximal size of request + reply
     */
    public int maxDataLength() {
        return maxDataLength;
    }
    /**
     * the maximal size of the whole packet (including RTE data)
     */
    public int maxSegmentSize() {
        // return maxSegmentSize;
        return this.maxSegmentSize;
    }
    /**
     * the minimal size of a reply.
     */
    public int minReplySize() {
        return minReplySize;
    }
    /**
     *
     */
    public int packetSize() {
        return packetSize;
    }

    public boolean isChallengeResponseSupported() {
        return supportsChallengeResponse;
    }
    
    private void
    getPacketLayoutFromReply (
        StructuredBytes reply,
        boolean trustReply,
        boolean parseVarData) 
    {

        this.maxDataLength = reply.getInt4 (RteC.Header_END_O_C + RteC.Connect_MaxDataLen_O);
        this.minReplySize = reply.getInt4 (RteC.Header_END_O_C + RteC.Connect_MinReplySize_O);
        this.packetSize = reply.getInt4 (RteC.Header_END_O_C + RteC.Connect_PacketSize_O);
        if (trustReply) {
            this.maxSegmentSize = reply.getInt4 (RteC.Header_END_O_C + RteC.Connect_MaxSegmentSize_O);
        }
        else {
            this.maxSegmentSize = packetSize;
        }

        // Sanity checks that prevent garbled replies from the x_server
        // to do any harm
        /*
        if(   (packetSize < 16384)  // lower limit of packet size is 16384
           || (maxDataLen <= packetSize) // maxDataLength is always greater 		
           || (packetSize > 500 * 1024) // upper limit of packet size
           ) {
        	throw new RTEException (MessageTranslator.translate(MessageKey.ERROR_REPLY_GARBLED),
            RteC.CommunicationErrorCodeMap_C[RteC.SQLRECEIVE_LINE_DOWN_C]);
        }
        */
        if (parseVarData){
            this.parseVardataPart(reply);
        }    
    }

    private void parseVardataPart (StructuredBytes reply) {
        boolean forceReconnect = false;
        int vardataOffest = RteC.Header_END_O_C + RteC.Connect_VarPart_O;
        int vardataLen = reply.bytes().length - vardataOffest;
        for (int pos = vardataOffest; pos < vardataLen; ){
          int len = reply.getInt1(pos);
          if (len <= 0) break;
          switch ((char)reply.getInt1(pos+1)) {
	        case RteC.ARGID_PORT_NO_C:{
	            //always not swapped
	            int lowerByte = reply.getInt1(pos+3);
	            if (lowerByte < 0) {
	                lowerByte += 256;
	            }
	            this.portNumber = (reply.getInt1(pos+2) * 256) + lowerByte;
   	            break;
	        }    
	        case RteC.ARGID_AUTH_ALLOW_C:{
	            String auth = reply.getString(pos+2,len-3);
	            StringTokenizer st = new StringTokenizer(auth,",");
	            while (st.hasMoreTokens()){
	              if (st.nextToken().equals("SCRAMMD5")){
	                this.supportsChallengeResponse = true;  
	                break;
	              }  
	            }
                
	            break;
	        }    
	        default:
	            break;
          }
//          System.out.println("Vardata Type: "+ reply.getString(pos+1,1)+ " Value: "+ Tracer.Hex2String(reply.getBytes(pos+2,len-2)));
          pos += len;
        }
    }

 
    public int getPortNumber() {
        return portNumber;
    }
    
}