package com.its.dsrc.xnettcp.dsrc.process.service.impl;

import com.beanit.asn1bean.ber.types.BerBoolean;
import com.beanit.asn1bean.ber.types.BerInteger;
import com.beanit.asn1bean.ber.types.BerOctetString;
import com.beanit.asn1dsrc.dsrc.*;
import com.beanit.asn1dsrc.enums.eAuthInfo;
import com.beanit.asn1dsrc.enums.eControlDevice;
import com.beanit.asn1dsrc.enums.eControlRequest;
import com.beanit.asn1dsrc.enums.eObjectId;
import com.beanit.asn1dsrc.util.DsrcAsn1Utils;
import com.its.app.utils.NettyUtils;
import com.its.dsrc.entity.TbRseCtlr;
import com.its.dsrc.xnettcp.dsrc.process.service.ControlDeviceService;
import com.its.dsrc.xnettcp.dsrc.process.service.SubscriptionService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayInputStream;
import java.util.List;

@Slf4j
public class SubscriptionSingleService implements SubscriptionService {
    private static SubscriptionSingleService _instance = null;

    public static SubscriptionSingleService getInstance() {
        if (_instance == null) {
            synchronized (SubscriptionSingleService.class) {
                if (_instance == null)
                    _instance = new SubscriptionSingleService();
            }
        }
        return _instance;
    }

    public SubscriptionSingleService() {
    }

    @Override
    public boolean response(TbRseCtlr obj, Channel channel, int objectId, Subscription subscription) {
        /*
        *  SubscriptionResponse 에서 호출
         */
        String ipAddress = NettyUtils.getRemoteIpAddress(channel);
        log.info("SubscriptionSingleService.response: {}. SubscriptionSingleService: ObjectId: {}, Subscription: {}", ipAddress, objectId, subscription.toString());

        if (objectId != eObjectId.OBJ_ControlDevice.getValue()) {
            log.error("{}. SubscriptionSingleService.response: unknown ObjectId: {}, Subscription: {}", ipAddress, objectId, subscription.toString());
            return false;
        }

        boolean isMultimedia = false;
        Publication publication = null;
        int serialNmbr = subscription.getDatexSubscribeSerialNbr().value.intValue();
        byte[] auth = { (byte) eAuthInfo.AI_NonCryptObu.getValue() };

        try {
            SubscriptionData subscriptionData = subscription.getDatexSubscribeType().getSubscription();
            ControlDeviceList list = new ControlDeviceList();
            byte[] inBytes = subscriptionData.getDatexSubscribePdu().getEndApplicationMessageMsg().value;
            list.decode(new ByteArrayInputStream(inBytes, 0, inBytes.length));
            List<ControlDevice> objs = list.getControlDevice();
            for (ControlDevice device : objs) {
                eControlDevice requestType = eControlDevice.getByValue(device.getVpbdControlID().value[0]);
                if (requestType == null || requestType.getValue() != eControlDevice.Control_InfoRequest.getValue())
                    continue;

                try {
                    DSRCTrafficInfoRequest request = new DSRCTrafficInfoRequest();
                    byte[] datas = device.getVpbdControlDeviceData().value;
                    request.decode(new ByteArrayInputStream(datas, 0, datas.length));
                    eControlRequest queryType = eControlRequest.getByValue(request.getQueryType().value.intValue());
                    ControlDevice resDevice = ControlDeviceService.getInstance().makeControlDevice_BasicBaseInfo(obj, queryType);
                    EndApplicationMessage endMsg = ControlDeviceService.getInstance().makeEndApplicationMessage(obj, resDevice);
                    if (endMsg == null) {
                        log.error("{}. SubscriptionSingleService: EndApplicationMessage error, DSRCTrafficInfoRequest: {}", ipAddress, request.toString());
                        continue;
                    }

                    PublicationType publicationType = new PublicationType();
                    publicationType.setDatexPublishData(endMsg);

                    PublicationData publicationData = new PublicationData();
                    publicationData.setDatexPublishSubscribeSerialNbr(new BerInteger(serialNmbr));          // 요청 serial nmbr
                    publicationData.setDatexPublishSerialNbr(new BerInteger(obj.getSeq().nextValue()));     // 생성 serial nmbr
                    publicationData.setDatexPublishLatePublicationFlag(new BerBoolean(true));
                    publicationData.setDatexPublishType(publicationType);

                    PublishFormat.DatexPublishData publishData = new PublishFormat.DatexPublishData();
                    publishData.getPublicationData().add(publicationData);

                    PublishFormat publishFormat = new PublishFormat();
                    publishFormat.setDatexPublishData(publishData);

                    publication = new Publication();
                    publication.setDatexPublishFormat(publishFormat);
                    publication.setDatexPublishGuaranteedBool(new BerBoolean(true));
                    if (queryType.getValue() == eControlRequest.Request_MulticastInfo.getValue()) {
                        auth[0] = (byte)eAuthInfo.AI_Multimedia.getValue();
                        isMultimedia = true;
                    }
                }
                catch (Exception e) {
                    log.error("{}. SubscriptionSingleService: SubscriptionData: {}, ControlDevice: {}, Exception: {}", ipAddress, subscriptionData.toString(),  device.toString(), e);
                }
            }
        } catch (Exception e) {
            log.error("{}. SubscriptionSingleService: Subscription: {}, Exception: {}", ipAddress, subscription.toString(), e);
        }
        if (publication == null) {
            return false;
        }

        int packetNmbr = obj.getSeq().nextValue();
        C2CAuthenticatedMessage c2c = new C2CAuthenticatedMessage();
        PDUs pdus = new PDUs();
        pdus.setPublication(publication);
        c2c.setDatexDataPacketNumber(new BerInteger(packetNmbr));
        c2c.setDatexDataPacketPriorityNumber(new BerInteger(0));
        c2c.setDatexAuthenticationInfoText(new BerOctetString(auth));
        c2c.setOptions(DsrcAsn1Utils.swapHeaderOptions(obj.getHeaderOptions()));
        c2c.setPdu(pdus);

        log.info("SubscriptionSingleService: {}, C2CAuth: {}", obj.getID(), c2c);

        ChannelFuture f = channel.writeAndFlush(c2c);
        if (f.isSuccess()) {
            obj.putRegisteredCommands(c2c);
        } else {
            log.error("SubscriptionSingleService: {}, Exception: {}", obj.getID(), c2c);
        }

        if (isMultimedia) {
            // TODO: Multimedia 정보 내려보낸 내용을 이력으로 저장한다.
            //DsrcAsn1ServerDataProcess dsrcAsn1ServerDataProcess  = (DsrcAsn1ServerDataProcess) BeanUtils.getBean(DsrcAsn1ServerDataProcess.class);
            //dsrcAsn1ServerDataProcess.add(new DsrcAsn1ServerData(DsrcAsn1ServerData.DATA_TYPE_MULTIMEDIA_HS, obj, null, (Object) command));
        }
        return true;
    }

}
