// • ▌ ▄ ·.  ▄▄▄·  ▄▄ • ▪   ▄▄· ▄▄▄▄·  ▄▄▄·  ▐▄▄▄  ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀  █▪▀▀▀ ▀  ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀  ▀  ▀ ▀▀  █▪ ▀▀▀
//      Magicbane Emulator Project © 2013 - 2022
//                www.magicbane.com


package engine.net.client.msg;

import engine.gameManager.BuildingManager;
import engine.gameManager.ForgeManager;
import engine.gameManager.NPCManager;
import engine.loot.WorkOrder;
import engine.mbEnums;
import engine.mbEnums.GameObjectType;
import engine.net.*;
import engine.objects.Building;
import engine.objects.Item;
import engine.objects.NPC;

import java.util.HashMap;

public class ItemProductionMsg extends ClientNetMsg {

    public int size;
    public int buildingUUID;
    public int unknown01;
    public int itemUUID;
    public int itemType;
    public int total_to_produce;
    public int unknown03;
    public int pToken;
    public int sToken;
    public String name;
    public mbEnums.ProductionActionType actionType;
    public int npcUUID;
    public boolean add;
    public int itemPrice;
    public HashMap<Integer, Integer> items;

    /**
     * This is the general purpose constructor.
     */

    public ItemProductionMsg() {
        super(Protocol.ITEMPRODUCTION);
        this.actionType = mbEnums.ProductionActionType.NONE;
        this.size = 0;
        this.buildingUUID = 0;
        this.unknown01 = 0;
        this.itemUUID = 0;
        this.total_to_produce = 0;
        this.unknown03 = 0;
        this.pToken = 0;
        this.sToken = 0;
        this.name = "";
        this.itemPrice = 0;
        this.itemType = 0;

    }

    public ItemProductionMsg(Building building, NPC vendor, Item item, mbEnums.ProductionActionType actionType, boolean add) {
        super(Protocol.ITEMPRODUCTION);
        this.actionType = actionType;
        this.size = 0;
        this.buildingUUID = building.getObjectUUID();
        this.npcUUID = vendor.getObjectUUID();
        this.itemType = item.getObjectType().ordinal();
        this.itemUUID = item.getObjectUUID();
        this.unknown01 = 0;
        this.total_to_produce = 0;
        this.unknown03 = 0;
        this.pToken = 0;
        this.sToken = 0;
        this.name = "";
        this.add = add;
        this.itemPrice = item.getValue();

    }

    /**
     * This constructor is used by NetMsgFactory. It attempts to deserialize the
     * ByteBuffer into a message. If a BufferUnderflow occurs (based on reading
     * past the limit) then this constructor Throws that Exception to the
     * caller.
     */
    public ItemProductionMsg(AbstractConnection origin, ByteBufferReader reader) {
        super(Protocol.ITEMPRODUCTION, origin, reader);

    }

    /**
     * @see AbstractNetMsg#getPowerOfTwoBufferSize()
     */
    @Override
    protected int getPowerOfTwoBufferSize() {
        //Larger size for historically larger opcodes
        return (16); // 2^16 == 64k
    }

    /**
     * Serializes the subclass specific items to the supplied NetMsgWriter.
     */
    @Override
    protected void _serialize(ByteBufferWriter writer) {
        Building building = BuildingManager.getBuildingFromCache(this.buildingUUID);
        if (building == null)
            return;
        // Common Header

        writer.putInt(this.actionType.ordinal());
        writer.putInt(GameObjectType.Building.ordinal());
        writer.putInt(this.buildingUUID);
        writer.putInt(GameObjectType.NPC.ordinal());
        writer.putInt(this.npcUUID);

        switch (this.actionType) {

            case CONFIRM_DEPOSIT:
                writer.putInt(0); // Not item ordinal?
                writer.putInt(0); // Not item uuid?
                writer.putInt(1);
                writer.putInt(0);

                if (!add) {
                    writer.put((byte) 1);

                    Item item;
                    item = Item.getFromCache(this.itemUUID);  // Negative ID items not sent here.  Deposit virtual item?

                    if (item != null)
                        Item.serializeForClientMsgWithoutSlot(item, writer);

                    writer.putInt(building.getStrongboxValue());
                    writer.putInt(0);
                    writer.putInt(0);
                    writer.put((byte) 0);
                    break;
                }
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(0);
                writer.put((byte) 1);

                Item item = Item.getFromCache(this.itemUUID);

                if (item != null)
                    Item.serializeForClientMsgWithoutSlot(item, writer);

                writer.putInt(building.getStrongboxValue());
                writer.putInt(0);
                writer.putInt(0);
                writer.put((byte) 0);
                break;
            case CONFIRM_TAKE:
                writer.putInt(this.itemType);
                writer.putInt(this.itemUUID);
                writer.putInt(1);
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(0);
                writer.put((byte) 0);
                break;
            case SETPRICE:
                writer.putInt(this.itemType);
                writer.putInt(this.itemUUID);
                writer.putInt(1);
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(this.itemPrice); // new price
                writer.putInt(0);
                writer.putInt(0);
                writer.put((byte) 0);
                break;
            case CONFIRM_SETPRICE:
                writer.putInt(this.itemType);
                writer.putInt(this.itemUUID);
                writer.putInt(1);
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(0);
                writer.put((byte) 1);
                writer.putInt(building.getStrongboxValue()); // new price
                writer.putInt(0);
                writer.putInt(0);
                //writer.put((byte) 0);
                break;
            case DEPOSIT:
                writer.putInt(this.itemType);
                writer.putInt(this.itemUUID);
                writer.putInt(1);
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(0);
                writer.put((byte) 0);
                break;
            case TAKE:
            case RECYCLE:
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(1);
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(0);
                writer.put((byte) 1);
                writer.putInt(building.getStrongboxValue());

                if (this.items != null) {
                    writer.putInt(this.items.size());

                    for (int itemID : this.items.keySet()) {
                        writer.putInt(this.items.get(itemID));
                        writer.putInt(itemID);
                    }

                } else
                    writer.putInt(0);

                writer.putInt(0);

                break;
            case CONFIRM_PRODUCE:
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(1);
                Item toRoll = Item.getFromCache(this.itemUUID);
                writer.putInt(-1497023830);

                WorkOrder workOrder = ForgeManager.itemWorkOrderLookup.get(toRoll);

                this.pToken = toRoll.prefixToken;
                this.sToken = toRoll.suffixToken;

                if (toRoll.isComplete() || (workOrder.prefixToken != 0 && workOrder.suffixToken != 0)) {
                    writer.putInt(this.pToken);
                    writer.putInt(this.sToken);
                } else {
                    writer.putInt(0);
                    writer.putInt(0);
                }

                writer.putString(toRoll.name);
                writer.putInt(toRoll.getObjectType().ordinal());
                writer.putInt(this.itemUUID);
                writer.putInt(0); //items left to produce?

                writer.putInt(toRoll.templateID);
                writer.putInt(toRoll.getValue());

                NPC vendor = NPC.getFromCache(this.npcUUID);

                if (vendor != null) {
                    if (toRoll.isComplete()) {
                        writer.putInt(0);
                        writer.putInt(0);
                    } else {
                        long timeLeft = toRoll.getDateToUpgrade() - System.currentTimeMillis();

                        timeLeft /= 1000;
                        writer.putInt((int) timeLeft);
                        writer.putInt((int) (NPCManager.calcRollingDuration(vendor, toRoll.templateID) * .001));
                    }

                } else {
                    writer.putInt(0);
                    writer.putInt(0);
                }
                if (toRoll.isComplete())
                    writer.putInt(0);
                else
                    writer.putInt(1);
                writer.put((byte) 0);

                if (toRoll != null && toRoll.isComplete())
                    writer.put((byte) 1);
                else
                    writer.put((byte) 0);
                writer.put((byte) 0);
                writer.put((byte) 1);
                writer.putInt(vendor.getBuilding().getStrongboxValue());

                writer.putInt(0);
                writer.putInt(0);
                //writer.putInt(0); //error popup

                break;
            case COMPLETE:
                writer.putInt(this.itemType);
                writer.putInt(this.itemUUID);
                writer.putInt(this.total_to_produce);
                writer.putInt(this.unknown03);
                writer.putInt(this.pToken);
                writer.putInt(this.sToken);
                writer.putInt(0);
                writer.putInt(0);
                writer.putInt(0);
                writer.put((byte) 0);
                break;
            case JUNK:
                writer.putInt(this.itemType);
                writer.putInt(this.itemUUID);
                writer.putInt(this.total_to_produce);
                writer.putInt(this.unknown03);
                writer.putInt(this.pToken);
                writer.putInt(this.sToken);
                writer.putString(this.name);
                writer.putInt(0);
                writer.putInt(0);
                writer.putShort((short) 0);
                writer.put((byte) 0);
                break;
            default:
                writer.putInt(0);
                writer.putInt(1);
                writer.putInt(0);
                writer.putInt(0);
                break;
        }
    }

    /**
     * Deserializes the subclass specific items from the supplied NetMsgReader.
     */
    @Override
    protected void _deserialize(ByteBufferReader reader) {

        // Common header

        this.actionType = mbEnums.ProductionActionType.values()[reader.getInt()];
        reader.getInt(); // Building type padding
        this.buildingUUID = reader.getInt();
        reader.getInt(); // NPC type padding
        this.npcUUID = reader.getInt();

        switch (this.actionType) {
            case SETPRICE:
                this.itemType = reader.getInt();
                this.itemUUID = reader.getInt();
                reader.getInt();
                reader.getInt();
                reader.getInt();
                reader.getInt();
                reader.getInt();
                this.itemPrice = reader.getInt();
                reader.getInt();
                reader.getInt();
                reader.get();
                break;
            case RECYCLE:
            case TAKE:
                reader.getInt();
                reader.getInt();
                reader.getInt();
                reader.getInt();
                reader.getInt();
                reader.getInt();
                reader.getInt();
                reader.get();
                this.size = reader.getInt();
                HashMap<Integer, Integer> tempIDs = new HashMap<>();
                for (int i = 0; i < this.size; i++) {
                    int type = reader.getInt(); // Item type padding
                    this.itemUUID = reader.getInt();
                    tempIDs.put(this.itemUUID, type);
                }
                reader.getInt();
                this.items = tempIDs;
                break;
            case DEPOSIT:
                this.itemType = reader.getInt();
                this.itemUUID = reader.getInt();
                reader.getInt();
                reader.getInt();
                reader.getInt();
                reader.getInt();
                reader.getInt();
                reader.getInt();
                reader.getInt();
                reader.get();
                break;
            case JUNK:
                this.itemType = reader.getInt();
                this.itemUUID = reader.getInt();
                this.total_to_produce = reader.getInt();
                this.unknown03 = reader.getInt();
                this.pToken = reader.getInt();
                this.sToken = reader.getInt();
                this.name = reader.getString();
                reader.getInt();
                reader.getInt();
                reader.get();
                break;
            default:
                this.itemType = reader.getInt();
                this.itemUUID = reader.getInt();
                this.total_to_produce = reader.getInt();
                this.unknown03 = reader.getInt();
                this.pToken = reader.getInt();
                this.sToken = reader.getInt();
                this.name = reader.getString();
                this.size = reader.getInt();
                reader.getInt();

                if (this.actionType == mbEnums.ProductionActionType.COMPLETE || this.actionType == mbEnums.ProductionActionType.JUNK)
                    reader.get();
                else
                    reader.getShort();
                break;
        }
    }

}
