001    package org.bukkit.material;
002    
003    import java.util.Arrays;
004    import java.util.EnumSet;
005    
006    import org.bukkit.Material;
007    import org.bukkit.block.BlockFace;
008    
009    /**
010     * Represents a vine
011     */
012    public class Vine extends MaterialData {
013        private static final int VINE_NORTH = 0x4;
014        private static final int VINE_EAST = 0x8;
015        private static final int VINE_WEST = 0x2;
016        private static final int VINE_SOUTH = 0x1;
017        EnumSet<BlockFace> possibleFaces = EnumSet.of(BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST);
018    
019        public Vine() {
020            super(Material.VINE);
021        }
022    
023        /**
024         *
025         * @deprecated Magic value
026         */
027        @Deprecated
028        public Vine(int type, byte data){
029            super(type, data);
030        }
031    
032        /**
033         *
034         * @deprecated Magic value
035         */
036        @Deprecated
037        public Vine(byte data) {
038            super(Material.VINE, data);
039        }
040    
041        public Vine(BlockFace... faces) {
042            this(EnumSet.copyOf(Arrays.asList(faces)));
043        }
044    
045        public Vine(EnumSet<BlockFace> faces) {
046            this((byte) 0);
047            faces.retainAll(possibleFaces);
048    
049            byte data = 0;
050    
051            if (faces.contains(BlockFace.WEST)) {
052                data |= VINE_WEST;
053            }
054    
055            if (faces.contains(BlockFace.NORTH)) {
056                data |= VINE_NORTH;
057            }
058    
059            if (faces.contains(BlockFace.SOUTH)) {
060                data |= VINE_SOUTH;
061            }
062    
063            if (faces.contains(BlockFace.EAST)) {
064                data |= VINE_EAST;
065            }
066    
067            setData(data);
068        }
069    
070        /**
071         * Check if the vine is attached to the specified face of an adjacent
072         * block. You can check two faces at once by passing e.g. {@link
073         * BlockFace#NORTH_EAST}.
074         *
075         * @param face The face to check.
076         * @return Whether it is attached to that face.
077         */
078        public boolean isOnFace(BlockFace face) {
079            switch (face) {
080                case WEST:
081                    return (getData() & VINE_WEST) == VINE_WEST;
082                case NORTH:
083                    return (getData() & VINE_NORTH) == VINE_NORTH;
084                case SOUTH:
085                    return (getData() & VINE_SOUTH) == VINE_SOUTH;
086                case EAST:
087                    return (getData() & VINE_EAST) == VINE_EAST;
088                case NORTH_EAST:
089                    return isOnFace(BlockFace.EAST) && isOnFace(BlockFace.NORTH);
090                case NORTH_WEST:
091                    return isOnFace(BlockFace.WEST) && isOnFace(BlockFace.NORTH);
092                case SOUTH_EAST:
093                    return isOnFace(BlockFace.EAST) && isOnFace(BlockFace.SOUTH);
094                case SOUTH_WEST:
095                    return isOnFace(BlockFace.WEST) && isOnFace(BlockFace.SOUTH);
096                case UP: // It's impossible to be accurate with this since it's contextual
097                    return true;
098                default:
099                    return false;
100            }
101        }
102    
103        /**
104         * Attach the vine to the specified face of an adjacent block.
105         *
106         * @param face The face to attach.
107         */
108        public void putOnFace(BlockFace face) {
109            switch(face) {
110                case WEST:
111                    setData((byte) (getData() | VINE_WEST));
112                    break;
113                case NORTH:
114                    setData((byte) (getData() | VINE_NORTH));
115                    break;
116                case SOUTH:
117                    setData((byte) (getData() | VINE_SOUTH));
118                    break;
119                case EAST:
120                    setData((byte) (getData() | VINE_EAST));
121                    break;
122                case NORTH_WEST:
123                    putOnFace(BlockFace.WEST);
124                    putOnFace(BlockFace.NORTH);
125                    break;
126                case SOUTH_WEST:
127                    putOnFace(BlockFace.WEST);
128                    putOnFace(BlockFace.SOUTH);
129                    break;
130                case NORTH_EAST:
131                    putOnFace(BlockFace.EAST);
132                    putOnFace(BlockFace.NORTH);
133                    break;
134                case SOUTH_EAST:
135                    putOnFace(BlockFace.EAST);
136                    putOnFace(BlockFace.SOUTH);
137                    break;
138                case UP:
139                    break;
140                default:
141                    throw new IllegalArgumentException("Vines can't go on face " + face.toString());
142            }
143        }
144    
145        /**
146         * Detach the vine from the specified face of an adjacent block.
147         *
148         * @param face The face to detach.
149         */
150        public void removeFromFace(BlockFace face) {
151            switch(face) {
152                case WEST:
153                    setData((byte) (getData() & ~VINE_WEST));
154                    break;
155                case NORTH:
156                    setData((byte) (getData() & ~VINE_NORTH));
157                    break;
158                case SOUTH:
159                    setData((byte) (getData() & ~VINE_SOUTH));
160                    break;
161                case EAST:
162                    setData((byte) (getData() & ~VINE_EAST));
163                    break;
164                case NORTH_WEST:
165                    removeFromFace(BlockFace.WEST);
166                    removeFromFace(BlockFace.NORTH);
167                    break;
168                case SOUTH_WEST:
169                    removeFromFace(BlockFace.WEST);
170                    removeFromFace(BlockFace.SOUTH);
171                    break;
172                case NORTH_EAST:
173                    removeFromFace(BlockFace.EAST);
174                    removeFromFace(BlockFace.NORTH);
175                    break;
176                case SOUTH_EAST:
177                    removeFromFace(BlockFace.EAST);
178                    removeFromFace(BlockFace.SOUTH);
179                    break;
180                case UP:
181                    break;
182                default:
183                    throw new IllegalArgumentException("Vines can't go on face " + face.toString());
184            }
185        }
186    
187        @Override
188        public String toString() {
189            return "VINE";
190        }
191    
192        @Override
193        public Vine clone() {
194            return (Vine) super.clone();
195        }
196    }