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        private List<ModContainer> immutableMods;
041    
042        public ModSorter(List<ModContainer> modList, Map<String, ModContainer> nameLookup)
043        {
044            buildGraph(modList, nameLookup);
045        }
046    
047        private void buildGraph(List<ModContainer> modList, Map<String, ModContainer> nameLookup)
048        {
049            modGraph = new DirectedGraph<ModContainer>();
050            immutableMods = Lists.newArrayList();
051            modGraph.addNode(beforeAll);
052            modGraph.addNode(before);
053            modGraph.addNode(afterAll);
054            modGraph.addNode(after);
055            modGraph.addEdge(before, after);
056            modGraph.addEdge(beforeAll, before);
057            modGraph.addEdge(after, afterAll);
058    
059            for (ModContainer mod : modList)
060            {
061                if (!mod.isImmutable())
062                {
063                    modGraph.addNode(mod);
064                }
065                else
066                {
067                    immutableMods.add(mod);
068                }
069            }
070    
071            for (ModContainer mod : modList)
072            {
073                if (mod.isImmutable())
074                    continue;
075                boolean preDepAdded = false;
076                boolean postDepAdded = false;
077    
078                for (ArtifactVersion dep : mod.getDependencies())
079                {
080                    preDepAdded = true;
081    
082                    String modid = dep.getLabel();
083                    if (modid.equals("*"))
084                    {
085                        // We are "after" everything
086                        modGraph.addEdge(mod, afterAll);
087                        modGraph.addEdge(after, mod);
088                        postDepAdded = true;
089                    }
090                    else
091                    {
092                        modGraph.addEdge(before, mod);
093                        if (Loader.isModLoaded(modid)) {
094                            modGraph.addEdge(nameLookup.get(modid), mod);
095                        }
096                    }
097                }
098    
099                for (ArtifactVersion dep : mod.getDependants())
100                {
101                    postDepAdded = true;
102    
103                    String modid = dep.getLabel();
104                    if (modid.equals("*"))
105                    {
106                        // We are "before" everything
107                        modGraph.addEdge(beforeAll, mod);
108                        modGraph.addEdge(mod, before);
109                        preDepAdded = true;
110                    }
111                    else
112                    {
113                        modGraph.addEdge(mod, after);
114                        if (Loader.isModLoaded(modid)) {
115                            modGraph.addEdge(mod, nameLookup.get(modid));
116                        }
117                    }
118                }
119    
120                if (!preDepAdded)
121                {
122                    modGraph.addEdge(before, mod);
123                }
124    
125                if (!postDepAdded)
126                {
127                    modGraph.addEdge(mod, after);
128                }
129            }
130        }
131    
132        public List<ModContainer> sort()
133        {
134            List<ModContainer> sortedList = TopologicalSort.topologicalSort(modGraph);
135            sortedList.removeAll(Arrays.asList(new ModContainer[] {beforeAll, before, after, afterAll}));
136            immutableMods.addAll(sortedList);
137            return immutableMods;
138        }
139    }