public static void Apply(AAProgram ast, FinalTransformations finalTrans)
        {
            //Build list of file dependacies
            Phase1 phase1 = new Phase1(finalTrans);
            ast.Apply(phase1);
            var dependancies = phase1.dependancies;
            if (dependancies.Keys.Count == 0) return;
            AASourceFile root = Util.GetAncestor<AASourceFile>(finalTrans.mainEntry) ??
                                dependancies.Keys.FirstOrDefault(file => !file.GetName().Text.Contains("\\")) ??
                                dependancies.Keys.First(file => true);

            //Remove files unreachable from root
            //On second thought, dont. there might be static refferences the other way which needs to be included
            /*{
                List<AASourceFile> reachable = GetReachable(root, dependancies);
                AASourceFile[] keys = new AASourceFile[dependancies.Count];
                dependancies.Keys.CopyTo(keys, 0);
                foreach (AASourceFile key in keys)
                {
                    if (!reachable.Contains(key))
                        dependancies.Remove(key);
                }
            }*/

            //Push common depancies up
            /*
             * root -> (item1 -> (item3), item2 -> (item4 -> (item3)))
             *
             * root -> (item3, item1, item2 -> (item4))
             */

            //Add unreachable to the root
            while (true)
            {
                List<AASourceFile> reachable = new List<AASourceFile>();
                GetReachable(root, dependancies, ref reachable);
                if (reachable.Count == dependancies.Count + (reachable.Contains(null) ? 1 : 0)) break;
                AASourceFile[] keys = new AASourceFile[dependancies.Count];
                dependancies.Keys.CopyTo(keys, 0);
                foreach (AASourceFile key in keys)
                {
                    if (!reachable.Contains(key))
                    {
                        AASourceFile k = key;
                        //See if you can find another unreachable file which need this file
                        Dictionary<AASourceFile, int> decendantCounts = new Dictionary<AASourceFile, int>();
                        decendantCounts.Add(k, CountDecendants(k, dependancies, new List<AASourceFile>()));
                        while (true)
                        {
                            AASourceFile file = null;
                            foreach (KeyValuePair<AASourceFile, List<AASourceFile>> dependancy in dependancies)
                            {
                                if (decendantCounts.ContainsKey(dependancy.Key))
                                    continue;
                                if (!dependancy.Value.Contains(k))
                                    continue;
                                file = dependancy.Key;
                                break;
                            }

                            //AASourceFile file = dependancies.FirstOrDefault(item => item.Value.Contains(k)).Key;
                            if (file == null) break;
                            decendantCounts.Add(file, CountDecendants(file, dependancies, new List<AASourceFile>()));
                            k = file;
                        }
                        foreach (KeyValuePair<AASourceFile, int> decendantItem in decendantCounts)
                        {
                            if (decendantItem.Value > decendantCounts[k])
                                k = decendantItem.Key;
                        }

                        dependancies[root].Add(k);
                        break;
                    }
                }
            }
            //It is moved down here because cycles are not removed in unreachable
            RemoveCycles(root, dependancies, new List<AASourceFile> { root });

            //Convert to tree to make it easier
            List<Item> allItems = new List<Item>();
            IncludeItem rootIncludeItem = MakeTree(root, dependancies, allItems, null);
            bool[] removed = new bool[allItems.Count];
            for (int i = 0; i < removed.Length; i++)
                removed[i] = false;
            int removedCount = 0;

            //Ensure that each include is only included one place
            for (int i = 0; i < allItems.Count; i++)
            {
                if (removed[i])
                    continue;

                IncludeItem item1 = (IncludeItem)allItems[i];
                for (int j = i + 1; j < allItems.Count; j++)
                {
                    if (removed[j])
                        continue;
                    IncludeItem item2 = (IncludeItem)allItems[j];

                    if (item1.Current == item2.Current)
                    {
                        List<Item> path1 = item1.Path;
                        List<Item> path2 = item2.Path;

                        for (int k = 0; k < Math.Min(path1.Count, path2.Count); k++)
                        {
                            if (path1[k] != path2[k])
                            {

                                int insertAt = Math.Min(path1[k - 1].Children.IndexOf(path1[k]),
                                                        path2[k - 1].Children.IndexOf(path2[k]));

                                item1.Parent.Children.Remove(item1);
                                LinkedList<IncludeItem> toRemove = new LinkedList<IncludeItem>();
                                toRemove.AddLast(item2);
                                while (toRemove.Count > 0)
                                {
                                    IncludeItem item = toRemove.First.Value;
                                    toRemove.RemoveFirst();
                                    item.Parent.Children.Remove(item);
                                    //allItems.Remove(item);
                                    removedCount++;
                                    removed[item.ListIndex] = true;
                                    foreach (IncludeItem child in item.Children)
                                    {
                                        toRemove.AddLast(child);
                                    }
                                }
                                //j--;

                                path1[k - 1].Children.Insert(insertAt, item1);
                                item1.Parent = path1[k - 1];

                                break;
                            }
                        }
                    }
                }
            }

            List<Item> newAllItems = new List<Item>(allItems.Count - removedCount);
            for (int i = 0; i < allItems.Count; i++)
                if (!removed[i])
                    newAllItems.Add(allItems[i]);
            allItems = newAllItems;

            //Move the null node to nr [0]
            foreach (IncludeItem item in allItems)
            {
                if (item.Current == null)
                {
                    int itemIndex = item.Parent.Children.IndexOf(item);
                    Item item0 = item.Parent.Children[0];
                    item.Parent.Children[0] = item;
                    item.Parent.Children[itemIndex] = item0;
                    break;
                }
            }

            //Insert method decls and move structs & fields up as needed
            ast.Apply(new Phase2(finalTrans, allItems));

            //Insert the headers in the files

            if (Options.Compiler.OneOutputFile)
            {
                //for (int i = 0; i < allItems.Count; i++)
                int i = 0;
                while (allItems.Count > 0)
                {
                    if (allItems[i] is IncludeItem)
                    {
                        IncludeItem includeItem = (IncludeItem) allItems[i];
                        //Dont want the standard lib
                        if (includeItem.Current == null)
                        {
                            i++;
                            continue;
                        }
                        //If it has children with children, then pick another first
                        if (includeItem.Children.Any(child => child.Children.Count > 0))
                        {
                            i++;
                            continue;
                        }
                        if (includeItem.Children.Count == 0)
                        {
                            if (includeItem.Parent == null)
                                break;
                            i++;
                            continue;
                        }
                        i = 0;
                        //Put all children into this
                        while (includeItem.Children.Count > 0)
                        {
                            int childNr = includeItem.Children.Count - 1;
                            allItems.Remove(includeItem.Children[childNr]);
                            if (includeItem.Children[childNr] is FieldItem)
                            {
                                FieldItem aItem = (FieldItem)includeItem.Children[childNr];
                                Node node = aItem.FieldDecl;
                                node.Parent().RemoveChild(node);
                                includeItem.Current.GetDecl().Insert(0, node);
                            }
                            else if (includeItem.Children[childNr] is StructItem)
                            {
                                StructItem aItem = (StructItem)includeItem.Children[childNr];
                                Node node = aItem.StructDecl;
                                node.Parent().RemoveChild(node);
                                includeItem.Current.GetDecl().Insert(0, node);
                            }
                            else if (includeItem.Children[childNr] is MethodDeclItem)
                            {
                                MethodDeclItem aItem = (MethodDeclItem)includeItem.Children[childNr];
                                AMethodDecl aNode = new AMethodDecl();
                                if (aItem.RealDecl.GetStatic() != null) aNode.SetStatic(new TStatic("static"));
                                aNode.SetReturnType(Util.MakeClone(aItem.RealDecl.GetReturnType(), finalTrans.data));
                                aNode.SetName(new TIdentifier(aItem.RealDecl.GetName().Text));
                                foreach (AALocalDecl formal in aItem.RealDecl.GetFormals())
                                {
                                    AALocalDecl clone = new AALocalDecl(new APublicVisibilityModifier(), null, null, null, null, Util.MakeClone(formal.GetType(), finalTrans.data), new TIdentifier(formal.GetName().Text), null);
                                    aNode.GetFormals().Add(clone);
                                }
                                includeItem.Current.GetDecl().Insert(0, aNode);
                            }
                            else if (includeItem.Children[childNr] is IncludeItem)
                            {
                                IncludeItem aChild = (IncludeItem)includeItem.Children[childNr];
                                if (aChild.Current == null)
                                {
                                    AIncludeDecl node = new AIncludeDecl(new TInclude("include"),
                                                        new TStringLiteral("\"TriggerLibs/NativeLib\""));
                                    includeItem.Current.GetDecl().Insert(0, node);
                                }
                                else
                                {
                                    PDecl[] decls = new PDecl[aChild.Current.GetDecl().Count];
                                    aChild.Current.GetDecl().CopyTo(decls, 0);
                                    for (int k = decls.Length - 1; k >= 0; k--)
                                    {
                                        includeItem.Current.GetDecl().Insert(0, decls[k]);
                                    }
                                    aChild.Current.Parent().RemoveChild(aChild.Current);
                                    //i = -1;
                                }
                            }
                            includeItem.Children.RemoveAt(childNr);
                        }
                    }
                }
            }
            else
                foreach (IncludeItem includeItem in allItems.OfType<IncludeItem>())
                {
                    for (int i = includeItem.Children.Count - 1; i >= 0; i--)
                    {
                        Node node;
                        if (includeItem.Children[i] is IncludeItem)
                        {
                            IncludeItem aItem = (IncludeItem) includeItem.Children[i];
                            node = new AIncludeDecl(new TInclude("include"),
                                                    new TStringLiteral("\"" + (aItem.Current == null ? "TriggerLibs/NativeLib" : aItem.Current.GetName().Text.Replace("\\", "/")) + "\""));
                            if (aItem.Current == null && finalTrans.mainEntry != null)
                            {
                                //Search for user defined initlib
                                bool foundInvoke = false;
                                foreach (ASimpleInvokeExp invokeExp in finalTrans.data.SimpleMethodLinks.Keys)
                                {
                                    if(invokeExp.GetName().Text == "libNtve_InitLib" && invokeExp.GetArgs().Count == 0)
                                    {
                                        /*finalTrans.errors.Add(new ErrorCollection.Error(invokeExp.GetName(),
                                                                                        Util.GetAncestor<AASourceFile>(
                                                                                            invokeExp),
                                                                                        "You are invoking libNtve_InitLib() yourself somewhere. It will not be auto inserted.",
                                                                                        true));*/
                                        foundInvoke = true;
                                        break;
                                    }
                                }

                                if (!foundInvoke)
                                {
                                    //Init the lib
                                    ASimpleInvokeExp initExp = new ASimpleInvokeExp();
                                    initExp.SetName(new TIdentifier("libNtve_InitLib"));
                                    finalTrans.data.ExpTypes[initExp] = new AVoidType(new TVoid("void"));
                                    foreach (AMethodDecl method in finalTrans.data.Libraries.Methods)
                                    {
                                        if (method.GetName().Text == "libNtve_InitLib" && method.GetFormals().Count == 0)
                                        {
                                            finalTrans.data.SimpleMethodLinks[initExp] = method;
                                        }
                                    }
                                    AABlock block = (AABlock) finalTrans.mainEntry.GetBlock();
                                    block.GetStatements().Insert(0, new AExpStm(new TSemicolon(";"), initExp));
                                }
                            }
                        }
                        else if (includeItem.Children[i] is FieldItem)
                        {
                            FieldItem aItem = (FieldItem)includeItem.Children[i];
                            node = aItem.FieldDecl;
                            node.Parent().RemoveChild(node);
                        }
                        else if (includeItem.Children[i] is StructItem)
                        {
                            StructItem aItem = (StructItem)includeItem.Children[i];
                            node = aItem.StructDecl;
                            node.Parent().RemoveChild(node);
                        }
                        else if (includeItem.Children[i] is MethodDeclItem)
                        {
                            MethodDeclItem aItem = (MethodDeclItem)includeItem.Children[i];
                            AMethodDecl aNode = new AMethodDecl();
                            if (aItem.RealDecl.GetStatic() != null) aNode.SetStatic(new TStatic("static"));
                            aNode.SetReturnType(Util.MakeClone(aItem.RealDecl.GetReturnType(), finalTrans.data));
                            aNode.SetName(new TIdentifier(aItem.RealDecl.GetName().Text));
                            foreach (AALocalDecl formal in aItem.RealDecl.GetFormals())
                            {
                                AALocalDecl clone = new AALocalDecl(new APublicVisibilityModifier(), null, null, null, null, Util.MakeClone(formal.GetType(), finalTrans.data), new TIdentifier(formal.GetName().Text), null);
                                aNode.GetFormals().Add(clone);
                            }
                            node = aNode;
                        }
                        else
                            throw new Exception("FixIncludes.Apply: Unexpected item type");

                        includeItem.Current.GetDecl().Insert(0, node);
                    }
                }
        }
        //private List<ErrorCollection.Error> multipleEntryCandidates = new List<ErrorCollection.Error>();
        public override void CaseAMethodDecl(AMethodDecl node)
        {
            //Done in a previous iteration
            /*if (node.GetName().Text == "InitMap" && node.GetFormals().Count == 0)
            {
                if (finalTrans.multipleMainEntries)
                {
                    multipleEntryCandidates.Add(new ErrorCollection.Error(node.GetName(), Util.GetAncestor<AASourceFile>(node.GetName()), "Candidate"));
                }
                else if (finalTrans.mainEntry != null)
                {
                    multipleEntryCandidates.Add(new ErrorCollection.Error(finalTrans.mainEntry.GetName(), Util.GetAncestor<AASourceFile>(finalTrans.mainEntry.GetName()), "Candidate"));
                    multipleEntryCandidates.Add(new ErrorCollection.Error(node.GetName(), Util.GetAncestor<AASourceFile>(node.GetName()), "Candidate"));
                    //finalTrans.errors.Add(new ErrorCollection.Error(node.GetName(), Util.GetAncestor<AASourceFile>(node), "Found multiple candidates for a main entry", true));
                    finalTrans.multipleMainEntries = true;
                    finalTrans.mainEntry = null;
                }
                else
                    finalTrans.mainEntry = node;
            }*/

            AStructDecl str = Util.GetAncestor<AStructDecl>(node);
            if (str != null)
            {
                if (node.GetStatic() == null)
                    structMethods.Add(node);
                //Move the method outside the struct
                str.RemoveChild(node.Parent());
                AASourceFile file = (AASourceFile)str.Parent();
                int i = file.GetDecl().IndexOf(str);
                file.GetDecl().Insert(i/* + 1*/, node);
                node.GetName().Text = GetUniqueStructMethodName(str.GetName().Text + "_" + node.GetName().Text);

                if (node.GetStatic() == null)
                {
                    //Add the struct as a parameter
                    PType structType = new ANamedType(new TIdentifier(str.GetName().Text), null);
                    finalTrans.data.StructTypeLinks[(ANamedType) structType] = str;
                    if (str.GetClassToken() != null)
                    {
                        structType = new APointerType(new TStar("*"), structType);
                    }
                    structFormal = new AALocalDecl(new APublicVisibilityModifier(), null,
                                                   str.GetClassToken() == null ? new TRef("ref") : null, null, null,
                                                   structType,
                                                   new TIdentifier("currentStruct", node.GetName().Line,
                                                                   node.GetName().Pos), null);
                    node.GetFormals().Add(structFormal);
                    data.Locals[(AABlock) node.GetBlock()].Add(structFormal);
                }
                else
                    node.SetStatic(null);
                finalTrans.data.Methods.Add(new SharedData.DeclItem<AMethodDecl>(file, node));
                if (node.GetStatic() == null)
                    OldParentStruct[node] = str;
                //Fix refferences to other struct stuff);
                base.CaseAMethodDecl(node);
                //Will visit later, since it's added after the struct
                //base.CaseAMethodDecl(node);
                //if (str.GetLocals().Count == 0)
                //    str.Parent().RemoveChild(str);
                return;
            }
            AEnrichmentDecl enrichment = Util.GetAncestor<AEnrichmentDecl>(node);
            if (enrichment != null)
            {
                if (node.GetStatic() == null)
                    structMethods.Add(node);
                //Move the method outside the struct
                enrichment.RemoveChild(node);
                AASourceFile file = (AASourceFile)enrichment.Parent();
                int i = file.GetDecl().IndexOf(enrichment);
                file.GetDecl().Insert(i/* + 1*/, node);
                node.GetName().Text = GetUniqueStructMethodName(Util.TypeToIdentifierString(enrichment.GetType()) + "_" + node.GetName().Text);

                if (node.GetStatic() == null)
                {
                    //Add the struct as a parameter
                    PType structType = Util.MakeClone(enrichment.GetType(), finalTrans.data);
                    structFormal = new AALocalDecl(new APublicVisibilityModifier(), null, new TRef("ref"), null, null,
                                                   structType,
                                                   new TIdentifier("currentEnrichment", node.GetName().Line,
                                                                   node.GetName().Pos), null);
                    node.GetFormals().Add(structFormal);
                }
                finalTrans.data.Methods.Add(new SharedData.DeclItem<AMethodDecl>(file, node));
                //Fix refferences to other struct stuff);
                base.CaseAMethodDecl(node);
                //Will visit later, since it's added after the struct
                //base.CaseAMethodDecl(node);
                //if (str.GetLocals().Count == 0)
                //    str.Parent().RemoveChild(str);
                return;
            }
            //Build a list of overloads
            List<AMethodDecl> overloads = new List<AMethodDecl>();
            List<string> prefixMatches = new List<string>();

            foreach (SharedData.DeclItem<AMethodDecl> declItem in finalTrans.data.Methods)
            {
                if (!Util.IsSameNamespace(declItem.Decl, node))
                    continue;
                if (declItem.Decl.GetName().Text == node.GetName().Text)
                    overloads.Add(declItem.Decl);
                if (declItem.Decl.GetName().Text.StartsWith(node.GetName().Text + "O"))
                    prefixMatches.Add(declItem.Decl.GetName().Text);
            }

            foreach (AMethodDecl method in finalTrans.data.Libraries.Methods)
            {
                if (method.GetBlock() != null || method.GetNative() != null)
                {
                    if (method.GetName().Text == node.GetName().Text)
                        overloads.Add(method);
                    if (method.GetName().Text.StartsWith(node.GetName().Text + "O"))
                        prefixMatches.Add(method.GetName().Text);
                }
            }

            //Add fields
            foreach (SharedData.DeclItem<AFieldDecl> declItem in finalTrans.data.Fields)
            {
                if (declItem.Decl.GetName().Text.StartsWith(node.GetName().Text + "O"))
                    prefixMatches.Add(declItem.Decl.GetName().Text);
            }

            foreach (AFieldDecl field in finalTrans.data.Libraries.Fields)
            {
                if (field.GetName().Text.StartsWith(node.GetName().Text + "O"))
                    prefixMatches.Add(field.GetName().Text);
            }

            //Dont want to hit another method by appending O#
            string postfix = "";
            while (true)
            {
                postfix += "O";
                if (prefixMatches.Any(text => text.StartsWith(node.GetName().Text + postfix)))
                {
                    continue;
                }
                break;
            }

            if (overloads.Count > 1)
            {
                int i = 0;
                foreach (AMethodDecl method in overloads)
                {
                    if (node == finalTrans.mainEntry || (node.GetTrigger() != null && finalTrans.data.HasUnknownTrigger))
                        continue;
                    i++;
                    method.GetName().Text += postfix + i;
                }
            }

            if (node != finalTrans.mainEntry && (node.GetTrigger() == null || !finalTrans.data.HasUnknownTrigger))
                node.GetName().Text = namespacePrefix + node.GetName().Text;

            base.CaseAMethodDecl(node);
        }