001    /*
002     * The FML Forge Mod Loader suite. Copyright (C) 2012 cpw
003     *
004     * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
005     * Software Foundation; either version 2.1 of the License, or any later version.
006     *
007     * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
008     * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
009     *
010     * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51
011     * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
012     */
013    package cpw.mods.fml.common.toposort;
014    
015    import java.util.Arrays;
016    import java.util.List;
017    import java.util.Map;
018    
019    import com.google.common.collect.Lists;
020    
021    import cpw.mods.fml.common.DummyModContainer;
022    import cpw.mods.fml.common.Loader;
023    import cpw.mods.fml.common.ModContainer;
024    import cpw.mods.fml.common.toposort.TopologicalSort.DirectedGraph;
025    import cpw.mods.fml.common.versioning.ArtifactVersion;
026    
027    /**
028     * @author cpw
029     *
030     */
031    public class ModSorter
032    {
033        private DirectedGraph<ModContainer> modGraph;
034    
035        private ModContainer beforeAll = new DummyModContainer();
036        private ModContainer afterAll = new DummyModContainer();
037        private ModContainer before = new DummyModContainer();
038        private ModContainer after = new DummyModContainer();
039    
040        public ModSorter(List<ModContainer> modList, Map<String, ModContainer> nameLookup)
041        {
042            buildGraph(modList, nameLookup);
043        }
044    
045        private void buildGraph(List<ModContainer> modList, Map<String, ModContainer> nameLookup)
046        {
047            modGraph = new DirectedGraph<ModContainer>();
048            modGraph.addNode(beforeAll);
049            modGraph.addNode(before);
050            modGraph.addNode(afterAll);
051            modGraph.addNode(after);
052            modGraph.addEdge(before, after);
053            modGraph.addEdge(beforeAll, before);
054            modGraph.addEdge(after, afterAll);
055    
056            for (ModContainer mod : modList)
057            {
058                modGraph.addNode(mod);
059            }
060    
061            for (ModContainer mod : modList)
062            {
063                if (mod.isImmutable())
064                {
065                    // Immutable mods are always before everything
066                    modGraph.addEdge(beforeAll, mod);
067                    modGraph.addEdge(mod, before);
068                    continue;
069                }
070                boolean preDepAdded = false;
071                boolean postDepAdded = false;
072    
073                for (ArtifactVersion dep : mod.getDependencies())
074                {
075                    preDepAdded = true;
076    
077                    String modid = dep.getLabel();
078                    if (modid.equals("*"))
079                    {
080                        // We are "after" everything
081                        modGraph.addEdge(mod, afterAll);
082                        modGraph.addEdge(after, mod);
083                        postDepAdded = true;
084                    }
085                    else
086                    {
087                        modGraph.addEdge(before, mod);
088                        if (Loader.isModLoaded(modid)) {
089                            modGraph.addEdge(nameLookup.get(modid), mod);
090                        }
091                    }
092                }
093    
094                for (ArtifactVersion dep : mod.getDependants())
095                {
096                    postDepAdded = true;
097    
098                    String modid = dep.getLabel();
099                    if (modid.equals("*"))
100                    {
101                        // We are "before" everything
102                        modGraph.addEdge(beforeAll, mod);
103                        modGraph.addEdge(mod, before);
104                        preDepAdded = true;
105                    }
106                    else
107                    {
108                        modGraph.addEdge(mod, after);
109                        if (Loader.isModLoaded(modid)) {
110                            modGraph.addEdge(mod, nameLookup.get(modid));
111                        }
112                    }
113                }
114    
115                if (!preDepAdded)
116                {
117                    modGraph.addEdge(before, mod);
118                }
119    
120                if (!postDepAdded)
121                {
122                    modGraph.addEdge(mod, after);
123                }
124            }
125        }
126    
127        public List<ModContainer> sort()
128        {
129            List<ModContainer> sortedList = TopologicalSort.topologicalSort(modGraph);
130            sortedList.removeAll(Arrays.asList(new ModContainer[] {beforeAll, before, after, afterAll}));
131            return sortedList;
132        }
133    }