package com.radio.codec2talkie.protocol.aprs;

import com.radio.codec2talkie.protocol.message.TextMessage;
import com.radio.codec2talkie.protocol.position.Position;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AprsDataTextMessage implements AprsData {

    public String srcCallsign;
    public String dstCallsign;
    public String digipath;
    public String textMessage;
    public Integer ackId;

    private boolean _isValid;

    @Override
    public boolean isPositionReport() {
        return false;
    }

    @Override
    public boolean isTextMessage() {
        return true;
    }

    @Override
    public void fromPosition(Position position) {
        _isValid = false;
    }

    @Override
    public void fromTextMessage(TextMessage textMessage) {
        this.dstCallsign = textMessage.dst;
        this.textMessage = textMessage.text;
        this.digipath = textMessage.digipath;
        this.ackId = textMessage.ackId;
        _isValid = true;
    }

    @Override
    public Position toPosition() {
        return null;
    }

    @Override
    public TextMessage toTextMessage() {
        TextMessage textMessage = new TextMessage();
        textMessage.src = this.srcCallsign;
        textMessage.dst = this.dstCallsign;
        textMessage.digipath = this.digipath;
        textMessage.text = this.textMessage;
        textMessage.ackId = this.ackId;
        return textMessage;
    }

    @Override
    public void fromBinary(String srcCallsign, String dstCallsign, String digipath, byte[] infoData) {
        _isValid = false;
        if (infoData.length < 10) return;
        this.digipath = digipath;
        this.srcCallsign = srcCallsign;
        ByteBuffer buffer = ByteBuffer.wrap(infoData);

        // callsign, trim ending spaces
        byte[] callsign = new byte[9];
        buffer.get(callsign);
        this.dstCallsign = new String(callsign).replaceAll("\\s+$", "");

        // ':' separator
        byte b = buffer.get();
        if (b != ':') return;

        // message
        byte[] message = new byte[buffer.remaining()];
        buffer.get(message);
        String stringMessage = new String(message, StandardCharsets.UTF_8);

        // ack/rej message
        this.ackId = 0;
        Pattern p = Pattern.compile("^(ack|rej)(\n+){1,5}$", Pattern.DOTALL);
        Matcher m = p.matcher(stringMessage);
        if (m.find()) {
            String type = m.group(1);
            if (type != null) {
                String ackIdStr = m.group(2);
                if (ackIdStr != null)
                    this.ackId = Integer.parseInt(ackIdStr);
            }
        } else {
            // message requires acknowledge {xxxxx (for auto ack)
            p = Pattern.compile("^.+[{](\\d+){1,5}$", Pattern.DOTALL);
            m = p.matcher(stringMessage);
            if (m.find()) {
                this.textMessage = m.group(1);
                String ackNumStr = m.group(2);
                if (ackNumStr != null)
                    this.ackId = Integer.parseInt(ackNumStr);
            } else {
                this.textMessage = stringMessage;
            }
        }

        // TODO, telemetry, make subclass from message, extend and extract values
        if (this.textMessage != null)
            _isValid = !isTelemetry(this.textMessage);
    }

    @Override
    public byte[] toBinary() {
        return (ackId > 0)
                ? String.format(Locale.US, ":%-9s:%s{%d", dstCallsign, textMessage, ackId).getBytes()
                : String.format(":%-9s:%s", dstCallsign, textMessage).getBytes();
    }

    @Override
    public boolean isValid() {
        return _isValid;
    }

    private boolean isTelemetry(String textMessage) {
        Pattern p = Pattern.compile("^(EQNS|PARM|UNIT|BITS)[.].+$", Pattern.DOTALL);
        Matcher m = p.matcher(textMessage);
        return m.matches();
    }
}
