    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}