001package net.minecraftforge.event;
002
003import java.util.*;
004
005
006public class ListenerList
007{
008    private static ArrayList<ListenerList> allLists = new ArrayList<ListenerList>();
009    private static int maxSize = 0;
010    
011    private ListenerList parent;
012    private ListenerListInst[] lists = new ListenerListInst[0];
013    
014    public ListenerList()
015    {
016        allLists.add(this);
017        resizeLists(maxSize);
018    }
019    
020    public ListenerList(ListenerList parent)
021    {
022        allLists.add(this);
023        this.parent = parent;
024        resizeLists(maxSize);
025    }
026    
027    public static void resize(int max)
028    {
029        if (max <= maxSize)
030        {
031            return;
032        }
033        for (ListenerList list : allLists)
034        {
035            list.resizeLists(max);
036        }
037        maxSize = max;
038    }
039    
040    public void resizeLists(int max)
041    {
042        if (parent != null)
043        {
044            parent.resizeLists(max);
045        }
046        
047        if (lists.length >= max)
048        {
049            return;
050        }
051        
052        ListenerListInst[] newList = new ListenerListInst[max];
053        int x = 0;
054        for (; x < lists.length; x++)
055        {
056            newList[x] = lists[x];
057        }
058        for(; x < max; x++)
059        {
060            if (parent != null)
061            {
062                newList[x] = new ListenerListInst(parent.getInstance(x));
063            }
064            else
065            {
066                newList[x] = new ListenerListInst();
067            }
068        }
069        lists = newList;
070    }
071    
072    public static void clearBusID(int id)
073    {
074        for (ListenerList list : allLists)
075        {
076            list.lists[id].dispose();
077        }
078    }
079    
080    protected ListenerListInst getInstance(int id)
081    {
082        return lists[id];
083    }
084
085    public IEventListener[] getListeners(int id)
086    {
087        return lists[id].getListeners();
088    }
089    
090    public void register(int id, EventPriority priority, IEventListener listener)
091    {
092        lists[id].register(priority, listener);
093    }
094    
095    public void unregister(int id, IEventListener listener)
096    {
097        lists[id].unregister(listener);
098    }
099    
100    public static void unregiterAll(int id, IEventListener listener)
101    {
102        for (ListenerList list : allLists)
103        {
104            list.unregister(id, listener);
105        }
106    }
107    
108    private class ListenerListInst
109    {
110        private boolean rebuild = true;
111        private IEventListener[] listeners;
112        private ArrayList<ArrayList<IEventListener>> priorities;
113        private ListenerListInst parent;
114        
115        private ListenerListInst()
116        {
117            int count = EventPriority.values().length;
118            priorities = new ArrayList<ArrayList<IEventListener>>(count);
119            
120            for (int x = 0; x < count; x++)
121            {
122                priorities.add(new ArrayList<IEventListener>());
123            }
124        }
125        
126        public void dispose()
127        {
128            for (ArrayList<IEventListener> listeners : priorities)
129            {
130                listeners.clear();
131            }
132            priorities.clear();
133            parent = null;
134            listeners = null;
135        }
136
137        private ListenerListInst(ListenerListInst parent)
138        {
139            this();
140            this.parent = parent;
141        }
142        
143        /**
144         * Returns a ArrayList containing all listeners for this event, 
145         * and all parent events for the specified priority.
146         * 
147         * The list is returned with the listeners for the children events first.
148         * 
149         * @param priority The Priority to get
150         * @return ArrayList containing listeners
151         */
152        public ArrayList<IEventListener> getListeners(EventPriority priority)
153        {
154            ArrayList<IEventListener> ret = new ArrayList<IEventListener>(priorities.get(priority.ordinal()));
155            if (parent != null)
156            {
157                ret.addAll(parent.getListeners(priority));
158            }
159            return ret;
160        }
161        
162        /**
163         * Returns a full list of all listeners for all priority levels.
164         * Including all parent listeners.
165         * 
166         * List is returned in proper priority order.
167         * 
168         * Automatically rebuilds the internal Array cache if its information is out of date.
169         * 
170         * @return Array containing listeners
171         */
172        public IEventListener[] getListeners()
173        {
174            if (shouldRebuild()) buildCache();
175            return listeners;
176        }
177        
178        protected boolean shouldRebuild()
179        {
180            return rebuild || (parent != null && parent.shouldRebuild());
181        }
182        
183        /**
184         * Rebuild the local Array of listeners, returns early if there is no work to do.
185         */
186        private void buildCache()
187        {        
188            if(parent != null && parent.shouldRebuild())
189            {
190                parent.buildCache();
191            }
192            
193            ArrayList<IEventListener> ret = new ArrayList<IEventListener>();
194            for (EventPriority value : EventPriority.values())
195            {
196                ret.addAll(getListeners(value));
197            }
198            listeners = ret.toArray(new IEventListener[ret.size()]);
199            rebuild = false;
200        }
201        
202        public void register(EventPriority priority, IEventListener listener)
203        {
204            priorities.get(priority.ordinal()).add(listener);
205            rebuild = true;
206        }
207        
208        public void unregister(IEventListener listener)
209        {
210            for(ArrayList<IEventListener> list : priorities)
211            {
212                if (list.remove(listener))
213                {
214                    rebuild = true;
215                }
216            }
217        }
218    }
219}