// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.builtin.adventure.shop.barter;

import com.hypixel.hytale.codec.builder.BuilderCodec;
import java.time.temporal.Temporal;
import java.time.Duration;
import com.hypixel.hytale.server.core.inventory.transaction.ItemStackTransaction;
import com.hypixel.hytale.server.core.inventory.container.CombinedItemContainer;
import com.hypixel.hytale.server.core.inventory.Inventory;
import com.hypixel.hytale.server.core.entity.ItemUtils;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.server.core.inventory.container.ItemContainer;
import com.hypixel.hytale.server.core.ui.builder.EventData;
import com.hypixel.hytale.protocol.packets.interface_.CustomUIEventBindingType;
import com.hypixel.hytale.server.core.entity.entities.Player;
import java.time.Instant;
import com.hypixel.hytale.server.core.modules.time.WorldTimeResource;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.ui.builder.UIEventBuilder;
import com.hypixel.hytale.server.core.ui.builder.UICommandBuilder;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.core.modules.item.ItemModule;
import com.hypixel.hytale.protocol.packets.interface_.CustomPageLifetime;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.entity.entities.player.pages.InteractiveCustomUIPage;

public class BarterPage extends InteractiveCustomUIPage<BarterEventData>
{
    private final BarterShopAsset shopAsset;
    
    public BarterPage(@Nonnull final PlayerRef playerRef, @Nonnull final String shopId) {
        super(playerRef, CustomPageLifetime.CanDismissOrCloseThroughInteraction, BarterEventData.CODEC);
        this.shopAsset = BarterShopAsset.getAssetMap().getAsset(shopId);
    }
    
    private boolean isTradeValid(final BarterTrade trade) {
        if (!ItemModule.exists(trade.getOutput().getItemId())) {
            return false;
        }
        for (final BarterItemStack input : trade.getInput()) {
            if (!ItemModule.exists(input.getItemId())) {
                return false;
            }
        }
        return true;
    }
    
    private String getSafeItemId(final String itemId) {
        return ItemModule.exists(itemId) ? itemId : "Unknown";
    }
    
    @Override
    public void build(@Nonnull final Ref<EntityStore> ref, @Nonnull final UICommandBuilder commandBuilder, @Nonnull final UIEventBuilder eventBuilder, @Nonnull final Store<EntityStore> store) {
        if (this.shopAsset == null) {
            return;
        }
        commandBuilder.append("Pages/BarterPage.ui");
        final String titleKey = (this.shopAsset.getDisplayNameKey() != null) ? this.shopAsset.getDisplayNameKey() : this.shopAsset.getId();
        commandBuilder.set("#ShopTitle.Text", Message.translation(titleKey));
        final WorldTimeResource timeResource = store.getResource(WorldTimeResource.getResourceType());
        final Instant gameTime = (timeResource != null) ? timeResource.getGameTime() : Instant.now();
        final BarterShopState barterState = BarterShopState.get();
        final int[] stockArray = barterState.getStockArray(this.shopAsset, gameTime);
        final Message refreshText = this.getRefreshTimerText(barterState, gameTime);
        if (refreshText != null) {
            commandBuilder.set("#RefreshTimer.Text", refreshText);
        }
        commandBuilder.clear("#TradeGrid");
        final Ref<EntityStore> playerEntityRef = this.playerRef.getReference();
        final Player playerComponent = (playerEntityRef != null) ? store.getComponent(playerEntityRef, Player.getComponentType()) : null;
        ItemContainer playerInventory = null;
        if (playerComponent != null) {
            playerInventory = playerComponent.getInventory().getCombinedHotbarFirst();
        }
        final BarterTrade[] trades = barterState.getResolvedTrades(this.shopAsset, gameTime);
        for (int i = 0; i < trades.length; ++i) {
            final BarterTrade trade = trades[i];
            final String selector = "#TradeGrid[" + i;
            final int stock = (i < stockArray.length) ? stockArray[i] : 0;
            final boolean tradeValid = this.isTradeValid(trade);
            commandBuilder.append("#TradeGrid", "Pages/BarterTradeRow.ui");
            commandBuilder.set(selector + " #OutputSlot.ItemId", this.getSafeItemId(trade.getOutput().getItemId()));
            final int outputQty = trade.getOutput().getQuantity();
            commandBuilder.set(selector + " #OutputQuantity.Text", (outputQty > 1) ? String.valueOf(outputQty) : "");
            boolean canAfford = true;
            int playerHas = 0;
            if (trade.getInput().length > 0) {
                final BarterItemStack firstInput = trade.getInput()[0];
                final String inputItemId = firstInput.getItemId();
                final int inputQty = firstInput.getQuantity();
                commandBuilder.set(selector + " #InputSlot.ItemId", this.getSafeItemId(inputItemId));
                commandBuilder.set(selector + " #InputQuantity.Text", (inputQty > 1) ? String.valueOf(inputQty) : "");
                if (ItemModule.exists(inputItemId)) {
                    playerHas = ((playerInventory != null) ? this.countItemsInContainer(playerInventory, inputItemId) : 0);
                    canAfford = (playerHas >= inputQty);
                }
                else {
                    canAfford = false;
                }
                commandBuilder.set(selector + " #InputSlotBorder.Background", canAfford ? "#2a5a3a" : "#5a2a2a");
                commandBuilder.set(selector + " #HaveNeedLabel.Text", "Have: " + playerHas);
                commandBuilder.set(selector + " #HaveNeedLabel.Style.TextColor", canAfford ? "#3d913f" : "#962f2f");
            }
            if (!tradeValid) {
                commandBuilder.set(selector + " #Stock.Visible", false);
                commandBuilder.set(selector + " #OutOfStockOverlay.Visible", true);
                commandBuilder.set(selector + " #OutOfStockLabel.Text", "INVALID ITEM");
                commandBuilder.set(selector + " #OutOfStockLabel.Style.TextColor", "#cc8844");
                commandBuilder.set(selector + " #TradeButton.Disabled", true);
                commandBuilder.set(selector + " #TradeButton.Style.Disabled.Background", "#4a3020");
            }
            else if (stock <= 0) {
                commandBuilder.set(selector + " #Stock.Visible", false);
                commandBuilder.set(selector + " #OutOfStockOverlay.Visible", true);
                commandBuilder.set(selector + " #OutOfStockLabel.Text", "OUT OF STOCK");
                commandBuilder.set(selector + " #OutOfStockLabel.Style.TextColor", "#cc4444");
                commandBuilder.set(selector + " #TradeButton.Disabled", true);
                commandBuilder.set(selector + " #TradeButton.Style.Disabled.Background", "#4a2020");
            }
            else {
                commandBuilder.set(selector + " #Stock.TextSpans", Message.translation("server.barter.customUI.barterPage.inStock").param("count", stock));
            }
            eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, selector + " #TradeButton", EventData.of("TradeIndex", String.valueOf(i)).append("Quantity", "1"), false);
            eventBuilder.addEventBinding(CustomUIEventBindingType.RightClicking, selector + " #TradeButton", EventData.of("TradeIndex", String.valueOf(i)).append("Quantity", "1"), false);
        }
        final int cardsPerRow = 3;
        final int remainder = trades.length % cardsPerRow;
        if (remainder > 0) {
            for (int spacersNeeded = cardsPerRow - remainder, s = 0; s < spacersNeeded; ++s) {
                commandBuilder.append("#TradeGrid", "Pages/BarterGridSpacer.ui");
            }
        }
    }
    
    @Override
    public void handleDataEvent(@Nonnull final Ref<EntityStore> ref, @Nonnull final Store<EntityStore> store, @Nonnull final BarterEventData data) {
        if (this.shopAsset == null) {
            return;
        }
        final int tradeIndex = data.getTradeIndex();
        final int requestedQuantity = data.getQuantity();
        if (requestedQuantity <= 0) {
            return;
        }
        final WorldTimeResource timeResource = store.getResource(WorldTimeResource.getResourceType());
        final Instant gameTime = (timeResource != null) ? timeResource.getGameTime() : Instant.now();
        final BarterShopState barterState = BarterShopState.get();
        final BarterTrade[] trades = barterState.getResolvedTrades(this.shopAsset, gameTime);
        if (tradeIndex < 0 || tradeIndex >= trades.length) {
            return;
        }
        final BarterTrade trade = trades[tradeIndex];
        if (!this.isTradeValid(trade)) {
            return;
        }
        final BarterShopState.ShopInstanceState shopState = barterState.getOrCreateShopState(this.shopAsset, gameTime);
        final int currentStock = shopState.getCurrentStock()[tradeIndex];
        if (currentStock <= 0) {
            return;
        }
        final Ref<EntityStore> playerEntityRef = this.playerRef.getReference();
        if (playerEntityRef == null) {
            return;
        }
        final Player playerComponent = store.getComponent(playerEntityRef, Player.getComponentType());
        if (playerComponent == null) {
            return;
        }
        final Inventory inventory = playerComponent.getInventory();
        final CombinedItemContainer container = inventory.getCombinedHotbarFirst();
        int maxQuantity = Math.min(requestedQuantity, currentStock);
        for (final BarterItemStack inputStack : trade.getInput()) {
            final int has = this.countItemsInContainer(container, inputStack.getItemId());
            final int canAfford = has / inputStack.getQuantity();
            maxQuantity = Math.min(maxQuantity, canAfford);
        }
        if (maxQuantity <= 0) {
            return;
        }
        final int quantity = maxQuantity;
        for (final BarterItemStack inputStack2 : trade.getInput()) {
            final int toRemove = inputStack2.getQuantity() * quantity;
            this.removeItemsFromContainer(container, inputStack2.getItemId(), toRemove);
        }
        final BarterItemStack output = trade.getOutput();
        final ItemStack outputStack = new ItemStack(output.getItemId(), output.getQuantity() * quantity);
        final ItemStackTransaction transaction = container.addItemStack(outputStack);
        final ItemStack remainder = transaction.getRemainder();
        if (remainder != null && !remainder.isEmpty()) {
            final int addedQty = outputStack.getQuantity() - remainder.getQuantity();
            if (addedQty > 0) {
                playerComponent.notifyPickupItem(playerEntityRef, outputStack.withQuantity(addedQty), null, store);
            }
            ItemUtils.dropItem(playerEntityRef, remainder, store);
        }
        else {
            playerComponent.notifyPickupItem(playerEntityRef, outputStack, null, store);
        }
        barterState.executeTrade(this.shopAsset, tradeIndex, quantity, gameTime);
        this.updateAfterTrade(ref, store, tradeIndex);
    }
    
    private void updateAfterTrade(@Nonnull final Ref<EntityStore> ref, @Nonnull final Store<EntityStore> store, final int tradedIndex) {
        final UICommandBuilder commandBuilder = new UICommandBuilder();
        final WorldTimeResource timeResource = store.getResource(WorldTimeResource.getResourceType());
        final Instant gameTime = (timeResource != null) ? timeResource.getGameTime() : Instant.now();
        final BarterShopState barterState = BarterShopState.get();
        final int[] stockArray = barterState.getStockArray(this.shopAsset, gameTime);
        final BarterTrade[] trades = barterState.getResolvedTrades(this.shopAsset, gameTime);
        final Ref<EntityStore> playerEntityRef = this.playerRef.getReference();
        final Player playerComponent = (playerEntityRef != null) ? store.getComponent(playerEntityRef, Player.getComponentType()) : null;
        ItemContainer playerInventory = null;
        if (playerComponent != null) {
            playerInventory = playerComponent.getInventory().getCombinedHotbarFirst();
        }
        for (int i = 0; i < trades.length; ++i) {
            final BarterTrade trade = trades[i];
            final String selector = "#TradeGrid[" + i;
            final int stock = (i < stockArray.length) ? stockArray[i] : 0;
            final boolean tradeValid = this.isTradeValid(trade);
            if (trade.getInput().length > 0) {
                final BarterItemStack firstInput = trade.getInput()[0];
                int playerHas = 0;
                boolean canAfford = false;
                if (ItemModule.exists(firstInput.getItemId())) {
                    playerHas = ((playerInventory != null) ? this.countItemsInContainer(playerInventory, firstInput.getItemId()) : 0);
                    canAfford = (playerHas >= firstInput.getQuantity());
                }
                commandBuilder.set(selector + " #InputSlotBorder.Background", canAfford ? "#2a5a3a" : "#5a2a2a");
                commandBuilder.set(selector + " #HaveNeedLabel.Text", "Have: " + playerHas);
                commandBuilder.set(selector + " #HaveNeedLabel.Style.TextColor", canAfford ? "#3d913f" : "#962f2f");
            }
            if (!tradeValid) {
                commandBuilder.set(selector + " #Stock.Visible", false);
                commandBuilder.set(selector + " #OutOfStockOverlay.Visible", true);
                commandBuilder.set(selector + " #TradeButton.Disabled", true);
            }
            else if (stock <= 0) {
                commandBuilder.set(selector + " #Stock.Visible", false);
                commandBuilder.set(selector + " #OutOfStockOverlay.Visible", true);
                commandBuilder.set(selector + " #OutOfStockLabel.Text", "OUT OF STOCK");
                commandBuilder.set(selector + " #OutOfStockLabel.Style.TextColor", "#cc4444");
                commandBuilder.set(selector + " #TradeButton.Disabled", true);
                commandBuilder.set(selector + " #TradeButton.Style.Disabled.Background", "#4a2020");
            }
            else {
                commandBuilder.set(selector + " #Stock.Visible", true);
                commandBuilder.set(selector + " #Stock.TextSpans", Message.translation("server.barter.customUI.barterPage.inStock").param("count", stock));
                commandBuilder.set(selector + " #OutOfStockOverlay.Visible", false);
                commandBuilder.set(selector + " #TradeButton.Disabled", false);
                commandBuilder.set(selector + " #TradeButton.Style.Default.Background", "#1e2a3a");
            }
        }
        this.sendUpdate(commandBuilder, new UIEventBuilder(), false);
    }
    
    private int countItemsInContainer(final ItemContainer container, final String itemId) {
        return container.countItemStacks(stack -> itemId.equals(stack.getItemId()));
    }
    
    private void removeItemsFromContainer(final ItemContainer container, final String itemId, final int amount) {
        container.removeItemStack(new ItemStack(itemId, amount));
    }
    
    private void refreshUI(@Nonnull final Ref<EntityStore> ref, @Nonnull final Store<EntityStore> store) {
        final UICommandBuilder commandBuilder = new UICommandBuilder();
        final UIEventBuilder eventBuilder = new UIEventBuilder();
        this.build(ref, commandBuilder, eventBuilder, store);
        this.sendUpdate(commandBuilder, eventBuilder, true);
    }
    
    private Message getRefreshTimerText(final BarterShopState barterState, final Instant gameTime) {
        if (this.shopAsset == null) {
            return null;
        }
        final RefreshInterval interval = this.shopAsset.getRefreshInterval();
        if (interval == null) {
            return null;
        }
        final BarterShopState.ShopInstanceState shopState = barterState.getOrCreateShopState(this.shopAsset, gameTime);
        final Instant nextRefresh = shopState.getNextRefreshTime();
        if (nextRefresh == null) {
            return null;
        }
        final Duration remaining = Duration.between(gameTime, nextRefresh);
        if (remaining.isNegative() || remaining.isZero()) {
            return null;
        }
        final long currentDayNumber = gameTime.getEpochSecond() / WorldTimeResource.SECONDS_PER_DAY;
        final long refreshDayNumber = nextRefresh.getEpochSecond() / WorldTimeResource.SECONDS_PER_DAY;
        final long daysUntilRefresh = refreshDayNumber - currentDayNumber;
        final int hour = this.shopAsset.getRestockHour();
        final String amPm = (hour >= 12) ? "PM" : "AM";
        int displayHour = hour % 12;
        if (displayHour == 0) {
            displayHour = 12;
        }
        final String timeString = String.format("%d:00 %s", displayHour, amPm);
        if (daysUntilRefresh <= 0L) {
            return Message.translation("server.barter.customUI.barterPage.restocksToday").param("restockTime", timeString);
        }
        if (daysUntilRefresh == 1L) {
            return Message.translation("server.barter.customUI.barterPage.restocksTomorrow").param("restockTime", timeString);
        }
        return Message.translation("server.barter.customUI.barterPage.restocksInDays").param("days", (int)daysUntilRefresh);
    }
    
    public static class BarterEventData
    {
        static final String TRADE_INDEX = "TradeIndex";
        static final String QUANTITY = "Quantity";
        static final String SHIFT_HELD = "ShiftHeld";
        public static final BuilderCodec<BarterEventData> CODEC;
        private int tradeIndex;
        private int quantity;
        private boolean shiftHeld;
        
        public BarterEventData() {
            this.quantity = 1;
            this.shiftHeld = false;
        }
        
        public int getTradeIndex() {
            return this.tradeIndex;
        }
        
        public int getQuantity() {
            return this.shiftHeld ? 10 : this.quantity;
        }
        
        public boolean isShiftHeld() {
            return this.shiftHeld;
        }
        
        static {
            // 
            // This method could not be decompiled.
            // 
            // Original Bytecode:
            // 
            //     2: invokedynamic   BootstrapMethod #0, get:()Ljava/util/function/Supplier;
            //     7: invokestatic    com/hypixel/hytale/codec/builder/BuilderCodec.builder:(Ljava/lang/Class;Ljava/util/function/Supplier;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //    10: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //    13: dup            
            //    14: ldc             "TradeIndex"
            //    16: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
            //    19: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //    22: invokedynamic   BootstrapMethod #1, accept:()Ljava/util/function/BiConsumer;
            //    27: invokedynamic   BootstrapMethod #2, apply:()Ljava/util/function/Function;
            //    32: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.append:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderField$FieldBuilder;
            //    35: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.add:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //    38: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //    41: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //    44: dup            
            //    45: ldc             "Quantity"
            //    47: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
            //    50: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //    53: invokedynamic   BootstrapMethod #3, accept:()Ljava/util/function/BiConsumer;
            //    58: invokedynamic   BootstrapMethod #4, apply:()Ljava/util/function/Function;
            //    63: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.append:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderField$FieldBuilder;
            //    66: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.add:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //    69: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //    72: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //    75: dup            
            //    76: ldc             "ShiftHeld"
            //    78: getstatic       com/hypixel/hytale/codec/Codec.BOOLEAN:Lcom/hypixel/hytale/codec/codecs/simple/BooleanCodec;
            //    81: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //    84: invokedynamic   BootstrapMethod #5, accept:()Ljava/util/function/BiConsumer;
            //    89: invokedynamic   BootstrapMethod #6, apply:()Ljava/util/function/Function;
            //    94: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.append:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderField$FieldBuilder;
            //    97: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.add:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //   100: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //   103: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.build:()Lcom/hypixel/hytale/codec/builder/BuilderCodec;
            //   106: putstatic       com/hypixel/hytale/builtin/adventure/shop/barter/BarterPage$BarterEventData.CODEC:Lcom/hypixel/hytale/codec/builder/BuilderCodec;
            //   109: return         
            // 
            // The error that occurred was:
            // 
            // java.lang.UnsupportedOperationException: The requested operation is not supported.
            //     at com.strobel.util.ContractUtils.unsupported(ContractUtils.java:27)
            //     at com.strobel.assembler.metadata.TypeReference.getRawType(TypeReference.java:284)
            //     at com.strobel.assembler.metadata.TypeReference.getRawType(TypeReference.java:279)
            //     at com.strobel.assembler.metadata.TypeReference.makeGenericType(TypeReference.java:154)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitParameterizedType(TypeSubstitutionVisitor.java:225)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitParameterizedType(TypeSubstitutionVisitor.java:25)
            //     at com.strobel.assembler.metadata.ParameterizedType.accept(ParameterizedType.java:103)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visit(TypeSubstitutionVisitor.java:40)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitParameterizedType(TypeSubstitutionVisitor.java:211)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitParameterizedType(TypeSubstitutionVisitor.java:25)
            //     at com.strobel.assembler.metadata.ParameterizedType.accept(ParameterizedType.java:103)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visit(TypeSubstitutionVisitor.java:40)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitMethod(TypeSubstitutionVisitor.java:314)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2611)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1083)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:684)
            //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:667)
            //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:373)
            //     at com.strobel.decompiler.ast.TypeAnalysis.run(TypeAnalysis.java:95)
            //     at com.strobel.decompiler.ast.AstOptimizer.optimize(AstOptimizer.java:344)
            //     at com.strobel.decompiler.ast.AstOptimizer.optimize(AstOptimizer.java:42)
            //     at com.strobel.decompiler.languages.java.ast.AstMethodBodyBuilder.createMethodBody(AstMethodBodyBuilder.java:206)
            //     at com.strobel.decompiler.languages.java.ast.AstMethodBodyBuilder.createMethodBody(AstMethodBodyBuilder.java:93)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createMethodBody(AstBuilder.java:868)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createMethod(AstBuilder.java:761)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addTypeMembers(AstBuilder.java:638)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeCore(AstBuilder.java:605)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeNoCache(AstBuilder.java:195)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addTypeMembers(AstBuilder.java:662)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeCore(AstBuilder.java:605)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeNoCache(AstBuilder.java:195)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createType(AstBuilder.java:162)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addType(AstBuilder.java:137)
            //     at com.strobel.decompiler.languages.java.JavaLanguage.buildAst(JavaLanguage.java:71)
            //     at com.strobel.decompiler.languages.java.JavaLanguage.decompileType(JavaLanguage.java:59)
            //     at com.strobel.decompiler.DecompilerDriver.decompileType(DecompilerDriver.java:333)
            //     at com.strobel.decompiler.DecompilerDriver.decompileJar(DecompilerDriver.java:254)
            //     at com.strobel.decompiler.DecompilerDriver.main(DecompilerDriver.java:129)
            // 
            throw new IllegalStateException("An error occurred while decompiling this method.");
        }
    }
}
