/*  Copyright (C) <2015>  <XFactHD, DrakoAlcarus>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see http://www.gnu.org/licenses. */

package XFactHD.thermalreactors.common.blocks.machine.miscellaneous;

import XFactHD.thermalreactors.common.blocks.TileEntityBaseTR;
import XFactHD.thermalreactors.common.util.LogHelper;
import XFactHD.thermalreactors.common.util.Utils;
import cofh.api.energy.*;
import cofh.api.tileentity.IEnergyInfo;
import cofh.api.tileentity.IRedstoneControl;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.play.server.S35PacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection;

public class TileEntityPlutoniumEnergyCell extends TileEntityBaseTR implements IEnergyHandler
{
    public EnergyStorage energyStorage = new EnergyStorage(320000000, 128000, 128000);
    public int[] sides = new int[]{1, 2, 1, 1, 1, 1};
    public int facing = 0;
    public int charge = 0;
    public int input = 128000;
    public int output = 128000;
    public int mode = 1;
    public boolean powered = false;

    public TileEntityPlutoniumEnergyCell(){}

    @Override
    public boolean receiveClientEvent(int id, int arg)
    {
        if(id==0)
        {
            this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
            return true;
        }
        return false;
    }

    @Override
    public void updateEntity()
    {
        if(!worldObj.isRemote)
        {
            this.transferEnergy();
            if (charge != getChargeIn8s())
            {
                charge = getChargeIn8s();
                worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
            }
        }
    }

    public int getRedstoneMode()
    {
        return mode;
    }

    public void setRedstoneMode(int mode)
    {
        this.mode = mode;
        worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
    }

    public boolean canBeActive()
    {
        return (mode == 0 || (mode == 1 && !powered) || (mode == 2 && powered));
    }

    public void setFace(int id, int setting)
    {
        ForgeDirection fd;
        switch (facing)
        {
            case 0: switch (id)
            {
                case 0: fd = ForgeDirection.DOWN;
                case 1: fd = ForgeDirection.UP;
                case 2: fd = ForgeDirection.NORTH;
                case 3: fd = ForgeDirection.SOUTH;
                case 4: fd = ForgeDirection.WEST;
                case 5: fd = ForgeDirection.EAST;
            }
            case 1: switch (id)
            {
                case 0: fd = ForgeDirection.DOWN;
                case 1: fd = ForgeDirection.UP;
                case 2: fd = ForgeDirection.WEST;
                case 3: fd = ForgeDirection.EAST;
                case 4: fd = ForgeDirection.NORTH;
                case 5: fd = ForgeDirection.SOUTH;
            }
            case 2: switch (id)
            {
                case 0: fd = ForgeDirection.DOWN;
                case 1: fd = ForgeDirection.UP;
                case 2: fd = ForgeDirection.SOUTH;
                case 3: fd = ForgeDirection.NORTH;
                case 4: fd = ForgeDirection.EAST;
                case 5: fd = ForgeDirection.WEST;
            }
            case 3: switch (id)
            {
                case 0: fd = ForgeDirection.DOWN;
                case 1: fd = ForgeDirection.UP;
                case 2: fd = ForgeDirection.EAST;
                case 3: fd = ForgeDirection.WEST;
                case 4: fd = ForgeDirection.SOUTH;
                case 5: fd = ForgeDirection.NORTH;
            }
            default: fd = ForgeDirection.UNKNOWN;
        }

        sides[Utils.getIntFromFD(fd)] = setting;
        worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
    }

    public int getFace(int id)
    {
        switch (facing)
        {
            case 0: switch (id)
            {
                case 0: /*Bottom*/ return sides[0]; //Down
                case 1: /*Top*/ return sides[1]; //Up
                case 2: /*Front*/ return sides[2]; //North
                case 3: /*Back*/ return sides[3]; //South
                case 4: /*Right*/ return sides[4]; //West
                case 5: /*Left*/ return sides[5]; //East
            }
            case 1: switch (id)
            {
                case 0: /*Top*/ return sides[0];
                case 1: /*Bottom*/ return sides[1];
                case 2: /*Front*/ return sides[4];
                case 3: /*Back*/ return sides[5];
                case 4: /*Right*/ return sides[2];
                case 5: /*Left*/ return sides[3];
            }
            case 2: switch (id)
            {
                case 0: /*Top*/ return sides[0];
                case 1: /*Bottom*/ return sides[1];
                case 2: /*Front*/ return sides[3];
                case 3: /*Back*/ return sides[2];
                case 4: /*Right*/ return sides[5];
                case 5: /*Left*/ return sides[4];
            }
            case 3: switch (id)
            {
                case 0: /*Top*/ return sides[0];
                case 1: /*Bottom*/ return sides[1];
                case 2: /*Front*/ return sides[5];
                case 3: /*Back*/ return sides[4];
                case 4: /*Right*/ return sides[3];
                case 5: /*Left*/ return sides[2];
            }
            default: return 0;
        }
    }

    public int getChargeIn8s()
    {
        double chargePart = (((double)energyStorage.getEnergyStored())/((double)energyStorage.getMaxEnergyStored()));
        return ((int)(chargePart*8));
    }

    //IEnergyHandler
    @Override
    public boolean canConnectEnergy(ForgeDirection fd)
    {
        return sides[Utils.getIntFromFD(fd)] > 0;
    }

    @Override
    public int receiveEnergy(ForgeDirection fd, int amount, boolean simulate)
    {
        if (fd == ForgeDirection.UNKNOWN)
        {
            return energyStorage.receiveEnergy(amount, simulate);
        }
        if (sides[Utils.getIntFromFD(fd)] == 1 && !worldObj.isRemote)
        {
            return energyStorage.receiveEnergy(amount, simulate);
        }
        return 0;
    }

    @Override
    public int extractEnergy(ForgeDirection fd, int amount, boolean simulate)
    {
        if (fd == ForgeDirection.UNKNOWN)
        {
            worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
            return energyStorage.extractEnergy(amount, simulate);
        }
        if (sides[Utils.getIntFromFD(fd)] == 2 && !worldObj.isRemote)
        {
            worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
            return energyStorage.extractEnergy(amount, simulate);
        }
        return 0;
    }

    @Override
    public int getEnergyStored(ForgeDirection forgeDirection)
    {
        return energyStorage.getEnergyStored();
    }

    @Override
    public int getMaxEnergyStored(ForgeDirection forgeDirection)
    {
        return energyStorage.getMaxEnergyStored();
    }

    protected void transferEnergy()
    {
        for(int i=0; i<6; i++)
        {
            ForgeDirection fd = ForgeDirection.VALID_DIRECTIONS[i];
            TileEntity tileEntity = worldObj.getTileEntity(xCoord+fd.offsetX, yCoord+fd.offsetY, zCoord+fd.offsetZ);
            if(canBeActive() && sides[Utils.getIntFromFD(fd)] == 2 && tileEntity instanceof IEnergyReceiver && ((IEnergyReceiver)tileEntity).receiveEnergy(fd.getOpposite(), this.energyStorage.getMaxExtract(), true) > 0 && this.energyStorage.getEnergyStored() > 0)
            {
                int received =((IEnergyReceiver)tileEntity).receiveEnergy(fd.getOpposite(), this.energyStorage.getMaxExtract(), false);
                this.energyStorage.setEnergyStored(this.energyStorage.getEnergyStored()-received);
            }
        }
    }

    //NBT Stuff
    @Override
    public void readFromNBT(NBTTagCompound nbt)
    {
        super.readFromNBT(nbt);
        facing = nbt.getInteger("facing");
        sides = nbt.getIntArray("sides");
        charge = nbt.getInteger("charge");
        energyStorage.readFromNBT(nbt);
        //LogHelper.info("Reading from NBT");
    }

    @Override
    public void writeToNBT(NBTTagCompound nbt)
    {
        super.writeToNBT(nbt);
        nbt.setInteger("facing", facing);
        nbt.setIntArray("sides", sides);
        nbt.setInteger("charge", charge);
        energyStorage.writeToNBT(nbt);
        //LogHelper.info("Writing to NBT");
    }

    @Override
    public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt)
    {
        //LogHelper.info("Receiving Packet");
        this.readFromNBT(pkt.func_148857_g());
        worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
    }

    @Override
    public Packet getDescriptionPacket()
    {
        //LogHelper.info("Sending Packet");
        NBTTagCompound nbttagcompound = new NBTTagCompound();
        this.writeToNBT(nbttagcompound);
        return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, 3, nbttagcompound);
    }
}