/**
 * @author      ETSI / STF481 / Yann Garcia
 * @version     $URL$
 *              $Id$
 */
package org.etsi.ttcn.codec.its.security;

import org.etsi.common.ByteHelper;
import org.etsi.ttcn.codec.CodecBuffer;
import org.etsi.ttcn.codec.MainCodec;
import org.etsi.ttcn.codec.generic.Integer;
import org.etsi.ttcn.tci.IntegerValue;
import org.etsi.ttcn.tci.Type;
import org.etsi.ttcn.tci.Value;

/**
 * @desc Codec for an integer of variable length
 * @see Draft ETSI TS 103 097 V1.1.14 Clause 4.2.1   IntX
 */
public class IntX extends Integer {
    
    /**
     * Specialised constructor
     * @param mainCodec The MainCodec reference
     */
    public IntX(MainCodec mainCodec) {
        super(mainCodec);
    }
    
    /**
     * @desc Decoder for an integer of variable length
     */
    @Override
    public Value decode(CodecBuffer buf, Type decodingHypothesis) {
//        TERFactory.getInstance().logDebug(">>> IntX.decode: " + decodingHypothesis.getName());
        
        // Read the first byte
        byte msb = buf.getBytes(0, 1)[0];
        if ((msb & 0x80) == 0x00) { // Integer < 128
            mainCodec.setHint("IntXLen", "8");
            mainCodec.setHint("HeaderFieldContainer.its_aidLen", "8"); // TCT3 workaround, i don't know how to abstract this :-(
            return super.decode(buf, decodingHypothesis);
        } else {
            // Decode the length. The encoding of the length shall use at most 7 bits set to 1 (see Draft ETSI TS 103 097 V1.1.14 Clause 4.2.1    IntX)
            byte bit;
            byte byteLen = 1;
            do {
                bit = (byte) ((byte) (msb << byteLen++) & 0x80);
            } while (bit != 0x00);
            // Set the IntX length
            mainCodec.setHint(decodingHypothesis.getName() + "Len", String.valueOf(byteLen * Byte.SIZE ));
            mainCodec.setHint("HeaderFieldContainer.its_aid" + "Len", String.valueOf(byteLen * Byte.SIZE )); // TCT3 workaround, i don't know how to abstract this :-(
            // Remove the length from the real integer value
            byte[] newBuf = buf.getBytes();
            newBuf[0] &= (byte)(Math.pow(2.0, 8 - byteLen + 1) - 1);
            CodecBuffer newBuffer = new CodecBuffer(newBuf);
            buf.overwriteWith(newBuffer);
            // Decode it
            return super.decode(buf, decodingHypothesis);
        }
    }
    
    /**
     * @desc Encoder for an integer of variable length
     */
    @Override
    public CodecBuffer encode(Value value) {
//        TERFactory.getInstance().logDebug(">>> IntX.encode: " + value.getType().getName());
        
        int iv = mainCodec.getTciCDRequired().getInteger((IntegerValue)value);
        byte[] result = TlsHelper.getInstance().size2tls(iv);
        mainCodec.setHint("integerLen", String.valueOf(result.length * Byte.SIZE ));
        IntegerValue newValue = mainCodec.getTciCDRequired().setInteger(ByteHelper.byteArrayToInt(result));
        return super.encode(newValue);
    }
    
} // End of class IntX 
