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

import java.util.Map;
import java.util.TreeMap;

import org.etsi.ttcn.tri.TriMessage;
import org.etsi.ttcn.tci.TciCDProvided;
import org.etsi.ttcn.tci.TciCDRequired;
import org.etsi.ttcn.tci.Type;
import org.etsi.ttcn.tci.Value;

public class MainCodec extends ICodec {

    public MainCodec(TciCDRequired cdReq) {
        super(null);
        this.cdReq = cdReq;
    }

    public Value triDecode(TriMessage message, Type decodingHypothesis) {
        return decode(new CodecBuffer(message.getEncodedMessage()), decodingHypothesis);
    }

    public TriMessage triEncode(Value value) {
        CodecBuffer encoded = encode(value);
        encoded.runCallbacks();
        return new TriMessageImpl(encoded.getBytes());
    }

    @Override
    public Value decode(CodecBuffer buf, Type decodingHypothesis) {
        
        CodecFactory cf = CodecFactory.getInstance();
        TciCDProvided extCodec = cf.getExternalCodec(decodingHypothesis.getTypeEncoding());
        if(extCodec != null) {
            try {
                return extCodec.decode(new TriMessageImpl(buf.getBytes()), decodingHypothesis);
            }
            catch(Exception e) {
                return null;
            }            
        }
        else {
            ICodec codec = cf.getCodec(
                    this,
                    decodingHypothesis.getTypeClass(),
                    decodingHypothesis.getTypeEncoding(),
                    decodingHypothesis.getName()
                    );
            codec.preDecode(buf, decodingHypothesis);
            return codec.decode(buf, decodingHypothesis);
        }
    }

    @Override
    public CodecBuffer encode(Value value) {

        CodecFactory cf = CodecFactory.getInstance();
        TciCDProvided extCodec = cf.getExternalCodec(value.getValueEncoding());
        if(extCodec != null) {
            return new CodecBuffer(extCodec.encode(value).getEncodedMessage());            
        }
        else {
            ICodec codec = CodecFactory.getInstance().getCodec(
                    this,
                    value.getType().getTypeClass(),
                    value.getValueEncoding(),
                    value.getType().getName()
                    );
            CodecBuffer preBuf = codec.preEncode(value);
            CodecBuffer buf = codec.encode(value);
            if(preBuf != null) {
                preBuf.append(buf);
                buf = preBuf;
            }
            return buf;
        }
    }

    public String getHint(String key) {
        return hints.get(key);
    }

    public void setHint(String key, String value) {
        hints.put(key, value);
    }

    public java.lang.Boolean getPresenceHint(String key) {
        return presenceHints.get(key);
    }

    public void setPresenceHint(String key, java.lang.Boolean value) {
        presenceHints.put(key, value);
    }

    public TciCDRequired getTciCDRequired() {
        return cdReq;
    }

    protected Map<String, String> hints = new TreeMap<String, String>();
    protected Map<String, java.lang.Boolean> presenceHints = new TreeMap<String, java.lang.Boolean>();
    protected TciCDRequired cdReq;
}
