package net.minecraft.village;

import com.google.common.collect.Lists;
import java.util.Iterator;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.block.BlockDoor;
import net.minecraft.block.material.Material;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.world.World;
import net.minecraft.world.WorldProvider;
import net.minecraft.world.WorldSavedData;

public class VillageCollection extends WorldSavedData
{
    private World worldObj;
    /**
     * This is a black hole. You can add data to this list through a public interface, but you can't query that
     * information in any way and it's not used internally either.
     */
    private final List villagerPositionsList = Lists.newArrayList();
    private final List newDoors = Lists.newArrayList();
    private final List villageList = Lists.newArrayList();
    private int tickCounter;
    private static final String __OBFID = "CL_00001635";

    public VillageCollection(String p_i1677_1_)
    {
        super(p_i1677_1_);
    }

    public VillageCollection(World worldIn)
    {
        super(func_176062_a(worldIn.provider));
        this.worldObj = worldIn;
        this.markDirty();
    }

    public void func_82566_a(World worldIn)
    {
        this.worldObj = worldIn;
        Iterator iterator = this.villageList.iterator();

        while (iterator.hasNext())
        {
            Village village = (Village)iterator.next();
            village.func_82691_a(worldIn);
        }
    }

    public void func_176060_a(BlockPos p_176060_1_)
    {
        if (this.villagerPositionsList.size() <= 64)
        {
            if (!this.func_176057_e(p_176060_1_))
            {
                this.villagerPositionsList.add(p_176060_1_);
            }
        }
    }

    /**
     * Runs a single tick for the village collection
     */
    public void tick()
    {
        ++this.tickCounter;
        Iterator iterator = this.villageList.iterator();

        while (iterator.hasNext())
        {
            Village village = (Village)iterator.next();
            village.tick(this.tickCounter);
        }

        this.removeAnnihilatedVillages();
        this.dropOldestVillagerPosition();
        this.addNewDoorsToVillageOrCreateVillage();

        if (this.tickCounter % 400 == 0)
        {
            this.markDirty();
        }
    }

    private void removeAnnihilatedVillages()
    {
        Iterator iterator = this.villageList.iterator();

        while (iterator.hasNext())
        {
            Village village = (Village)iterator.next();

            if (village.isAnnihilated())
            {
                iterator.remove();
                this.markDirty();
            }
        }
    }

    /**
     * Get a list of villages.
     */
    public List getVillageList()
    {
        return this.villageList;
    }

    public Village func_176056_a(BlockPos p_176056_1_, int p_176056_2_)
    {
        Village village = null;
        double d0 = 3.4028234663852886E38D;
        Iterator iterator = this.villageList.iterator();

        while (iterator.hasNext())
        {
            Village village1 = (Village)iterator.next();
            double d1 = village1.func_180608_a().distanceSq(p_176056_1_);

            if (d1 < d0)
            {
                float f = (float)(p_176056_2_ + village1.getVillageRadius());

                if (d1 <= (double)(f * f))
                {
                    village = village1;
                    d0 = d1;
                }
            }
        }

        return village;
    }

    private void dropOldestVillagerPosition()
    {
        if (!this.villagerPositionsList.isEmpty())
        {
            this.func_180609_b((BlockPos)this.villagerPositionsList.remove(0));
        }
    }

    private void addNewDoorsToVillageOrCreateVillage()
    {
        for (int i = 0; i < this.newDoors.size(); ++i)
        {
            VillageDoorInfo villagedoorinfo = (VillageDoorInfo)this.newDoors.get(i);
            Village village = this.func_176056_a(villagedoorinfo.func_179852_d(), 32);

            if (village == null)
            {
                village = new Village(this.worldObj);
                this.villageList.add(village);
                this.markDirty();
            }

            village.addVillageDoorInfo(villagedoorinfo);
        }

        this.newDoors.clear();
    }

    private void func_180609_b(BlockPos p_180609_1_)
    {
        byte b0 = 16;
        byte b1 = 4;
        byte b2 = 16;

        for (int i = -b0; i < b0; ++i)
        {
            for (int j = -b1; j < b1; ++j)
            {
                for (int k = -b2; k < b2; ++k)
                {
                    BlockPos blockpos1 = p_180609_1_.add(i, j, k);

                    if (this.func_176058_f(blockpos1))
                    {
                        VillageDoorInfo villagedoorinfo = this.func_176055_c(blockpos1);

                        if (villagedoorinfo == null)
                        {
                            this.func_176059_d(blockpos1);
                        }
                        else
                        {
                            villagedoorinfo.func_179849_a(this.tickCounter);
                        }
                    }
                }
            }
        }
    }

    private VillageDoorInfo func_176055_c(BlockPos p_176055_1_)
    {
        Iterator iterator = this.newDoors.iterator();
        VillageDoorInfo villagedoorinfo;

        do
        {
            if (!iterator.hasNext())
            {
                iterator = this.villageList.iterator();
                VillageDoorInfo villagedoorinfo1;

                do
                {
                    if (!iterator.hasNext())
                    {
                        return null;
                    }

                    Village village = (Village)iterator.next();
                    villagedoorinfo1 = village.func_179864_e(p_176055_1_);
                }
                while (villagedoorinfo1 == null);

                return villagedoorinfo1;
            }

            villagedoorinfo = (VillageDoorInfo)iterator.next();
        }
        while (villagedoorinfo.func_179852_d().getX() != p_176055_1_.getX() || villagedoorinfo.func_179852_d().getZ() != p_176055_1_.getZ() || Math.abs(villagedoorinfo.func_179852_d().getY() - p_176055_1_.getY()) > 1);

        return villagedoorinfo;
    }

    private void func_176059_d(BlockPos p_176059_1_)
    {
        EnumFacing enumfacing = BlockDoor.func_176517_h(this.worldObj, p_176059_1_);
        EnumFacing enumfacing1 = enumfacing.getOpposite();
        int i = this.func_176061_a(p_176059_1_, enumfacing, 5);
        int j = this.func_176061_a(p_176059_1_, enumfacing1, i + 1);

        if (i != j)
        {
            this.newDoors.add(new VillageDoorInfo(p_176059_1_, i < j ? enumfacing : enumfacing1, this.tickCounter));
        }
    }

    private int func_176061_a(BlockPos p_176061_1_, EnumFacing p_176061_2_, int p_176061_3_)
    {
        int j = 0;

        for (int k = 1; k <= 5; ++k)
        {
            if (this.worldObj.canSeeSky(p_176061_1_.offset(p_176061_2_, k)))
            {
                ++j;

                if (j >= p_176061_3_)
                {
                    return j;
                }
            }
        }

        return j;
    }

    private boolean func_176057_e(BlockPos p_176057_1_)
    {
        Iterator iterator = this.villagerPositionsList.iterator();
        BlockPos blockpos1;

        do
        {
            if (!iterator.hasNext())
            {
                return false;
            }

            blockpos1 = (BlockPos)iterator.next();
        }
        while (!blockpos1.equals(p_176057_1_));

        return true;
    }

    private boolean func_176058_f(BlockPos p_176058_1_)
    {
        Block block = this.worldObj.getBlockState(p_176058_1_).getBlock();
        return block instanceof BlockDoor ? block.getMaterial() == Material.wood : false;
    }

    /**
     * reads in data from the NBTTagCompound into this MapDataBase
     */
    public void readFromNBT(NBTTagCompound nbt)
    {
        this.tickCounter = nbt.getInteger("Tick");
        NBTTagList nbttaglist = nbt.getTagList("Villages", 10);

        for (int i = 0; i < nbttaglist.tagCount(); ++i)
        {
            NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i);
            Village village = new Village();
            village.readVillageDataFromNBT(nbttagcompound1);
            this.villageList.add(village);
        }
    }

    /**
     * write data to NBTTagCompound from this MapDataBase, similar to Entities and TileEntities
     */
    public void writeToNBT(NBTTagCompound nbt)
    {
        nbt.setInteger("Tick", this.tickCounter);
        NBTTagList nbttaglist = new NBTTagList();
        Iterator iterator = this.villageList.iterator();

        while (iterator.hasNext())
        {
            Village village = (Village)iterator.next();
            NBTTagCompound nbttagcompound1 = new NBTTagCompound();
            village.writeVillageDataToNBT(nbttagcompound1);
            nbttaglist.appendTag(nbttagcompound1);
        }

        nbt.setTag("Villages", nbttaglist);
    }

    public static String func_176062_a(WorldProvider p_176062_0_)
    {
        return "villages" + p_176062_0_.getInternalNameSuffix();
    }
}