/*


    ========== 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.jdbc.packet;

import java.io.*;

import com.sap.dbtech.util.*;
import com.sap.dbtech.vsp001.*;

/**
 *
 */
public abstract class SQLPacket extends MemIndirection
    implements Traceable
{
    protected int segmOffs;
    protected int partOffs;
    // constants
    protected static final int Alignment_C = 8;
    /**
     *
     * @param rawPacket com.sap.dbtech.util.StructuredMem
     */
    protected SQLPacket(StructuredMem rawPacket) {
        super (rawPacket);
    }
    /**
     *
     * @return int
     * @param size int
     */
    protected final int aligned (int size) {
        int modResult = size % Alignment_C;
        if (modResult != 0) {
            size += (Alignment_C - modResult);
        }
        return size;
    }
    /**
     *
     * @param stream PrintStream
     * @param maxBuf int
     */
    int dumpPart (PrintStream stream, int maxBuf, int partPos) {
        /*
         * dump part header
         */
        stream.println ("       <PART ");
        stream.println ("       partkind=\""+PartKind.names [this.getInt1 (partPos + Part.PartKind_O)]+"\"");
        stream.println ("       arg_count=\""+this.getInt2 (partPos + Part.ArgCount_O)+"\"");
        stream.println ("       buflen=\""+this.getInt4 (partPos + Part.BufLen_O)+"\"");
        stream.println ("       bufsize=\""+this.getInt4 (partPos + Part.BufSize_O)+"\"");
        stream.println ("       partpos=\""+partPos+"\"");

//        StringUtil.fprintfs (stream, "        %s: %d arguments (%d of %d at %d)\n",
//            new Object [] {
//            PartKind.names [this.getInt1 (partPos + Part.PartKind_O)],
//                new Integer (this.getInt2 (partPos + Part.ArgCount_O)),
//                new Integer (this.getInt4 (partPos + Part.BufLen_O)),
//                new Integer (this.getInt4 (partPos + Part.BufSize_O)),
//                new Integer (partPos),
//        });

        /*
         * dump data
         */
        int offset = partPos + Part.Data_O;
        StructuredMem dataMem = this.getPointer (partPos + Part.Data_O);
        int dataLen = this.getInt4 (partPos + Part.BufLen_O);
        if (maxBuf == -1) {
            maxBuf = dataLen;
        }
        else {
            maxBuf = Math.min (maxBuf, dataLen);
        }
        switch (this.getInt1 (partPos + Part.PartKind_O)) {
          case PartKind.Longdata_C:{
             final String[] valmodeMap = {"vm_datapart","vm_alldata",
                                          "vm_lastdata","vm_nodata",
                                          "vm_no_more_data","vm_last_putval",
                                          "vm_data_trunc","vm_close"};
             int undef_signal = this.getInt1(offset+0);
             int info_set = this.getInt1(offset+25);
             int valmode = this.getInt1(offset+28);

             stream.println ("       <LONG_DESCRIPTOR ");
             stream.println("           undef_signal=\""+undef_signal+((undef_signal==256)?" isNull":" notNull")+"\"");
             stream.println("           maxlen      =\""+this.getInt4(offset+17)+"\"");
             stream.println("           intern_pos  =\""+this.getInt4(offset+21)+"\"");
             stream.print("           info_set    =\"");
             if (info_set==0)
              Tracer.println("0xFFFFFFFF\"");
             else {
              Tracer.print("0x");
              Tracer.print( ((info_set & 128)!=0)?"B":"F" );
              Tracer.print( ((info_set &  64)!=0)?"B":"F" );
              Tracer.print( ((info_set &  32)!=0)?"B":"F" );
              Tracer.print( ((info_set &  16)!=0)?"B":"F" );
              Tracer.print( ((info_set &   8)!=0)?"B":"F" );
              Tracer.print( ((info_set &   4)!=0)?"B":"F" );
              Tracer.print( ((info_set &   2)!=0)?"B":"F" );
              Tracer.println( ((info_set &   1)!=0)?"B\"":"F\"" );
             }
             stream.println("           valmode     =\""+valmode+" ("+valmodeMap[valmode]+")\"");
             stream.println("           valind      =\""+this.getInt2(offset+29)+"\"");
             stream.println("           valpos      =\""+this.getInt4(offset+33)+"\"");
             stream.println("           vallen      =\""+this.getInt4(offset+37)+"\"");
             stream.println ("       </LONG_DESCRIPTOR ");
            break;
          }
          default:{
//          dataMem.traceOn (stream, 0, maxBuf);
            break;
          }
        }
        stream.println ("       </PART> ");
      return this.aligned (Part.Data_O + dataLen);
    }
    /**
     *
     * @return int
     * @param stream java.io.PrintStream
     * @param maxBuf int
     * @param segmPos int
     */
    abstract int dumpSegment (PrintStream stream, int maxBuf, int segmPos);
    /**
     *
     * @return int
     */
    public int partCount () {
        return this.mem.getInt2 (this.segmOffs + Segment.NoOfParts_O);
    }
    /**
     *
     * @return int
     */
    public int segmCount () {
        return this.mem.getInt2 (Packet.NoOfSegm_O);
    }
    /**
     *
     * @param stream PrintStream
     * @param maxBuf int
     */
    public void traceOn (PrintStream stream) {
        this.traceOn (stream, -1);
    }
    
    /**
     *
     */
    public void invariant ()
    {
        int messSwap = this.getInt1 (Packet.MessSwap_O);
        if (messSwap <= 0) {
            throw new Error(
                MessageTranslator.translate(MessageKey.ERROR_INVARIANT_MESSSWAP,
                                            Integer.toString(messSwap))
            );
        }
    }
    
    /**
     *
     * @param stream PrintStream
     * @param maxBuf int
     */
    public void traceOn (PrintStream stream, int maxBuf) {
        /*
         * dump packet header
         */
        stream.println ("<PACKECT ");
        stream.println ("messcode=\"" + this.getInt1 (Packet.MessCode_O)+"\"");
        stream.println ("mess swap=\"" + this.getInt1 (Packet.MessSwap_O)+"\"");
        stream.println ("application=\"" + this.getString (Packet.ApplVersion_O, 8)+"\" >");
        stream.println ("<! (used " + String.valueOf (this.getInt4 (Packet.VarpartLen_O)) + " of "
            + String.valueOf (this.getInt4 (Packet.VarpartSize_O)) + ")>");
        /*
         * dump segments
         */
        int segmCount = this.segmCount ();
        int pos = Packet.Segment_O;
        for (int i = 0; i < segmCount; ++i) {
            pos += this.dumpSegment (stream, maxBuf, pos);
        }
        stream.println ("</PACKECT> <!=================End of packet >");
    }
}