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 */
013package cpw.mods.fml.common.toposort;
014
015import java.util.Arrays;
016import java.util.List;
017import java.util.Map;
018
019import com.google.common.collect.Lists;
020
021import cpw.mods.fml.common.DummyModContainer;
022import cpw.mods.fml.common.Loader;
023import cpw.mods.fml.common.ModContainer;
024import cpw.mods.fml.common.toposort.TopologicalSort.DirectedGraph;
025import cpw.mods.fml.common.versioning.ArtifactVersion;
026
027/**
028 * @author cpw
029 *
030 */
031public 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}