/**
 * @(#)Box.java
 * @author JLMJ
 * @date 2001-10-10
 */
package minoids1;

public final class Box
{
    private static final int BOUNDING_WALLS = 6;
    
    private int x, y, z;
    private int minOrder, maxOrder;
    
    private Minoid[] minoids;
    private Bits[] boundingWallsCheckersBits;
    private Bits[] anyConnectionsBits;
    private Bits[] hardConnectionsBits;
    private Bits[] softConnectionsBits;
    
    public Box(int x, int y, int z) {
        minoids = Minoid.getBoxMinoids(x, y, z);
        if (minoids != null) {
            this.x = x;
            this.y = y;
            this.z = z;
            minOrder = x + y + z - 1;
            maxOrder = x*y*(z+1) + x*(y+1)*z + (x+1)*y*z;
            setBoundingWallsCheckersBits();
            setAnyConnectionsBits();
            setHardConnectionsBits();
            setSoftConnectionsBits();
        }
    }
    
    public Minoid[] getMinoids() {
        return minoids;
    }
    
    private void setBoundingWallsCheckersBits() {
        boundingWallsCheckersBits = new Bits[BOUNDING_WALLS];
        for (int i=0; i < boundingWallsCheckersBits.length; i++) {
            boundingWallsCheckersBits[i] = new Bits(maxOrder, 0);
        }
        for (int i=0; i < maxOrder; i++) {
            int width = minoids[i].getX();
            if (width < 2)
                boundingWallsCheckersBits[0].setBit(i);
            if (width > (2*x - 2))
                boundingWallsCheckersBits[1].setBit(i);
            
            int depth = minoids[i].getY();
            if (depth < 2)
                boundingWallsCheckersBits[2].setBit(i);
            if (depth > (2*y - 2))
                boundingWallsCheckersBits[3].setBit(i);
            
            int height = minoids[i].getZ();
            if (height < 2)
                boundingWallsCheckersBits[4].setBit(i);
            if (height > (2*z - 2))
                boundingWallsCheckersBits[5].setBit(i);
        }
    }
    
    private void setAnyConnectionsBits() {
        anyConnectionsBits = new Bits[maxOrder];
        for (int i=0; i < maxOrder; i++)
            anyConnectionsBits[i] = new Bits(maxOrder, 0);
        for (int i=0; i < maxOrder; i++)
            for (int j=0; j < maxOrder; j++)
                if (minoids[i].isAnyConnected(minoids[j]))
                    anyConnectionsBits[j].setBit(i);
    }
    
    private void setHardConnectionsBits() {
        hardConnectionsBits = new Bits[maxOrder];
        for (int i=0; i < maxOrder; i++)
            hardConnectionsBits[i] = new Bits(maxOrder, 0);
        for (int i=0; i < maxOrder; i++)
            for (int j=0; j < maxOrder; j++)
                if (minoids[i].isHardConnected(minoids[j]))
                    hardConnectionsBits[j].setBit(i);
    }
    
    private void setSoftConnectionsBits() {
        softConnectionsBits = new Bits[maxOrder];
        for (int i=0; i < maxOrder; i++)
            softConnectionsBits[i] = new Bits(maxOrder, 0);
        for (int i=0; i < maxOrder; i++)
            for (int j=0; j < maxOrder; j++)
                if (minoids[i].isSoftConnected(minoids[j]))
                    softConnectionsBits[j].setBit(i);
    }
    
    public int getMinOrder() {
        return minOrder;
    }
    
    public int getMaxOrder() {
        return maxOrder;
    }

    public Bits[] getBoundingWallsCheckersBits() {
        return boundingWallsCheckersBits;
    }
    
    public Bits[] getAnyConnectionsBits() {
        return anyConnectionsBits;
    }
    
    public Bits[] getHardConnectionsBits() {
        return hardConnectionsBits;
    }
    
    public Bits[] getSoftConnectionsBits() {
        return softConnectionsBits;
    }
    
    public int getX() {
        return x;
    }
    
    public int getY() {
        return y;
    }
    
    public int getZ() {
        return z;
    }
    
    public String toString() {
        return "Box (" + x + ", " + y + ", " + z +
            "), minOrder=" + minOrder + ", maxOrder=" + maxOrder;
    }
    
    public String toShortString() {
        return "(" + x + ", " + y + ", " + z + ")";
    }
    
    public static Box[] getAllTranslationsBoxes(int order) {
        int x, y, z, total, count = 0;
        Box[] boxes = null;
        for (boolean counting = true; true; counting = false) {
            for (x=0; x <= order; x++) {
                for (y=0; y <= order; y++) {
                    for (z=0; z <= order; z++) {
                        total = x*y*(z+1) + x*(y+1)*z + (x+1)*y*z;
                        if (total >= order && (x+y+z) <= (order + 1)) {
                            if (counting)
                                count++;
                            else
                                boxes[count++] = new Box(x, y, z);
                        }
                    }
                }
            }
            if (counting)
                boxes = new Box[count];
            else
                return boxes;
            count = 0;
        }
    }
    
    public static Box[] getAllRotationsBoxes(int order) {
        int x, y, z, total, count = 0;
        Box[] boxes = null;
        for (boolean counting = true; true; counting = false) {
            for (x=0; x <= order; x++) {
                for (y=x; y <= order; y++) {
                    for (z=y; z <= order; z++) {
                        total = x*y*(z+1) + x*(y+1)*z + (x+1)*y*z;
                        if (total >= order && (x+y+z) <= (order + 1)) {
                            if (counting)
                                count++;
                            else
                                boxes[count++] = new Box(x, y, z);
                        }
                    }
                }
            }
            if (counting)
                boxes = new Box[count];
            else
                return boxes;
            count = 0;
        }
    }
    
    public static Box[] getAllRotationsRectangles(int order) {
        int x, y, z, total, count = 0;
        Box[] boxes = null;
        for (boolean counting = true; true; counting = false) {
            x = 0;
            for (y=x; y <= order; y++) {
                for (z=y; z <= order; z++) {
                    total = x*y*(z+1) + x*(y+1)*z + (x+1)*y*z;
                    if (total >= order && (x+y+z) <= (order + 1)) {
                        if (counting)
                            count++;
                        else
                            boxes[count++] = new Box(x, y, z);
                    }
                }
            }
            if (counting)
                boxes = new Box[count];
            else
                return boxes;
            count = 0;
        }
    }

    public int getNumberOfRotations() {
        if (x == y)
            return (y == z) ? 1 : 3;
        else
            return (x == z) ? 3 : (y == z) ? 3 : 6;
    }
}

