/**
 * @author      ETSI / STF462 / Alexandre Berge
 * @version     $URL$
 *              $Id$
 */
package org.etsi.ttcn.codec.generic;

import java.math.BigInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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

public class Integer extends ICodec {

    protected final static Pattern UNSIGNED_VARIANT = Pattern.compile("\\w*unsigned\\w*");
    
    public Integer(MainCodec mainCodec) {
        super(mainCodec);
    }

    @Override
    public Value decode(CodecBuffer buf, Type decodingHypothesis) {

        IntegerValue iv = (IntegerValue)decodingHypothesis.newInstance();
        int lengthInBits;
        byte[] value = null;

        // Get length
        String hint = mainCodec.getHint(decodingHypothesis.getName() + "Len");
        if(hint == null) {
            lengthInBits = getVariantBitLength(decodingHypothesis.getTypeEncodingVariant());
        }
        else {
            lengthInBits = java.lang.Integer.parseInt(hint);
        }
        
        value = buf.readBits(lengthInBits);
        
        try {
            Matcher matcher = UNSIGNED_VARIANT.matcher(decodingHypothesis.getTypeEncodingVariant());
            if(matcher.find()) {
                // Unsigned integer                
                if(lengthInBits >= 32) {                 
                    iv.setBigInt(new BigInteger(1, value)); // /!\ ttwb specific
                }
                else {
                    iv.setInt(ByteHelper.byteArrayToInt(value));
                }
            }
            else {
                // Signed integer 
                iv.setInt(ByteHelper.byteArrayToSignedInt(value, lengthInBits));
            }
        }
        catch(Exception e) {
            // empty on purpose
        }
        
        return iv;
    }

    @Override
    public CodecBuffer encode(Value value) {

        IntegerValue iv = (IntegerValue)value;
        byte[] encoded = null;
        CodecBuffer res = new CodecBuffer();
        int lengthInBits = 0;
        int lengthInBytes = 0;

        // Get length
        String hint = mainCodec.getHint(value.getType().getName() + "Len");
        if(hint == null) {
            lengthInBits = getVariantBitLength(value.getType().getTypeEncodingVariant());
        }
        else {
            lengthInBits = java.lang.Integer.parseInt(hint);
        }
        lengthInBytes = lengthInBits / 8 + (((lengthInBits % 8) > 0)?1:0);
        
//        System.out.println(String.format("Integer.encode: length: %d", lengthInBytes));
        if (lengthInBits > java.lang.Integer.SIZE) {
            encoded = ByteHelper.longToByteArray(iv.getBigInt().longValue(), lengthInBytes);
            res.setBits(encoded, lengthInBits);
        } else {
            encoded = ByteHelper.intToByteArray(iv.getInt(), lengthInBytes);
            res.setBits(encoded, lengthInBits);
        }
        res.setBits(encoded, lengthInBits);

        return res;
    }

}
