/**
 * @author	STF 424_ITS_Test_Platform
 * @version    $URL$
 *             $Id$
 */
package org.etsi.its.codec;

import java.io.IOException;
import java.math.BigInteger;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.etsi.codec.DecodingContext;
import org.etsi.codec.EncodingContext;
import org.etsi.codec.BasicCodecImpl;
import org.etsi.codec.TCIWrapperFactory;
import org.etsi.common.ByteHelper;
import org.etsi.ttcn.tci.BitstringValue;
import org.etsi.ttcn.tci.BooleanValue;
import org.etsi.ttcn.tci.CharstringValue;
import org.etsi.ttcn.tci.IntegerValue;
import org.etsi.ttcn.tci.OctetstringValue;
import org.etsi.ttcn.tci.TciCDProvided;
import org.etsi.ttcn.tci.TciCDRequired;
import org.etsi.ttcn.tci.TciValueTemplate;
import org.etsi.ttcn.tci.Type;
import org.etsi.ttcn.tci.Value;
import org.etsi.ttcn.tri.TriMessage;

/**
 * This is the base class to implement ITS specific codecs behavior. Default codec behavior are provided by the class BasicCodecImpl 
 *
 * Note that enumerated are encoded as integer, according to the variant
 * 
 * @category Codec
*/
public abstract class ItsCodecImpl extends BasicCodecImpl {

	/**
	 * Size of the Type fields in bits
	 */
	protected static final int TypeFieldBitSize = Byte.SIZE;

	/**
	 * Size of the Length fields in bytes
	 */
	protected static final int LengthFieldSize = 2;
	/**
	 * Size of the Length fields in bits
	 */
	protected static final int LengthFieldBitSize = LengthFieldSize * TypeFieldBitSize;
	
	/**
	 * Module version
	 */
	protected static final String Version = "1.0.0.2";

	/**
	 * Logger instance
	 */
	protected final static Logger _logger = Logger.getLogger("org.etsi.its");

	/** 
	 * Regex pattern used to extract length in value variant encoding clauses
	 */
	protected final static Pattern PatternVariantEncoding = Pattern.compile("((\\w+)\\s+)?((\\d+))\\s+bit"); // For Java regex test, see http://www.cis.upenn.edu/~matuszek/General/RegexTester/regex-tester.html;

	/** 
	 * Regex pattern used to extract length in value encoding clauses
	 */
	protected final static Pattern PatternEncoding = Pattern.compile("length\\((\\d+)\\)"); // For Java regex test, see http://www.cis.upenn.edu/~matuszek/General/RegexTester/regex-tester.html;

	/**
	 * Constructor
	 * @param typeServer 
	 */
	public ItsCodecImpl(TciCDRequired typeServer) {
		super(typeServer);
		_logger.entering(this.toString(), "Constructor");
	} // End of Constructor

	/** This operation decodes message according to the encoding rules and returns a TTCN-3 value. 
	 * The decodingHypothesis shall be used to determine whether the encoded value can be decoded. 
	 * If an encoding rule is not self-sufficient, i.e. if the encoded message does not inherently 
	 * contain its type decodingHypothesis shall be used. If the encoded value can be decoded without 
	 * the decoding hypothesis, the distinct null value shall be returned if the type determined from 
	 * the encoded message is not compatible with the decoding hypothesis
	 * 
	 * @param message The encoded message to be decoded
	 * @param decodingHypothesis The hypothesis the decoding can be based on
	 * @return Returns the decoded value, if the value is of a compatible type as the decodingHypothesis, else the distinct value null
	 * 
	 * See ETSI ES 201 873-6 V4.2.1 - 7.3.2.2.1 decode
	 */
	@Override
	public abstract Value decode(TriMessage message, Type decodingHypothesis);

	/** Returns an encoded TriMessage according to the encoding rules.
	 * This operation shall be called whenever the TE has to encode a Value
	 * 
	 * @param template The value to be encoded
	 * @return Returns an encoded TriMessage for the specified encoding rule
	 * 
	 * See ETSI ES 201 873-6 V4.2.1 - 7.3.2.2.2 encode
	 */
	@Override
	public TriMessage encode(final Value template) {
		_logger.entering(this.toString(), "encode", template.toString());
		return super.encode(template);
	}

	/**
	 * This method decodes a BitstringValue from a ByteArray representation at a global bit position
	 *
	 * @param decodingHypothesis The requested type
	 * @param decodingContext The complete encoded message as *received at a system port.
	 * @return A BitstringValue representing the decoded value
	 */
	protected BitstringValue decodeBitstringValue(final Type decodingHypothesis, DecodingContext decodingContext) {
		_logger.entering(this.toString(), "decodeBitstringValue", decodingHypothesis.getTypeEncodingVariant());

		BitstringValue value = (BitstringValue)decodingHypothesis.newInstance();

		_logger.info(String.format("Encoding: %s - %s", value.getValueEncodingVariant(), value.getValueEncoding()));
		// Extract the length
		int length = 0;
		if (value.getValueEncodingVariant() != null) {
			Matcher matcher = ItsCodecImpl.PatternVariantEncoding.matcher(value.getValueEncodingVariant());
			if (matcher.find()) {
				// Convert the integer value into byte array
				length = Integer.parseInt(matcher.group(3));
			} else {
				throw new RuntimeException(String.format("Invalid value encoding VARIANT: %s", value.getValueEncodingVariant()));
			}
		} else if (value.getValueEncoding() != null) {
			Matcher matcher = ItsCodecImpl.PatternEncoding.matcher(value.getValueEncoding());
			if (matcher.find()) {
				length = Integer.parseInt(matcher.group(1)); // Length is in bits
			} else {
				throw new RuntimeException(String.format("Invalid value encoding: %s", value.getValueEncodingVariant()));
			}
		} else {
			throw new RuntimeException("ItsCodecImpl.decodeBitstringValue: Variant values are null");
		}
		value = decodeBitstringValue(decodingContext, length);

		return value;
	} // End of method decodeBitstring

	/**
	 * This method decodes a BitstringValue from a ByteArray representation at a global bit position
	 *
	 * @param decodingContext The complete encoded message as *received at a system port.
	 * @param decodingLength An integer amount bits to decode
	 * @param decodingHypothesis The requested type
	 * @return an <code>BitstringValue</code> representing the decoded value
	 */
	@Override
	public BitstringValue decodeBitstringValue(DecodingContext decodingContext, int decodingLength, Type decodingHypothesis) {
		return decodeBitstringValue(decodingHypothesis, decodingContext);
	}

	/**
	 * This method decodes a CharstringValue from a ByteArray representation at a global bit position
	 *
	 * @param decodingContext The complete encoded message as *received at a system port.
	 * @param position The decoder bit position in the encoded buffer
	 * @return an <code>CharstringValue</code> representing the decoded value
	 */
	protected CharstringValue decodeCharstringValue(final Type decodingHypothesis, DecodingContext decodingContext) {
		_logger.entering(this.toString(), "decodeCharstringValue", decodingHypothesis.getName());
		int length = ByteHelper.byteArrayToInt(decodingContext.getNextBytes(Integer.SIZE / Byte.SIZE));
		return decodeCharstringValue(decodingContext, length * Byte.SIZE, decodingHypothesis);
	} // End of method decodeCharstringValue

	/**
	 * This method decodes a IntegerValue from a ByteArray representation at a global bit position
	 * Note that in this case, the global bit position is not byte aligned
	 *
	 * @param decodingHypothesis The requested type
	 * @param decodingContext The complete encoded message as received at a system port.
	 *
	 * @return An <code>IntegerValue</code> representing the decoded value
	 * 
	 * @see _theByte
	 */
	protected int decodeUnalignedIntegerValue(DecodingContext decodingContext, final int decodingLength) {
		_logger.entering(this.toString(), "decodeUnalignedIntegerValue", String.format("%d", decodingLength));

		BitstringValue bitValue = decodeBitstringValue(decodingContext, decodingLength);
		int value = 0;
		for (int i = 0; i < bitValue.getLength(); i++) {
			value = (value << 1) | bitValue.getBit(i);
		} // End of 'for' statement

		_logger.exiting(this.toString(), "decodeUnalignedIntegerValue", String.format("value:%08x", value));
		return value;
	} // End of method decodeUnalignedIntegerValue

	/**
	 * This method decodes a IntegerValue from a ByteArray representation at a global bit position
	 *
	 * @param decodingHypothesis The requested type
	 * @param decodingContext The complete encoded message as received at a system port.
	 *
	 * @return An <code>IntegerValue</code> representing the decoded value
	 */
	protected IntegerValue decodeIntegerValue(final Type decodingHypothesis, DecodingContext decodingContext) throws InstantiationException, IllegalAccessException {
		_logger.entering(this.toString(), "decodeIntegerValue", decodingHypothesis.getTypeEncodingVariant());

		IntegerValue value = (IntegerValue)decodingHypothesis.newInstance();

		// Extract the length
		if (value.getValueEncodingVariant() != null) {
			Matcher matcher = ItsCodecImpl.PatternVariantEncoding.matcher(value.getValueEncodingVariant());
			if (matcher.find()) {
				// Convert the integer value into byte array
				int length = Integer.parseInt(matcher.group(3));// Integer.parseInt(intValue.getValueEncodingVariant().split("\\s+")[1]); // Integer length in bits
				switch (length) {
					case 32:
						//No break;
					case 16:
						//No break;
					case 8: {
							if (!decodingContext.isPositionAligned()) {
								value.setInt(decodeUnalignedIntegerValue(decodingContext, length));
							} else {
								int intValue = decodeIntegerValue(decodingContext, length).getInt();
								if ((matcher.group(2) != null) && matcher.group(2).equals("unsigned")) {
									try {
										value.setBigInt(new BigInteger(1, ByteHelper.intToByteArray(intValue, length / 8)));
									} catch (de.tu_berlin.cs.uebb.muttcn.runtime.InvalidAssignmentError e) { 
										// Mismatch on constraint 
										_logger.severe(e.getMessage());
										throw(e);
									}
								} else {
									value.setInt(intValue);
								}
							}
						}
						break;
					default:
						value.setInt(decodeUnalignedIntegerValue(decodingContext, length));
						break;
				} // End of 'switch' statement
			} else {
				throw new RuntimeException(String.format("Failed to decode encoding variant value: %s", value.getValueEncodingVariant()));
			}
		} else { // Use default integer decoder
			value.setInt(decodeIntegerValue(decodingContext).getInt()); // Format is 32 bits integer
		}

		_logger.exiting(this.toString(), "decodeOctetstringValue", String.format("value: 0x%08x", value.getInt()));
		return value;
	} // End of method decodeIntegerValue

	/**
	 * This method decodes an OctetstringValue from a ByteArray representation at a global bit position
	 *
	 * @param decodingHypothesis The requested type
	 * @param decodingContext The complete encoded message as received at a system port.
	 *
	 * @return An <code>OctetstringValue</code> representing the decoded value
	 */
	public OctetstringValue decodeOctetstringValue(final Type decodingHypothesis, DecodingContext decodingContext) {
		_logger.entering(this.toString(), "decodeOctetstringValue", decodingHypothesis.getTypeEncodingVariant());

		OctetstringValue value = (OctetstringValue)decodingHypothesis.newInstance();

		_logger.info(String.format("Encoding: %s - %s", value.getValueEncodingVariant(), value.getValueEncoding()));
		// Extract the length
		int length = 0;
		if (value.getValueEncodingVariant() != null) {
			Matcher matcher = ItsCodecImpl.PatternVariantEncoding.matcher(value.getValueEncodingVariant());
			if (matcher.find()) {
				// Convert the integer value into byte array
				length = Integer.parseInt(matcher.group(3));
			} else { // Ignore it
				if (value.getValueEncoding() != null) {
					matcher = ItsCodecImpl.PatternEncoding.matcher(value.getValueEncoding());
					if (matcher.find()) {
						length = Integer.parseInt(matcher.group(1)) * 8; // Length is in bytes
					} else {
						throw new RuntimeException(String.format("Invalid value encoding: %s", value.getValueEncoding()));
					}
				} else {
					throw new RuntimeException("Variant values are null (1)");
				}
			}
		} else if (value.getValueEncoding() != null) {
			Matcher matcher = ItsCodecImpl.PatternEncoding.matcher(value.getValueEncoding());
			if (matcher.find()) {
				length = Integer.parseInt(matcher.group(1)) * 8; // Length is in bytes
			} else { // Try with decodingHypothesis type encoding
				matcher = ItsCodecImpl.PatternEncoding.matcher(decodingHypothesis.getTypeEncoding());
				if (matcher.find()) {
					length = Integer.parseInt(matcher.group(2)) * 8; // Length is in bytes
				} else { 
					throw new RuntimeException(String.format("Invalid value encoding: %s - %s", value.getValueEncoding(), decodingHypothesis.getTypeEncoding()));
				}
			}
		} else {
			throw new RuntimeException("Variant values are null (2)");
		}
		value = decodeOctetstringValue(decodingContext, length);

		_logger.exiting(this.toString(), "decodeOctetstringValue", String.format("%s", value.getString()));
		return value;
	} // End of method decodeOctetstringValue

	/** This method encodes a BitstringValue in a ByteArray representation at a global bit position
	 *
	 * @param encodingContext The EncodingContext collect the ByteArray
	 * @param fieldName Name of the field to be encoded
	 * @param bitstringValue The <code>IntegerValue</code> to encode
	 */
	public void encodeBitstringValue(EncodingContext encodingContext, final String fieldName, final BitstringValue bitstringValue) {
		_logger.entering(this.toString(), "encodeBitstringValue", String.format("<%s> - %s - %s - %s", bitstringValue.getString(), fieldName, bitstringValue.getType().getName(), bitstringValue.getValueEncoding()));

		try {
			encodingContext.setByte(TestAdapterMessageTypeEnum.convert(fieldName));
		} catch (IOException e) {
			e.printStackTrace();
		} // Type
		EncodingContext out_iv = new EncodingContext();
		super.encodeBitstringValue(out_iv, bitstringValue);
		try {
			encodingContext.setBytes((byte[])ByteHelper.intToByteArray(out_iv.size(), LengthFieldSize));
		} catch (IOException e) {
			e.printStackTrace();
		} // Length
		if (out_iv.size() != 0) { // Value
			try {
				encodingContext.setBytes(out_iv.toByteArray());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

//		if (_logger.isLoggable(Level.ALL)) ByteHelper.dump("encodeBitstringValue: ", encodingContext.toByteArray());
	} // End of method encodeBitstringValue

	/** This method encodes an BooleanValue in a ByteArray representation at a global bit position
	 *
	 * Note that:
	 * - true -> 0x01
	 * - false -> 0x00
	 *
	 * @param encodingContext The EncodingContext collect the ByteArray
	 * @param fieldName Name of the field to be encoded
	 * @param boolValue The <code>BooleanValue</code> to encode
	 */
	public void encodeBooleanValue(EncodingContext encodingContext, final String fieldName, final BooleanValue boolValue) {
		_logger.entering(this.toString(), "encodeBooleanValue", String.format("%s - %s - %s", fieldName, boolValue.getType().getName(), boolValue.getValueEncoding()));

		try {
			encodingContext.setByte(TestAdapterMessageTypeEnum.convert(fieldName));
		} catch (IOException e) {
			e.printStackTrace();
		} // Type
		EncodingContext out_iv = new EncodingContext();
		super.encodeBooleanValue(out_iv, boolValue);
		try {
			encodingContext.setBytes((byte[])ByteHelper.intToByteArray(out_iv.size(), LengthFieldSize));
		} catch (IOException e1) {
			e1.printStackTrace();
		} // Length
		if (out_iv.size() != 0) { // Value
			try {
				encodingContext.setBytes(out_iv.toByteArray());
			} catch (IOException e2) {
				e2.printStackTrace();
			}
		}

//		if (_logger.isLoggable(Level.ALL)) ByteHelper.dump("encodeBooleanValue: ", encodingContext.toByteArray());
	} // End of method encodeBooleanValue

	/**
	 * This method encodes a CharstringValue in a ByteArray representation at a global position bitpos. 
	 *
	 * @param encodingContext The EncodingContext collect the generated ByteArray.
	 * @param fieldName Name of the field to be encoded
	 * @param charstringValue The <code>CharstringValue</code> to encode
	 */
	public void encodeCharstringValue(EncodingContext encodingContext, final String fieldName, final CharstringValue charstringValue) {
		_logger.entering(this.toString(), "encodeCharstringValue", String.format("<%s> %s - %s - %s", charstringValue.getString(), fieldName, charstringValue.getType().getName(), (charstringValue.notPresent() == true) ? "not present" : "present"));

		if ((charstringValue == null) || charstringValue.notPresent()) {
			return;
		}

		try {
			encodingContext.setByte(TestAdapterMessageTypeEnum.convert(fieldName));
		} catch (IOException e) {
			e.printStackTrace();
		} // Type
		EncodingContext out_iv = new EncodingContext();
		encodeCharstringValue(out_iv, charstringValue);
		try {
			encodingContext.setBytes((byte[])ByteHelper.intToByteArray(out_iv.size(), LengthFieldSize));
		} catch (IOException e1) {
			e1.printStackTrace();
		} // Length
		if (out_iv.size() != 0) { // Value
			try {
				encodingContext.setBytes(out_iv.toByteArray());
			} catch (IOException e2) {
				e2.printStackTrace();
			}
		}

//		if (_logger.isLoggable(Level.ALL)) ByteHelper.dump("ItsCodecImpl.encodeCharstringValue: ", encodingContext.toByteArray());
	} // End of method encodeCharstringValue

	/**
	 * This method encodes a CharstringValue in a ByteArray representation at a global position bitpos. 
	 *
	 * @param encodingContext The EncodingContext collect the generated ByteArray.
	 * @param charstringValue The <code>CharstringValue</code> to encode
	 */
	@Override
	public void encodeCharstringValue(EncodingContext encodingContext, final CharstringValue charstringValue) {
		_logger.entering(this.toString(), "encodeCharstringValue", String.format("<%s> %s - %s", charstringValue.getString(), charstringValue.getType().getName(), (charstringValue.notPresent() == true) ? "not present" : "present"));

		if ((charstringValue == null) || charstringValue.notPresent()) {
			return;
		}

		try {
			// Write length first
			encodingContext.setBytes(ByteHelper.intToByteArray(charstringValue.getString().getBytes().length, Integer.SIZE / Byte.SIZE));
			// Write string
			byte[] buffer = charstringValue.getString().getBytes();
			encodingContext.setBytes(buffer);
		} catch (IOException e) {
			e.printStackTrace();
		}

//		if (_logger.isLoggable(Level.ALL)) ByteHelper.dump("ItsCodecImpl.encodeCharstringValue: ", encodingContext.toByteArray());
	} // End of method encodeCharstringValue
	
	/** 
	 * This method encodes an IntegerValue in a ByteArray representation at a global bit position
	 *
	 * @param encodingContext The EncodingContext collect the ByteArray
	 * @param fieldName Name of the field to be encoded
	 * @param intValue The <code>IntegerValue</code> to encode
	 */
	public void encodeIntegerValue(EncodingContext encodingContext, final String fieldName, final IntegerValue intValue) {
		_logger.entering(this.toString(), "encodeIntegerValue", String.format("<%d - %d> - %s - %s - %s", intValue.getInt(), intValue.getBigInt().longValue(), fieldName, intValue.getType().getName(), intValue.getValueEncoding()));

		try {
			encodingContext.setByte(TestAdapterMessageTypeEnum.convert(fieldName));
		} catch (IOException e) {
			e.printStackTrace();
		} // Type
		EncodingContext out_iv = new EncodingContext();
		encodeIntegerValue(out_iv, intValue);
		try {
			encodingContext.setBytes((byte[])ByteHelper.intToByteArray(out_iv.size(), LengthFieldSize));
		} catch (IOException e1) {
			e1.printStackTrace();
		} // Length
		if (out_iv.size() != 0) { // Value
			try {
				encodingContext.setBytes(out_iv.toByteArray());
			} catch (IOException e2) {
				e2.printStackTrace();
			}
		}

//		if (_logger.isLoggable(Level.ALL)) ByteHelper.dump("encodeIntegerValue: ", encodingContext.toByteArray());
	} // End of method encodeIntegerValue

	/**
	 * This method encodes an IntegerValue in a ByteArray representation at a global position <code>_bitpos</code>
	 * 
	 * @param encodingContext The EncodingContext collect the generated ByteArray
	 * @param intValue The <code>IntegerValue</code> to encode
	 */
	public void encodeIntegerValue(EncodingContext encodingContext, final IntegerValue intValue) {
		_logger.entering(this.toString(), "encodeIntegerValue", String.format("%s - %s", intValue.getType().getName(), (intValue.notPresent() == true) ? "not present" : "present"));

		if ((intValue == null) || intValue.notPresent()) {
			return;
		}

		_logger.info(String.format("Integer value=<%d> - <%s> - <%s>", intValue.getInt(), intValue.getValueEncoding(), intValue.getValueEncodingVariant()));
		if (intValue.getValueEncoding() == "MarkForUpdate") {
			encodingContext.markForUpdate();
		}
		if (intValue.getValueEncoding() == "MarkForNextHeader") { 
			encodingContext.markForNextHeader();
		}

		if (intValue.getValueEncodingVariant() != null) {
			_logger.info(String.format("Encoding type: %s", intValue.getValueEncodingVariant()));
			// Extract the length
			Matcher matcher = ItsCodecImpl.PatternVariantEncoding.matcher(intValue.getValueEncodingVariant());
			if (matcher.find()) {
				// Convert the integer value into byte array
				int length = Integer.parseInt(matcher.group(3));// Integer.parseInt(intValue.getValueEncodingVariant().split("\\s+")[1]); // Integer length in bits
				if (((length % 8) == 0) && encodingContext.isPositionAligned()) {
					int quot = length / 8;
					int rem = length % 8;
					byte [] encoded = new byte [quot + (int)((rem == 0) ? 0 : 1)];
					for (int i = 0; i < quot; i += 1) {
						encoded[encoded.length - i - 1] = (byte)((intValue.getInt() & (int)(0xff << 8 * i)) >> 8 * i);
					}
					if (rem != 0) {
						encoded[0] = (byte)((intValue.getInt() & (int)(0xff << 8 * quot)) >> 8 * quot);
						byte mask = (byte)((int)java.lang.Math.pow(2, rem) - 1);
						encoded[0] = (byte)(encoded[0] & mask);
					}
					// Fill 'encodingContext' buffer
					try {
						encodingContext.setBytes(encoded); // Value
						
//						if (_logger.isLoggable(Level.ALL)) ByteHelper.dump("ItsCodecImpl.encodeIntegerValue: ", encodingContext.toByteArray());
						return; // Encoding with variant succeeded
					} catch (IOException e) {
						e.printStackTrace();
					}
				} else { // Not aligned integer, process it as bitstring !
					StringBuffer bv = new StringBuffer();
					bv.append('\''); // Use bitstring format '1100'B
					int value = intValue.getInt() << (Integer.SIZE - length);
					for (int i = 0; i < length; i++) {
						bv.append((char)(((value & 0x80000000) == 0x80000000) ? '1' : '0'));
						value <<= 1;
					} // End of 'for' statement
					bv.append("'B");
					encodingContext.setBitString(bv.toString());
					//if (_logger.isLoggable(Level.ALL)) ByteHelper.dump("ItsCodecImpl.encodeIntegerValue: ", encodingContext.toByteArray());

					return;
				}
			}
		}
		// Here, variant format is unknown, use default encoding
		super.encodeIntegerValue(encodingContext, intValue); // Format is 32 bits integer

//		if (_logger.isLoggable(Level.ALL)) ByteHelper.dump("ItsCodecImpl.encodeIntegerValue: ", encodingContext.toByteArray());
	} // End of method encodeIntegerValue
	
	@Override
	public void encodeOctetstringValue(EncodingContext encodingContext, final OctetstringValue ov) {
		if ((ov == null) || ov.notPresent()) {
			return;
		}
		
		if (((TciValueTemplate)ov).isAnyOrOmit() || ((TciValueTemplate) ov).isAny()) {
			throw new RuntimeException("BasicCodecImpl.encodeOctetstringValue: Can't send wildcard " + ov.getType().getName());
		}
		
		_logger.info(String.format("Octetstring value=length<%d> - <%s> - <%s>", ov.getLength(), ov.getValueEncoding(), ov.getValueEncodingVariant()));
		String variant = ov.getValueEncodingVariant();
		if (variant != null) {
			if (variant == "MarkForIPv6SrcAddress") {
				encodingContext.markIPv6SrcAddress();
			} else if (variant == "MarkForIPv6DstAddress") {
				encodingContext.markIPv6DstAddress();
			} else if (variant == "MarkForIPv6ChecksumCalculation") {
				encodingContext.markForIPv6ChecksumCalculation();
			}
		}
		
		encodingContext.setOctetString(ov.getString());
	}

	/** 
	 * This method provides the codec associated to the specified encoding identifier
	 * 
	 * @param encodingName The name of the encoding, specified by the tTCN-3 key words 'with/encode'
	 * @return The codec associated to the specified encoding identifier
	 */
	@Override
	public TciCDProvided getCodec(final String encodingName) {
		_logger.entering(this.toString(), "getCodec", encodingName);
		return TCIWrapperFactory.getCodec(encodingName);
	}
	
} // End of abstract class ItsCodecImpl
