package client.renderer.chunk;

import java.util.BitSet;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;

import common.util.BlockPos;
import common.util.Facing;

public class VisGraph
{
    private static final int field_178616_a = (int)Math.pow(16.0D, 0.0D);
    private static final int field_178614_b = (int)Math.pow(16.0D, 1.0D);
    private static final int field_178615_c = (int)Math.pow(16.0D, 2.0D);
    private final BitSet field_178612_d = new BitSet(4096);
    private static final int[] field_178613_e = new int[1352];
    private static final Integer[] INTEGERS = new Integer[65535];
    
    private int field_178611_f = 4096;
    
    static {
        for(int z = 0; z < INTEGERS.length; z++) {
            INTEGERS[z] = z;
        }
    }

    public void func_178606_a(BlockPos pos)
    {
        this.field_178612_d.set(getIndex(pos), true);
        --this.field_178611_f;
    }

    private static int getIndex(BlockPos pos)
    {
        return getIndex(pos.getX() & 15, pos.getY() & 15, pos.getZ() & 15);
    }

    private static int getIndex(int x, int y, int z)
    {
        return x << 0 | y << 8 | z << 4;
    }

    public SetVisibility computeVisibility()
    {
        SetVisibility setvisibility = new SetVisibility();

        if (4096 - this.field_178611_f < 256)
        {
            setvisibility.setAllVisible(true);
        }
        else if (this.field_178611_f == 0)
        {
            setvisibility.setAllVisible(false);
        }
        else
        {
            for (int i : field_178613_e)
            {
                if (!this.field_178612_d.get(i))
                {
                    setvisibility.setManyVisible(this.func_178604_a(i));
                }
            }
        }

        return setvisibility;
    }

    public Set<Facing> func_178609_b(BlockPos pos)
    {
        return this.func_178604_a(getIndex(pos));
    }

    private Set<Facing> func_178604_a(int p_178604_1_)
    {
        Set<Facing> set = EnumSet.<Facing>noneOf(Facing.class);
        Queue<Integer> queue = new LinkedList<Integer>();
        queue.add(p_178604_1_ > 0 && p_178604_1_ < INTEGERS.length ? INTEGERS[p_178604_1_] : p_178604_1_);
        this.field_178612_d.set(p_178604_1_, true);

        while (!((Queue)queue).isEmpty())
        {
            int i = ((Integer)queue.poll()).intValue();
            this.func_178610_a(i, set);

            for (Facing enumfacing : Facing.values())
            {
                int j = this.func_178603_a(i, enumfacing);

                if (j >= 0 && !this.field_178612_d.get(j))
                {
                    this.field_178612_d.set(j, true);
                    queue.add(j > 0 && j < INTEGERS.length ? INTEGERS[j] : j);
                }
            }
        }

        return set;
    }

    private void func_178610_a(int p_178610_1_, Set<Facing> p_178610_2_)
    {
        int i = p_178610_1_ >> 0 & 15;

        if (i == 0)
        {
            p_178610_2_.add(Facing.WEST);
        }
        else if (i == 15)
        {
            p_178610_2_.add(Facing.EAST);
        }

        int j = p_178610_1_ >> 8 & 15;

        if (j == 0)
        {
            p_178610_2_.add(Facing.DOWN);
        }
        else if (j == 15)
        {
            p_178610_2_.add(Facing.UP);
        }

        int k = p_178610_1_ >> 4 & 15;

        if (k == 0)
        {
            p_178610_2_.add(Facing.NORTH);
        }
        else if (k == 15)
        {
            p_178610_2_.add(Facing.SOUTH);
        }
    }

    private int func_178603_a(int p_178603_1_, Facing p_178603_2_)
    {
        switch (p_178603_2_)
        {
            case DOWN:
                if ((p_178603_1_ >> 8 & 15) == 0)
                {
                    return -1;
                }

                return p_178603_1_ - field_178615_c;

            case UP:
                if ((p_178603_1_ >> 8 & 15) == 15)
                {
                    return -1;
                }

                return p_178603_1_ + field_178615_c;

            case NORTH:
                if ((p_178603_1_ >> 4 & 15) == 0)
                {
                    return -1;
                }

                return p_178603_1_ - field_178614_b;

            case SOUTH:
                if ((p_178603_1_ >> 4 & 15) == 15)
                {
                    return -1;
                }

                return p_178603_1_ + field_178614_b;

            case WEST:
                if ((p_178603_1_ >> 0 & 15) == 0)
                {
                    return -1;
                }

                return p_178603_1_ - field_178616_a;

            case EAST:
                if ((p_178603_1_ >> 0 & 15) == 15)
                {
                    return -1;
                }

                return p_178603_1_ + field_178616_a;

            default:
                return -1;
        }
    }

    static
    {
        int i = 0;
        int j = 15;
        int k = 0;

        for (int l = 0; l < 16; ++l)
        {
            for (int i1 = 0; i1 < 16; ++i1)
            {
                for (int j1 = 0; j1 < 16; ++j1)
                {
                    if (l == 0 || l == 15 || i1 == 0 || i1 == 15 || j1 == 0 || j1 == 15)
                    {
                        field_178613_e[k++] = getIndex(l, i1, j1);
                    }
                }
            }
        }
    }
}
