package com.nokia.sms.sgip.codec;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;

import com.nokia.sms.sgip.exception.ReadErrorException;
import com.nokia.sms.sgip.message.BindMessage;
import com.nokia.sms.sgip.message.BindResponseMessage;
import com.nokia.sms.sgip.message.DeliverMessage;
import com.nokia.sms.sgip.message.DeliverResponseMessage;
import com.nokia.sms.sgip.message.Head;
import com.nokia.sms.sgip.message.ReportMessage;
import com.nokia.sms.sgip.message.ReportResponseMessage;
import com.nokia.sms.sgip.message.SgipMessage;
import com.nokia.sms.sgip.message.SubmitMessage;
import com.nokia.sms.sgip.message.SubmitResponseMessage;
import com.nokia.sms.sgip.message.UnBindMessage;
import com.nokia.sms.sgip.message.UnBindResponseMessage;
import com.nokia.sms.sgip.message.UnknowMessage;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SgipMessageDecoder extends CumulativeProtocolDecoder {
    protected boolean doDecode(IoSession session, IoBuffer buffer, ProtocolDecoderOutput out)
            throws Exception {
        int oldPosition = buffer.position();

        int msgLen = buffer.getInt();
        if (buffer.remaining() >= msgLen - 4) {
            buffer.position(oldPosition);
            Head head = new Head();
            head.parse(buffer);
            SgipMessage message = null;
            switch (head.getCommandId()) {
                case 1:
                    message = new BindMessage();
                    break;
                case -2147483647:
                    message = new BindResponseMessage();
                    break;
                case 3:
                    message = new SubmitMessage();
                    break;
                case -2147483645:
                    message = new SubmitResponseMessage();
                    break;
                case 4:
                    message = new DeliverMessage();
                    break;
                case -2147483644:
                    message = new DeliverResponseMessage();
                    break;
                case 5:
                    message = new ReportMessage();
                    break;
                case -2147483643:
                    message = new ReportResponseMessage();
                    break;
                case 2:
                    message = new UnBindMessage();
                    break;
                case -2147483646:
                    message = new UnBindResponseMessage();
                    break;
                default:
                    message = new UnknowMessage();
                    byte count = ((Byte) session.getAttribute("readErrorCount")).byteValue();
                    count = (byte) (count + 1);
                    if (count >= 2) {
                        throw new ReadErrorException(
                                "MessageLength=" + msgLen + ",buffer.remaining=" + buffer.remaining());
                    }
                    count = (byte) (count + 1);
                    session.setAttribute("readErrorCount", Byte.valueOf(count));
            }
            message.parse(head, buffer);
            out.write(message);
            session.setAttribute("readErrorCount", Byte.valueOf((byte) 0));
            return true;
        }
        buffer.position(oldPosition);
        log.warn("MessageLength=" + msgLen + ",buffer.remaining=" + buffer.remaining() + ",HexDump="
                + buffer.getHexDump());
        buffer.position(oldPosition);
        byte count = ((Byte) session.getAttribute("readErrorCount")).byteValue();
        count = (byte) (count + 1);
        if (count >= 2) {
            throw new ReadErrorException("MessageLength=" + msgLen + ",buffer.remaining=" + buffer.remaining());
        }
        count = (byte) (count + 1);
        session.setAttribute("readErrorCount", Byte.valueOf(count));
        return false;
    }
}
