package com.alterdekim.hearthhack.component.processor;


import com.alterdekim.Protocol;
import com.alterdekim.hearthhack.component.TcpConnection;
import com.alterdekim.hearthhack.util.*;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import lombok.extern.slf4j.Slf4j;

import java.util.Optional;


@Slf4j
public class GameUtilitiesProcessor extends Processor {

    public GameUtilitiesProcessor() {
        this.setProcessorId(9);
    }

    private ClientRequestBody parseClientRequest(Protocol.ClientRequest request) {
        Optional<Protocol.Attribute> at = request.getAttributeList()
                .stream()
                .filter(a -> a.hasName() && a.getName().equals("p"))
                .findFirst();
        if( !at.isPresent() ) return null;
        byte[] b = at.get().getValue().getBlobValue().toByteArray();
        ClientRequestBody requestBody = null;
        try {
            requestBody = ClientRequestManager.GetUtilPacketFromBytes(b);
        } catch (InvalidProtocolBufferException e) {
            log.error(e.getMessage());
        }
        return requestBody;
    }

    private void parseRequestNetCacheObject(int token, ClientRequestBody body, TcpConnection conn) throws InvalidProtocolBufferException {
        parseGenericRequest(token, Protocol.UtilGenericRequest.parseFrom(body.getBody()), conn);
    }

    private void processProfileProgress( int token, TcpConnection conn ) throws Exception {
        // ProfileProgress
        byte[] b = Util.hexStringToByteArray("0A090A026964120318C6020A100A0570726F746F12073205080110C702");
        Protocol.Header header = Processor.generateResponse(b.length, token, 0, 0);
        conn.send(new BattleNetPacket(header, b));

        Protocol.GenericResponse gr = Protocol.GenericResponse.newBuilder()
                .setRequestId(201)
                .setRequestSubId(11)
                .setResultCode(Protocol.GenericResponse.Result.RESULT_REQUEST_IN_PROCESS)
                .build();

        Protocol.Notification n = generateNotification(326, gr.toByteString(), gr.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));

        Protocol.ProfileProgress profileProgress = Protocol.ProfileProgress.newBuilder()
                .setProgress(6)
                .setBestForge(0)
                .build();

        n = generateNotification(233, profileProgress.toByteString(), profileProgress.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));
    }

    private void processGoldBalance( TcpConnection conn ) throws Exception {
        Protocol.GoldBalance gb = Protocol.GoldBalance.newBuilder()
                .setCap(999999)
                .setBonusBalance(165)
                .setCappedBalance(160)
                .setCapWarning(2000)
                .build();

        byte[] b = generateNotification(278, gb.toByteString(), gb.getSerializedSize()).toByteArray();

        Protocol.Header header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(b.length)
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, b));
        
    }

    private void processDeckList(int token, TcpConnection conn) throws Exception {
        byte[] b = Util.hexStringToByteArray("0A090A026964120318C6020A100A0570726F746F12073205080110C702");
        Protocol.Header header = Processor.generateResponse(b.length, token, 0, 0);
        conn.send(new BattleNetPacket(header, b));

        Protocol.GenericResponse gr = Protocol.GenericResponse.newBuilder()
                .setRequestId(237)
                .setResultCode(Protocol.GenericResponse.Result.RESULT_REQUEST_IN_PROCESS)
                .build();

        Protocol.Notification n = generateNotification(326, gr.toByteString(), gr.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));

        gr = Protocol.GenericResponse.newBuilder()
                .setRequestId(201)
                .setResultCode(Protocol.GenericResponse.Result.RESULT_REQUEST_IN_PROCESS)
                .setRequestSubId(2)
                .build();

        n = generateNotification(326, gr.toByteString(), gr.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));

        gr = Protocol.GenericResponse.newBuilder()
                .setRequestId(201)
                .setResultCode(Protocol.GenericResponse.Result.RESULT_REQUEST_IN_PROCESS)
                .setRequestSubId(3)
                .build();

        n = generateNotification(326, gr.toByteString(), gr.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));

        gr = Protocol.GenericResponse.newBuilder()
                .setRequestId(201)
                .setResultCode(Protocol.GenericResponse.Result.RESULT_REQUEST_IN_PROCESS)
                .setRequestSubId(15)
                .build();

        n = generateNotification(326, gr.toByteString(), gr.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));

        Protocol.DeckList deckList = Protocol.DeckList.newBuilder()
                .addDecks(Protocol.DeckInfo.newBuilder()
                        .setId(794851023L)
                        .setName("The Fuck")
                        .setCardBack(0)
                        .setHero(637)
                        .setDeckType(Protocol.DeckType.NORMAL_DECK)
                        .setValidity(767L)
                        .setHeroPremium(0)
                        .setCardBackOverride(false)
                        .setHeroOverride(false)
                        .setLastModified(1461490210L)
                        .setSortOrder(1461490210L)
                        .setSourceType(Protocol.DeckSourceType.DECK_SOURCE_TYPE_BASIC_DECK))
                .addDecks(Protocol.DeckInfo.newBuilder()
                        .setId(794938262L)
                        .setName("The Cock")
                        .setCardBack(0)
                        .setHero(31)
                        .setDeckType(Protocol.DeckType.NORMAL_DECK)
                        .setValidity(767L)
                        .setHeroPremium(0)
                        .setCardBackOverride(false)
                        .setHeroOverride(false)
                        .setLastModified(1461490581L)
                        .setSortOrder(1461490581L)
                        .setSourceType(Protocol.DeckSourceType.DECK_SOURCE_TYPE_BASIC_DECK))
                .addDecks(Protocol.DeckInfo.newBuilder()
                        .setId(172325L)
                        .setName("precon")
                        .setCardBack(0)
                        .setHero(31)
                        .setDeckType(Protocol.DeckType.PRECON_DECK)
                        .setValidity(31L)
                        .setHeroPremium(0)
                        .setCardBackOverride(false)
                        .setHeroOverride(false)
                        .setSortOrder(0L)
                        .setSourceType(Protocol.DeckSourceType.DECK_SOURCE_TYPE_UNKNOWN))
                .addDecks(Protocol.DeckInfo.newBuilder()
                        .setId(171593L)
                        .setName("precon")
                        .setCardBack(0)
                        .setHero(637)
                        .setDeckType(Protocol.DeckType.PRECON_DECK)
                        .setValidity(31L)
                        .setHeroPremium(0)
                        .setCardBackOverride(false)
                        .setHeroOverride(false)
                        .setSortOrder(0L)
                        .setSourceType(Protocol.DeckSourceType.DECK_SOURCE_TYPE_UNKNOWN))
                .build();

        n = generateNotification(202, deckList.toByteString(), deckList.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));
    }

    private void processBoosters(int token, TcpConnection conn) throws Exception {
        byte[] b = Util.hexStringToByteArray("0A090A026964120318C6020A100A0570726F746F12073205080110C702");
        Protocol.Header header = Processor.generateResponse(b.length, token, 0, 0);
        conn.send(new BattleNetPacket(header, b));

        Protocol.GenericResponse gr = Protocol.GenericResponse.newBuilder()
                .setRequestId(201)
                .setRequestSubId(17)
                .setResultCode(Protocol.GenericResponse.Result.RESULT_REQUEST_IN_PROCESS)
                .build();

        Protocol.Notification n = generateNotification(326, gr.toByteString(), gr.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));

        gr = Protocol.GenericResponse.newBuilder()
                .setRequestId(201)
                .setRequestSubId(14)
                .setResultCode(Protocol.GenericResponse.Result.RESULT_REQUEST_IN_PROCESS)
                .build();

        n = generateNotification(326, gr.toByteString(), gr.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));

        gr = Protocol.GenericResponse.newBuilder()
                .setRequestId(201)
                .setRequestSubId(6)
                .setResultCode(Protocol.GenericResponse.Result.RESULT_REQUEST_IN_PROCESS)
                .build();

        n = generateNotification(326, gr.toByteString(), gr.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));

        //Protocol.BoosterList boosterList = Protocol.BoosterList.newBuilder().build();

        n = generateNotification(224, ByteString.EMPTY, 0);

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));
    }

    private void processCollection(int token, TcpConnection conn) throws Exception {
       // Protocol.Collection collection = Protocol.Collection.newBuilder().build();

        Protocol.Notification n = generateNotification(207, ByteString.EMPTY, 0);

        Protocol.Header header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));
    }

    private void processMedalInfo(TcpConnection conn) throws Exception {
        Protocol.MedalInfo medalInfo = Protocol.MedalInfo.newBuilder()
                .setWild(Protocol.MedalInfoData.newBuilder()
                        .setSeasonWins(0)
                        .setStars(0)
                        .setStreak(0)
                        .setStarLevel(1)
                        .setLevelStart(1)
                        .setLevelEnd(3)
                        .setCanLoseLevel(false)
                        .setBestStarLevel(1)
                        .setCanLoseStars(false))
                .setStandard(Protocol.MedalInfoData.newBuilder()
                        .setSeasonWins(0)
                        .setStars(0)
                        .setStreak(0)
                        .setStarLevel(1)
                        .setLevelStart(1)
                        .setLevelEnd(3)
                        .setCanLoseLevel(false)
                        .setBestStarLevel(1)
                        .setCanLoseStars(false))
                .build();

        Protocol.Notification n = generateNotification(232, medalInfo.toByteString(), medalInfo.getSerializedSize());

        Protocol.Header header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));
    }

    private void processNotSoMassiveLoginReply(TcpConnection conn) throws Exception {
        Protocol.NotSoMassiveLoginReply reply = Protocol.NotSoMassiveLoginReply.newBuilder()
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("launch"))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("naxx_1")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("naxx_2")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("naxx_3")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("naxx_4")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("naxx_5")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("gvg_promote")
                        .setStart(1)
                        .setEnd(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("gvg_begin")
                        .setStart(1)
                        .setEnd(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("gvg_arena")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("brm_1")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("brm_2")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("brm_3")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("brm_4")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("brm_5")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("brm_pre_sale")
                        .setStart(1)
                        .setEnd(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("brm_normal_sale")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("tgt_pre_sale")
                        .setStart(1)
                        .setEnd(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("tgt_normal_sale")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("loe_1")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("loe_2")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("loe_3")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("loe_4")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("feast_of_winter_veil")
                        .setStart(1)
                        .setEnd(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("set_rotation_2016")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("og_pre_purchase")
                        .setStart(1)
                        .setEnd(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("og_normal_sale")
                        .setStart(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("apple_charity_promo_2016")
                        .setStart(1)
                        .setEnd(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("naxx_gvg_real_money_sale")
                        .setStart(1)
                        .setEnd(0))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("set_rotation_2016_freepacks")
                        .setStart(0)
                        .setEnd(5059030))
                .addSpecialEventTiming(Protocol.SpecialEventTiming.newBuilder()
                        .setEvent("set_rotation_2016_questline")
                        .setStart(0)
                        .setEnd(5059028))
                .setTavernBrawls(Protocol.TavernBrawlInfo.newBuilder()
                        .setNextStartSecondsFromNow(124398L))
                .build();

        Protocol.Notification n = generateNotification(300, reply.toByteString(), reply.getSerializedSize());

        Protocol.Header header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));
    }

    private void processCardValues(TcpConnection conn) throws Exception {

       // Protocol.CardValues cardVals = Protocol.CardValues.newBuilder().build();

        //Protocol.Notification n = generateNotification(260, medalInfo.toByteString(), medalInfo.getSerializedSize());

       /* Protocol.Header header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));*/

        byte[] b = Util.hexStringToByteArray("[encoded data, 45058 characters]");

        Protocol.Header header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(b.length)
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, b));
    }

    private void processRewardProgress(TcpConnection conn) {
        // Protocol.RewardProgress
        // Notification 271
    }

    private void parseGenericRequest(int token, Protocol.UtilGenericRequest genericRequest, TcpConnection conn) {
        // body = genericRequest.getGenericData().getData().toByteArray()
        GetAccountInfoRequest req = GetAccountInfoRequest.parseFromInt(genericRequest.getRequestSubId());
        try {
            switch (req) {
                case GOLD_BALANCE -> processGoldBalance(conn);
                case CAMPAIGN_INFO -> processProfileProgress(token, conn);
                case DECK_LIST -> processDeckList(token, conn);
                // case ARCANE_DUST_BALANCE; case CLIENT_OPTIONS;
                case CARD_VALUES -> processCardValues(conn);
                case COLLECTION -> processCollection(token, conn);
                case BOOSTERS -> processBoosters(token, conn);
                case MEDAL_INFO -> processMedalInfo(conn);
                case NOT_SO_MASSIVE_LOGIN -> processNotSoMassiveLoginReply(conn);
                case REWARD_PROGRESS -> processRewardProgress(conn);
                default -> log.warn("Unknown generic request: {}", req);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    private void parseRequestNetCacheObjectList(int token, ClientRequestBody body, TcpConnection conn) throws InvalidProtocolBufferException {
        Protocol.GenericRequestList genericRequestList = Protocol.GenericRequestList.parseFrom(body.getBody());
        genericRequestList.getRequestsList().forEach(gr -> this.parseGenericRequest(token, gr, conn));
    }

    private void parseSubscriptionRequest(BattleNetPacket packet, TcpConnection conn) throws Exception {
        Protocol.Header header = Processor.generateResponse(37, packet.getHeader().getToken(), 0, 0);
        conn.send(new BattleNetPacket(header, Util.hexStringToByteArray("0A090A026964120318BB020A180A0570726F746F120F320D084918AC0220002800300F4078")));
    }

    private void parseGetAssetsVersion(BattleNetPacket packet, TcpConnection conn) throws Exception {
        Protocol.Header header = Processor.generateResponse(29, packet.getHeader().getToken(), 0, 0);

        conn.send(new BattleNetPacket(header, Util.hexStringToByteArray("0A090A026964120318C6020A100A0570726F746F12073205080110AF02")));

        Protocol.GuardianVars guardianVars = Protocol.GuardianVars.newBuilder()
                .setShowUserUi(1)
                .setClientOptionsUpdateIntervalSeconds(300)
                .build();

        Protocol.Notification n = generateNotification(264, guardianVars.toByteString(), guardianVars.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setStatus(0)
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));

        Protocol.AssetsVersionResponse assetsVersionResponse = Protocol.AssetsVersionResponse.newBuilder()
                .setVersion(11046)
                .build();

        n = generateNotification(304, assetsVersionResponse.toByteString(), assetsVersionResponse.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setStatus(0)
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));
    }

    private void parseCheckAccountLicenses(BattleNetPacket packet, TcpConnection conn) throws Exception {
        // CheckAccountLicensesResponse
        Protocol.Header header = Processor.generateResponse(29, packet.getHeader().getToken(), 0, 0);
        conn.send(new BattleNetPacket(header, Util.hexStringToByteArray("0A090A026964120318C6020A100A0570726F746F120732050801108B02")));

        Protocol.GenericResponse gr = Protocol.GenericResponse.newBuilder()
                .setRequestId(267)
                .setResultCode(Protocol.GenericResponse.Result.RESULT_REQUEST_IN_PROCESS)
                .build();

        Protocol.Notification n = generateNotification(326, gr.toByteString(), gr.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));
    }

    private void parseUpdateLogin(BattleNetPacket packet, TcpConnection conn) throws Exception {
        //Protocol.UpdateLogin updateLogin = Protocol.UpdateLogin.parseFrom(body.getBody());
        Protocol.Header header = Processor.generateResponse(29, packet.getHeader().getToken(), 0, 0);
        conn.send(new BattleNetPacket(header, Util.hexStringToByteArray("0A090A026964120318C6020A100A0570726F746F12073205080110CD01")));
    }

    private void parseCheckGameLicenses(BattleNetPacket packet, TcpConnection conn) throws Exception {
        // CheckGameLicensesResponse

        Protocol.Header header = Processor.generateResponse(29, packet.getHeader().getToken(), 0, 0);
        conn.send(new BattleNetPacket(header, Util.hexStringToByteArray("0A090A026964120318C6020A100A0570726F746F120732050801109402")));

        Protocol.GenericResponse gr = Protocol.GenericResponse.newBuilder()
                .setRequestId(205)
                .setResultCode(Protocol.GenericResponse.Result.RESULT_REQUEST_IN_PROCESS)
                .build();

        Protocol.Notification n = generateNotification(326, gr.toByteString(), gr.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));

        gr = Protocol.GenericResponse.newBuilder()
                .setRequestId(276)
                .setResultCode(Protocol.GenericResponse.Result.RESULT_REQUEST_IN_PROCESS)
                .build();

        n = generateNotification(326, gr.toByteString(), gr.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));


        Protocol.UpdateLoginComplete updateLoginComplete = Protocol.UpdateLoginComplete.newBuilder().build();

        n = generateNotification(307, updateLoginComplete.toByteString(), updateLoginComplete.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));

        Protocol.CheckGameLicensesResponse checkGameLicensesResponse = Protocol.CheckGameLicensesResponse.newBuilder()
                .setSuccess(true)
                .build();

        n = generateNotification(331, checkGameLicensesResponse.toByteString(), checkGameLicensesResponse.getSerializedSize());

        header = Protocol.Header.newBuilder()
                .setServiceId(4)
                .setMethodId(1)
                .setToken(conn.nextToken())
                .setObjectId(0)
                .setSize(n.getSerializedSize())
                .setStatus(0)
                .build();

        conn.send(new BattleNetPacket(header, n.toByteArray()));

    }

    private void parseGetAdventureProgress(BattleNetPacket packet, TcpConnection conn) throws Exception {
        byte[] b = Util.hexStringToByteArray("0A090A026964120318C6020A100A0570726F746F12073205080110B102");
        Protocol.Header header = Processor.generateResponse(b.length, packet.getHeader().getToken(), 0, 0);
        conn.send(new BattleNetPacket(header, b));
    }

    private void parseGetBattlePayConfig(ClientRequestBody body) {
        log.info("parseGetBattlePayConfig: got");
    }

    private void parseGetAchieves(ClientRequestBody body) throws InvalidProtocolBufferException {
        Protocol.GetAchieves getAchieves = Protocol.GetAchieves.parseFrom(body.getBody());
        log.info("parseGetAchieves: {}", getAchieves);
    }

    private void parseGetBattlePayStatus(ClientRequestBody body) {
        log.info("parseGetBattlePayStatus: got");
    }

    private void parseSetOptions(ClientRequestBody body) throws InvalidProtocolBufferException {
        Protocol.SetOptions setOptions = Protocol.SetOptions.parseFrom(body.getBody());
        log.info("parseSetOptions: {}", setOptions);
    }

    private void parseSendUnsubcribeRequest(ClientRequestBody body) {
        log.info("parseSendUnsubcribeRequest: got");
    }

    private Protocol.Notification generateNotification(int message_type, ByteString bs, int size) {
        return Protocol.Notification.newBuilder()
                .setSenderId(Protocol.EntityId.newBuilder()
                        .setHigh(144115188075855872L)
                        .setLow(0))
                .setTargetId(Protocol.EntityId.newBuilder()
                        .setHigh(144115198130930503L)
                        .setLow(78330215))
                .setType("WTCG.UtilNotificationMessage")
                .setSenderBattleTag("")
                .setSenderAccountId(Protocol.EntityId.newBuilder()
                        .setHigh(72057594037927936L)
                        .setLow(0))
                .setTargetAccountId(Protocol.EntityId.newBuilder()
                        .setHigh(72057594037927936L)
                        .setLow(437154195))
                .addAttribute(Protocol.Attribute.newBuilder()
                        .setName("message_type")
                        .setValue(Protocol.Variant.newBuilder()
                                .setIntValue(message_type)))
                .addAttribute(Protocol.Attribute.newBuilder()
                        .setName("fragment_000")
                        .setValue(Protocol.Variant.newBuilder()
                                .setBlobValue(bs)))
                .addAttribute(Protocol.Attribute.newBuilder()
                        .setName("message_size")
                        .setValue(Protocol.Variant.newBuilder()
                                .setIntValue(size)))
                .build();
    }

    private void processClientRequest(BattleNetPacket packet, TcpConnection conn) throws Exception {
        Protocol.ClientRequest cr = Protocol.ClientRequest.parseFrom(packet.getBody());

        var p = parseClientRequest(cr);

        //log.info("processClientRequest: {}, token={}, body={}", p, packet.getHeader().getToken(), Protocol.Subscribe.parseFrom(p.getBody()));
        log.info("processClientRequest: token={}", packet.getHeader().getToken());
        int type = p != null ? p.getType() : 0;
        switch(type) {
            case 201 -> parseRequestNetCacheObject(packet.getHeader().getToken(), p, conn);
            case 327 -> parseRequestNetCacheObjectList(packet.getHeader().getToken(), p, conn);
            case 314 -> parseSubscriptionRequest(packet, conn);
            case 303 -> parseGetAssetsVersion(packet, conn);
            case 267 -> parseCheckAccountLicenses(packet, conn);
            case 205 -> parseUpdateLogin(packet, conn);
            case 276 -> parseCheckGameLicenses(packet, conn);
            case 305 -> parseGetAdventureProgress(packet, conn);
            case 237 -> parseGetBattlePayConfig(p);
            case 253 -> parseGetAchieves(p);
            case 255 -> parseGetBattlePayStatus(p);
            case 239 -> parseSetOptions(p);
            case 329 -> parseSendUnsubcribeRequest(p);
            default -> log.warn("Unknown ClientRequest type #{}", p.getType());
        }

        if( packet.getHeader().getToken() == 17 ) {
            Protocol.Header header = Processor.generateResponse(Util.hexStringToByteArray("0A090A026964120318BB020A180A0570726F746F120F320D081E18AC0220002800300F4078").length, packet.getHeader().getToken(), 0, 0);

            conn.send(new BattleNetPacket(header, Util.hexStringToByteArray("0A090A026964120318BB020A180A0570726F746F120F320D081E18AC0220002800300F4078")));
        } else if( packet.getHeader().getToken() == 24 ) {

            byte[] b = Util.hexStringToByteArray("0A090A026964120318C6020A100A0570726F746F12073205080110C702");

            Protocol.Header header = Processor.generateResponse(b.length, packet.getHeader().getToken(), 0, 0);

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318C60222190A0C667261676D656E745F30303012093207080110C901180422120A0C6D6573736167655F73697A65120218072A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318C60222190A0C667261676D656E745F30303012093207080110C901181722120A0C6D6573736167655F73697A65120218072A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318C60222190A0C667261676D656E745F30303012093207080110C901181322120A0C6D6573736167655F73697A65120218072A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318C60222190A0C667261676D656E745F30303012093207080110C901180822120A0C6D6573736167655F73697A65120218072A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318C60222190A0C667261676D656E745F30303012093207080110C901181422120A0C6D6573736167655F73697A65120218072A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318C60222190A0C667261676D656E745F30303012093207080110C901181B22120A0C6D6573736167655F73697A65120218072A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318C60222190A0C667261676D656E745F30303012093207080110C901180722120A0C6D6573736167655F73697A65120218072A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318C60222190A0C667261676D656E745F30303012093207080110C901181C22120A0C6D6573736167655F73697A65120218072A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));



            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F747970651203188F0222410A0C667261676D656E745F3030301231322F0A0D08E00F1005181F2016280630121003180A2064281F483C503C5A0D08E00F1005180320002800300065AAAAAABD22120A0C6D6573736167655F73697A651202182F2A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F747970651203188E0222430A0C667261676D656E745F303030123332310A060801180120000A09080110FD04180120000A060804180620010A09080410FD04180120000A09080410AD0A1805200122120A0C6D6573736167655F73697A65120218312A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318860222140A0C667261676D656E745F30303012043202080022120A0C6D6573736167655F73697A65120218022A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            // GoldBalance
            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F747970651203189602221D0A0C667261676D656E745F303030120D320B0800100018BF843D20D00F22120A0C6D6573736167655F73697A651202180B2A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            // log.warn("ProtoNotify" + Protocol.Notification.parseFrom(b));

            /*Protocol.GoldBalance gb = Protocol.GoldBalance.newBuilder()
                    .setCap(999999)
                    .setBonusBalance(165)
                    .setCappedBalance(160)
                    .setCapWarning(2000)
                    .build();*/

           /* Protocol.Notification notification = Protocol.Notification.newBuilder()
                    .setSenderId(Protocol.EntityId.newBuilder()
                            .setHigh(144115188075855872L)
                            .setLow(0))
                    .setTargetId(Protocol.EntityId.newBuilder()
                            .setHigh(144115198130930503L)
                            .setLow(78330215))
                    .setType("WTCG.UtilNotificationMessage")
                    .setSenderBattleTag("")
                    .setSenderAccountId(Protocol.EntityId.newBuilder()
                            .setHigh(72057594037927936L)
                            .setLow(0))
                    .setTargetAccountId(Protocol.EntityId.newBuilder()
                            .setHigh(72057594037927936L)
                            .setLow(437154195))
                    .addAttribute(Protocol.Attribute.newBuilder()
                            .setName("message_type")
                            .setValue(Protocol.Variant.newBuilder()
                                    .setIntValue(278L)))
                    .addAttribute(Protocol.Attribute.newBuilder()
                            .setName("fragment_000")
                            .setValue(Protocol.Variant.newBuilder()
                                    .setBlobValue(gb.toByteString())))
                    .addAttribute(Protocol.Attribute.newBuilder()
                            .setName("message_size")
                            .setValue(Protocol.Variant.newBuilder()
                                    .setIntValue(gb.getSerializedSize())))
                    .build();*/
           /* b = notification.toByteArray();
            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));*/

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318F10122480A0C667261676D656E745F303030123832360A04081818030A0B08013080E08380C0E180180A090802308080808080100A04081418020A04081518010A04080818040A04080A180122120A0C6D6573736167655F73697A65120218362A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318B20222120A0C6D6573736167655F73697A65120218002A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F747970651203189B0222F5010A0C667261676D656E745F30303012E40132E1010A1708021001180020462A0D08021A090A0508B706100010020A1708031001180020462A0D08021A090A0508B503100010020A1708041002180C20502A0D08041A090A0508BC08100010020A1708051001180020462A0D08021A090A0508CF06100010020A1708061001180020462A0D08021A090A0508D10A100010020A1708071001180020462A0D08021A090A0508A503100010020A1708081001180020462A0D08021A090A05089309100010020A1708091001180020462A0D08021A090A0508D607100010020A17080A1001180020462A0D08021A090A0508AC071000100222130A0C6D6573736167655F73697A65120318E1012A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("[encoded data, 20806 characters]");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318BE0222730A0C667261676D656E745F303030126332610A090802120508920210000A0808031204081F10000A090804120508FD0410000A0908051205089F0510000A090806120508AD0610000A090807120508A20710000A090808120508AA0810000A090809120508FD0610000A08080A12040807100022120A0C6D6573736167655F73697A65120218612A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318C60222190A0C667261676D656E745F30303012093207080110C901181522120A0C6D6573736167655F73697A65120218072A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318EC0122140A0C667261676D656E745F30303012043202080022120A0C6D6573736167655F73697A65120218022A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318C50222120A0C6D6573736167655F73697A65120218002A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));
        } else if( packet.getHeader().getToken() == 25 ) {
            byte[] b = Util.hexStringToByteArray("0A090A026964120318C6020A100A0570726F746F12073205080110ED01");

            Protocol.Header header = Processor.generateResponse(b.length, packet.getHeader().getToken(), 0, 0);

            conn.send(new BattleNetPacket(header, b));
        } else if( packet.getHeader().getToken() == 27 ) {
            byte[] b = Util.hexStringToByteArray("0A090A026964120318C6020A100A0570726F746F12073205080110FD01");

            Protocol.Header header = Processor.generateResponse(b.length, packet.getHeader().getToken(), 0, 0);

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("[encoded data, 12496 characters]");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));
        } else if( packet.getHeader().getToken() == 28 ) {
            byte[] b = Util.hexStringToByteArray("0A090A02696412031889020A0F0A0570726F746F1206320408002001");

            Protocol.Header header = Processor.generateResponse(b.length, packet.getHeader().getToken(), 0, 0);

            conn.send(new BattleNetPacket(header, b));
        } else if( packet.getHeader().getToken() == 29 ) {
            byte[] b = Util.hexStringToByteArray("0A090A026964120318C6020A100A0570726F746F12073205080110C702");

            Protocol.Header header = Processor.generateResponse(29, packet.getHeader().getToken(), 0, 0);

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318C60222190A0C667261676D656E745F30303012093207080110C901180C22120A0C6D6573736167655F73697A65120218072A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318D40122120A0C6D6573736167655F73697A65120218002A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));
        } else if( packet.getHeader().getToken() == 30 ) {
            Protocol.Header header = Processor.generateResponse(0, packet.getHeader().getToken(), 0, 0);

            conn.send(new BattleNetPacket(header, new byte[0]));

            byte[] b = Util.hexStringToByteArray("1252AA064F0A12094743545702000002116739AB040000000012190A170A0A08CE840110021809200012091884B6DAFCCEBDCC02121E0A1C0A0A08CE8401100218082000120E3A0C0D4743545715746174731804");

            header = Protocol.Header.newBuilder()
                    .setServiceId(5)
                    .setMethodId(6)
                    .setToken(conn.nextToken())
                    .setObjectId(2)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));
        } else if( packet.getHeader().getToken() == 34 || packet.getHeader().getToken() == 35 ) {

            Protocol.Header header = Processor.generateResponse(0, 12, 0, 0);

            conn.send(new BattleNetPacket(header, new byte[0]));

            header = Processor.generateResponse(0, packet.getHeader().getToken(), 0, 0);

            conn.send(new BattleNetPacket(header, new byte[0]));

            byte[] b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318E00122120A0C6D6573736167655F73697A65120218002A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));

            b = Util.hexStringToByteArray("0A120900000000000000021100000000000000001212094743545702000002116739AB04000000001A1C575443472E5574696C4E6F74696669636174696F6E4D65737361676522130A0C6D6573736167655F74797065120318880222190A0C667261676D656E745F30303012093207800101A801AC0222120A0C6D6573736167655F73697A65120218072A1209000000000000000111000000000000000032120900000000000000011193710E1A000000003A004A0A0889FF5C1092E5A1B90552150A050D93710E1A120C0D6739AB0415474354571802");

            header = Protocol.Header.newBuilder()
                    .setServiceId(4)
                    .setMethodId(1)
                    .setToken(conn.nextToken())
                    .setObjectId(0)
                    .setSize(b.length)
                    .setStatus(0)
                    .build();

            conn.send(new BattleNetPacket(header, b));
        }
    }

    @Override
    public void process(BattleNetPacket packet, TcpConnection conn) throws Exception {
        if( packet.getHeader().getMethodId() == 1 ) {
            processClientRequest(packet, conn);
            return;
        }
        log.error("Can't process weird GameUtilitiesProcessor method: {}", packet.getHeader().getMethodId());
    }

    @Override
    public String getExportName() {
        return "bnet.protocol.game_utilities.GameUtilities";
    }
}
