package client.renderer.texture;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

import common.collect.Lists;
import common.collect.Sets;

public class Stitcher
{
    private final Set<Stitcher.Holder> holders = Sets.<Stitcher.Holder>newHashSetWithExpectedSize(256);
    private final List<Stitcher.Slot> slots = new ArrayList<Slot>(256);
    
    private int currentWidth;
    private int currentHeight;
    
	private static int roundUpToPowerOfTwo(int value) {
	    int i = value - 1;
	    i = i | i >> 1;
	    i = i | i >> 2;
	    i = i | i >> 4;
	    i = i | i >> 8;
	    i = i | i >> 16;
	    return i + 1;
	}

    public int getCurrentWidth()
    {
        return this.currentWidth;
    }

    public int getCurrentHeight()
    {
        return this.currentHeight;
    }

    public void addSprite(Sprite p_110934_1_)
    {
        Stitcher.Holder stitcher$holder = new Stitcher.Holder(p_110934_1_);
        this.holders.add(stitcher$holder);
    }

    public void doStitch()
    {
        Stitcher.Holder[] astitcher$holder = (Stitcher.Holder[])this.holders.toArray(new Stitcher.Holder[this.holders.size()]);
        Arrays.sort((Object[])astitcher$holder);

        for (Stitcher.Holder stitcher$holder : astitcher$holder)
        {
            this.allocateSlot(stitcher$holder);
        }

        this.currentWidth = roundUpToPowerOfTwo(this.currentWidth);
        this.currentHeight = roundUpToPowerOfTwo(this.currentHeight);
    }

    public List<Sprite> getStichSlots()
    {
        List<Stitcher.Slot> list = Lists.<Stitcher.Slot>newArrayList();

        for (Stitcher.Slot stitcher$slot : this.slots)
        {
            stitcher$slot.getAllStitchSlots(list);
        }

        List<Sprite> list1 = Lists.<Sprite>newArrayList();

        for (Stitcher.Slot stitcher$slot1 : list)
        {
            Stitcher.Holder stitcher$holder = stitcher$slot1.getStitchHolder();
            Sprite textureatlassprite = stitcher$holder.getAtlasSprite();
            textureatlassprite.initSprite(this.currentWidth, this.currentHeight, stitcher$slot1.getOriginX(), stitcher$slot1.getOriginY(), stitcher$holder.isRotated());
            list1.add(textureatlassprite);
        }

        return list1;
    }

    private void allocateSlot(Stitcher.Holder p_94310_1_)
    {
        for (int i = 0; i < this.slots.size(); ++i)
        {
            if (((Stitcher.Slot)this.slots.get(i)).addSlot(p_94310_1_))
            {
                return;
            }

            p_94310_1_.rotate();

            if (((Stitcher.Slot)this.slots.get(i)).addSlot(p_94310_1_))
            {
                return;
            }

            p_94310_1_.rotate();
        }

        this.expandAndAllocateSlot(p_94310_1_);
    }

    private void expandAndAllocateSlot(Stitcher.Holder p_94311_1_)
    {
        int i = Math.min(p_94311_1_.getWidth(), p_94311_1_.getHeight());
        boolean flag = this.currentWidth == 0 && this.currentHeight == 0;
        boolean flag1;

        int j = roundUpToPowerOfTwo(this.currentWidth);
        int k = roundUpToPowerOfTwo(this.currentHeight);
        int l = roundUpToPowerOfTwo(this.currentWidth + i);
        int i1 = roundUpToPowerOfTwo(this.currentHeight + i);

        boolean flag4 = j != l;
        boolean flag5 = k != i1;

        if (flag4 ^ flag5)
        {
            flag1 = !flag4;
        }
        else
        {
            flag1 = j <= k;
        }
        Stitcher.Slot stitcher$slot;

        if (flag1)
        {
            if (p_94311_1_.getWidth() > p_94311_1_.getHeight())
            {
                p_94311_1_.rotate();
            }

            if (this.currentHeight == 0)
            {
                this.currentHeight = p_94311_1_.getHeight();
            }

            stitcher$slot = new Stitcher.Slot(this.currentWidth, 0, p_94311_1_.getWidth(), this.currentHeight);
            this.currentWidth += p_94311_1_.getWidth();
        }
        else
        {
            stitcher$slot = new Stitcher.Slot(0, this.currentHeight, this.currentWidth, p_94311_1_.getHeight());
            this.currentHeight += p_94311_1_.getHeight();
        }

        stitcher$slot.addSlot(p_94311_1_);
        this.slots.add(stitcher$slot);
    }

	public static class Holder implements Comparable<Stitcher.Holder>
    {
        private final Sprite theTexture;
        private final int width;
        private final int height;
        private boolean rotated;
        private float scaleFactor = 1.0F;

        public Holder(Sprite p_i45094_1_)
        {
            this.theTexture = p_i45094_1_;
            this.width = p_i45094_1_.getIconWidth();
            this.height = p_i45094_1_.getIconHeight();
            this.rotated = this.height > this.width;
        }

        public Sprite getAtlasSprite()
        {
            return this.theTexture;
        }

        public int getWidth()
        {
            return this.rotated ? (int)((float)this.height * this.scaleFactor) : (int)((float)this.width * this.scaleFactor);
        }

        public int getHeight()
        {
            return this.rotated ? (int)((float)this.width * this.scaleFactor) : (int)((float)this.height * this.scaleFactor);
        }

        public void rotate()
        {
            this.rotated = !this.rotated;
        }

        public boolean isRotated()
        {
            return this.rotated;
        }

        public void setNewDimension(int p_94196_1_)
        {
            if (this.width > p_94196_1_ && this.height > p_94196_1_)
            {
                this.scaleFactor = (float)p_94196_1_ / (float)Math.min(this.width, this.height);
            }
        }

        public int compareTo(Stitcher.Holder p_compareTo_1_)
        {
            int i;

            if (this.getHeight() == p_compareTo_1_.getHeight())
            {
                if (this.getWidth() == p_compareTo_1_.getWidth())
                {
                    if (this.theTexture.getIconName() == null)
                    {
                        return p_compareTo_1_.theTexture.getIconName() == null ? 0 : -1;
                    }

                    return this.theTexture.getIconName().compareTo(p_compareTo_1_.theTexture.getIconName());
                }

                i = this.getWidth() < p_compareTo_1_.getWidth() ? 1 : -1;
            }
            else
            {
                i = this.getHeight() < p_compareTo_1_.getHeight() ? 1 : -1;
            }

            return i;
        }
    }

    public static class Slot
    {
        private final int originX;
        private final int originY;
        private final int width;
        private final int height;
        private List<Stitcher.Slot> subSlots;
        private Stitcher.Holder holder;

        public Slot(int p_i1277_1_, int p_i1277_2_, int widthIn, int heightIn)
        {
            this.originX = p_i1277_1_;
            this.originY = p_i1277_2_;
            this.width = widthIn;
            this.height = heightIn;
        }

        public Stitcher.Holder getStitchHolder()
        {
            return this.holder;
        }

        public int getOriginX()
        {
            return this.originX;
        }

        public int getOriginY()
        {
            return this.originY;
        }

        public boolean addSlot(Stitcher.Holder holderIn)
        {
            if (this.holder != null)
            {
                return false;
            }
            else
            {
                int i = holderIn.getWidth();
                int j = holderIn.getHeight();

                if (i <= this.width && j <= this.height)
                {
                    if (i == this.width && j == this.height)
                    {
                        this.holder = holderIn;
                        return true;
                    }
                    else
                    {
                        if (this.subSlots == null)
                        {
                            this.subSlots = new ArrayList<Slot>(1);
                            this.subSlots.add(new Stitcher.Slot(this.originX, this.originY, i, j));
                            int k = this.width - i;
                            int l = this.height - j;

                            if (l > 0 && k > 0)
                            {
                                int i1 = Math.max(this.height, k);
                                int j1 = Math.max(this.width, l);

                                if (i1 >= j1)
                                {
                                    this.subSlots.add(new Stitcher.Slot(this.originX, this.originY + j, i, l));
                                    this.subSlots.add(new Stitcher.Slot(this.originX + i, this.originY, k, this.height));
                                }
                                else
                                {
                                    this.subSlots.add(new Stitcher.Slot(this.originX + i, this.originY, k, j));
                                    this.subSlots.add(new Stitcher.Slot(this.originX, this.originY + j, this.width, l));
                                }
                            }
                            else if (k == 0)
                            {
                                this.subSlots.add(new Stitcher.Slot(this.originX, this.originY + j, i, l));
                            }
                            else if (l == 0)
                            {
                                this.subSlots.add(new Stitcher.Slot(this.originX + i, this.originY, k, j));
                            }
                        }

                        for (Stitcher.Slot stitcher$slot : this.subSlots)
                        {
                            if (stitcher$slot.addSlot(holderIn))
                            {
                                return true;
                            }
                        }

                        return false;
                    }
                }
                else
                {
                    return false;
                }
            }
        }

        public void getAllStitchSlots(List<Stitcher.Slot> p_94184_1_)
        {
            if (this.holder != null)
            {
                p_94184_1_.add(this);
            }
            else if (this.subSlots != null)
            {
                for (Stitcher.Slot stitcher$slot : this.subSlots)
                {
                    stitcher$slot.getAllStitchSlots(p_94184_1_);
                }
            }
        }
    }
}
