internal MFComponentDescriptor(MFComponent cmp, string desc, string docs, string projPath, Processor processor)
 {
     Component = cmp;
     Description = desc;
     Documentation = docs;
     ProjectPath = projPath;
     SolutionProcessor = processor;
 }
        public bool ContainsFeature(MFComponent compFeature)
        {
            foreach (MFComponent cmp in featuresField)
            {
                if (0 == string.Compare(cmp.Guid, compFeature.Guid, true))
                {
                    return true;
                }
            }

            return false;
        }
        public void AnalyzeLibraries(InventoryHelper helper, MFSolution solution, List<LibraryCategory> unresolved, List<LibraryCategory> removed)
        {
            Dictionary<string, MFComponent> reqLibList = new Dictionary<string, MFComponent>();
            Dictionary<string, MFComponent> unresolvedTypes = new Dictionary<string, MFComponent>();
            List<MFComponent> features = new List<MFComponent>();
            Dictionary<string, MFComponent> preferredLibrary = new Dictionary<string, MFComponent>();
            
            Processor proc = helper.FindProcessor(solution.Processor.Guid);

            libraryCategoriesField.Clear();

            ///
            /// First add all the features and there dependencies
            ///
            if (this.IsClrProject)
            {
                foreach (MFComponent cmpFeat in featuresField)
                {
                    RecurseFeatureDeps(cmpFeat, features, helper);
                }

                ///
                /// get debug transport
                ///
                if (solution.TransportType != null)
                {
                    string key = solution.TransportType.Guid.ToLower();

                    foreach (MFComponent transportFeat in solution.TransportType.FeatureAssociations)
                    {
                        if (!features.Contains(transportFeat))
                        {
                            features.Add(transportFeat);
                        }
                    }
                }
            }

            this.featuresField.Clear();
            foreach (MFComponent cmpFeat in features)
            {
                Feature feat = helper.FindFeature(cmpFeat.Guid);

                this.featuresField.Add(cmpFeat);

                foreach (MFComponent cmp in feat.ComponentDependencies)
                {
                    string key = cmp.Guid.ToLower();

                    if (cmp.ComponentType == MFComponentType.LibraryCategory)
                    {
                        if (!unresolvedTypes.ContainsKey(key))
                        {
                            unresolvedTypes[key] = cmp;
                        }
                    }
                    else if (cmp.ComponentType == MFComponentType.Library)
                    {
                        reqLibList[key] = cmp;
                        RecurseLibCatDeps(cmp, unresolvedTypes, helper, false);
                    }
                }
            }

            ///
            /// Add any required libraries before analyzing all project libraries
            ///
            foreach (Library lib in helper.GetRequiredLibraries())
            {
                // Only add CLR libraries to CLR projects
                if (lib.Level == LibraryLevel.CLR && !this.IsClrProject)
                    continue;

                string key = lib.Guid.ToLower();

                if (!reqLibList.ContainsKey(key))
                {
                    MFComponent cmpNew = new MFComponent(MFComponentType.Library, lib.Name, lib.Guid, lib.ProjectPath);

                    reqLibList[key] = cmpNew;

                    RecurseLibCatDeps(cmpNew, unresolvedTypes, helper, false);
                }
            }

            ///
            /// Now add all required library categories
            ///
            foreach (LibraryCategory lc in helper.GetRequiredLibraryCategories())
            {
                if (lc.Level == LibraryLevel.CLR && !this.isClrProjectField) continue;

                string key = lc.Guid.ToLower();

                if (!unresolvedTypes.ContainsKey(key))
                {
                    MFComponent cmp = new MFComponent(MFComponentType.LibraryCategory, lc.Name, lc.Guid, lc.ProjectPath);

                    unresolvedTypes[lc.Guid.ToLower()] = cmp;
                }
            }

            ///
            /// Add cloned solution's solution-dependent projects
            /// 
            if (solution.m_cloneSolution != null && m_cloneProj != null)
            {
                foreach (MFComponent lib in m_cloneProj.librariesField)
                {
                    // If we have already added a library for the current solution, then just add a new component to the project
                    if (solution.m_clonedLibraryMap.ContainsKey(lib.Guid.ToUpper()))
                    {
                        Library newLib = solution.m_clonedLibraryMap[lib.Guid.ToUpper()];

                        librariesField.Add(new MFComponent(lib.ComponentType, newLib.Name, newLib.Guid, newLib.ProjectPath, lib.Conditional));
                    }
                    // otherwise, create a new library based on the cloned solution's library
                    else if (lib.ProjectPath.ToUpper().Contains("\\SOLUTIONS\\" + solution.m_cloneSolution.Name.ToUpper() + "\\"))
                    {
                        string name = CopyHelper.ReplaceText(lib.Name, solution.m_cloneSolution.Name, solution.Name);
                        string path = CopyHelper.ReplaceText(lib.ProjectPath, solution.m_cloneSolution.Name, solution.Name);
                        string guid = System.Guid.NewGuid().ToString("B").ToUpper();

                        // find cloned solution's library in the intventory
                        Library l = helper.FindLibrary(lib);
                        if (l != null)
                        {
                            Library l2 = new Library();

                            // copy and rename 
                            l.CopyTo(l2);

                            CopyHelper.Rename(l2, solution.m_cloneSolution.Name, solution.Name);

                            l2.Name = name;
                            l2.Guid = guid;
                            l2.ProjectPath = path;

                            // add library to inventory
                            helper.AddLibraryToInventory(l2, false, helper.DefaultInventory);

                            // hash to used so that we don't add multiple libraries for each project
                            solution.m_clonedLibraryMap[lib.Guid.ToUpper()] = l2;
                            // Add the component to this projects library list
                            MFComponent newCmp = new MFComponent(lib.ComponentType, name, guid, path, lib.Conditional);
                            librariesField.Add(newCmp);

                            if (l.HasLibraryCategory)
                            {
                                preferredLibrary[l.LibraryCategory.Guid.ToLower()] = newCmp;
                            }
                        }
                    }
                }
            }

            ///
            /// HACK - fix this to make it data driven (add a field on library categories that allows them to be required by a solution)
            /// 
            if (this.isClrProjectField)
            {
                LibraryCategory lc = helper.FindLibraryCategoryByName("WearLeveling_HAL");

                if (lc != null)
                {
                    string key = lc.Guid.ToLower();
                    if (unresolvedTypes.ContainsKey(key))
                    {
                        solution.m_solRequiredLibCats[key] = unresolvedTypes[key];
                    }
                }
            }
            else if(solution.m_solRequiredLibCats != null)
            {
                foreach (MFComponent cmp in solution.m_solRequiredLibCats.Values)
                {
                    string key = cmp.Guid.ToLower();

                    if (!unresolvedTypes.ContainsKey(key))
                    {
                        unresolvedTypes[key] = cmp;
                    }
                }
            }

            /// 
            /// Use a copy of the libraries, because the libraryField may be updated inside the loop
            /// 
            MFComponent[] __libs = new MFComponent[librariesField.Count];
            librariesField.CopyTo(__libs);

            List<MFComponent> libs = new List<MFComponent>(__libs);
            Dictionary<string, MFComponent> resolvedTypes = new Dictionary<string, MFComponent>();
            List<string> duplicateLibList = new List<string>();

            while (true)
            {
                List<MFComponent> remList = new List<MFComponent>();
                Dictionary<string, MFComponent> newUnresolvedTypes = new Dictionary<string, MFComponent>();

                foreach (MFComponent cmpLib in libs)
                {
                    Library lib = helper.FindLibrary(cmpLib);

                    bool fKeepingLib = false;

                    if (duplicateLibList.Contains(cmpLib.Guid.ToLower()) || lib == null || !ValidateLibrary(lib, solution, proc, helper))
                    {
                        librariesField.Remove(cmpLib);
                        remList.Add(cmpLib);
                        continue;
                    }

                    if (lib.HasLibraryCategory)
                    {
                        if (preferredLibrary.ContainsKey(lib.LibraryCategory.Guid.ToLower()) &&
                            string.Compare(cmpLib.Guid, preferredLibrary[lib.LibraryCategory.Guid.ToLower()].Guid, true) != 0)
                        {
                            fKeepingLib = true;
                        }
                        ///
                        /// Make sure the library selection matches the feature selection
                        ///
                        else if (this.isClrProjectField)
                        {
                            LibraryCategory lc = helper.FindLibraryCategory(lib.LibraryCategory.Guid);

                            if (lc != null)
                            {
                                if (lc.FeatureAssociations.Count > 0)
                                {
                                    bool fFeatureSelected = false;

                                    foreach (MFComponent feat in lc.FeatureAssociations)
                                    {
                                        if (features.Contains(feat))
                                        {
                                            fFeatureSelected = true;
                                            break;
                                        }
                                    }

                                    if (((!fFeatureSelected && !lib.IsStub) || (fFeatureSelected && lib.IsStub)) &&
                                        string.IsNullOrEmpty(cmpLib.Conditional))
                                    {
                                        librariesField.Remove(cmpLib);
                                        remList.Add(cmpLib);
                                        continue;
                                    }
                                }
                            }
                        }

                        if (!fKeepingLib)
                        {
                            string key = lib.LibraryCategory.Guid.ToLower();

                            if (unresolvedTypes.ContainsKey(key) || (!string.IsNullOrEmpty(cmpLib.Conditional) && resolvedTypes.ContainsKey(key)))
                            {
                                unresolvedTypes.Remove(key);
                                resolvedTypes[key] = lib.LibraryCategory;
                                fKeepingLib = true;
                                RecurseLibCatDeps(cmpLib, newUnresolvedTypes, helper, true);
                            }
                        }
                    }
                    else
                    {
                        fKeepingLib = true;
                    }

                    if (fKeepingLib)
                    {
                        remList.Add(cmpLib);

                        duplicateLibList.Add(cmpLib.Guid.ToLower());

                        foreach (MFComponent dep in lib.Dependencies)
                        {
                            if (dep.ComponentType == MFComponentType.Library)
                            {
                                if (duplicateLibList.Contains(dep.Guid.ToLower()) || librariesField.Contains(dep))
                                {
                                    continue;
                                }

                                Library libDep = helper.FindLibrary(dep);

                                if (libDep != null && libDep.HasLibraryCategory)
                                {
                                    string key = libDep.LibraryCategory.Guid.ToLower();
                                    if(!unresolvedTypes.ContainsKey(key) && !resolvedTypes.ContainsKey(key) && !newUnresolvedTypes.ContainsKey(key))
                                    {
                                        newUnresolvedTypes[key] = libDep.LibraryCategory;
                                    }
                                }
                                else
                                {
                                    remList.Add(dep);
                                    librariesField.Add(dep);
                                }
                            }
                        }
                    }
                }

                foreach (MFComponent cmp in remList)
                {
                    if (libs.Contains(cmp))
                    {
                        libs.Remove(cmp);
                    }
                }

                if (newUnresolvedTypes.Count == 0) break;

                foreach (string key in newUnresolvedTypes.Keys)
                {
                    if (!unresolvedTypes.ContainsKey(key) && !resolvedTypes.ContainsKey(key))
                    {
                        unresolvedTypes[key] = newUnresolvedTypes[key];
                    }
                }
            }

            foreach (MFComponent cmp in resolvedTypes.Values)
            {
                libraryCategoriesField.Add(cmp);
            }

            foreach (MFComponent cmp in libs)
            {
                librariesField.Remove(cmp);
            }

            foreach (MFComponent cmp in reqLibList.Values)
            {
                if (!librariesField.Contains(cmp))
                {
                    Library lib = helper.FindLibrary(cmp);
                    if (lib != null && ValidateLibrary(lib, solution, proc, helper))
                    {
                        librariesField.Add(cmp);
                    }
                }
            }

            foreach (MFComponent cmp in unresolvedTypes.Values)
            {
                LibraryCategory lc = helper.FindLibraryCategory(cmp.Guid);

                unresolved.Add(lc);
            }
        }
 internal TemplateGenerationData(LibraryCategory lc, MFComponent cmp)
 {
     LibraryCat = lc;
     Comp       = cmp;
 }
        internal MFProject LoadProjectProj(string projFile, string path)
        {
            MFProject mfproj = new MFProject();
            Project proj;
            string fullpath = ExpandEnvVars(projFile, path);

            List<MFComponent> driverLibCheck = new List<MFComponent>();

            try
            {
                proj = LoadProject(fullpath);

                path = Path.GetDirectoryName(fullpath);

                mfproj.ProjectPath = ConvertPathToEnv(projFile);

                Dictionary<string, string> tbl = new Dictionary<string, string>();
                tbl["AssemblyName"] = "Name";
                tbl["MFSettingsFile"] = "SettingsFile";
                tbl["ProjectGuid"] = "Guid";

                LoadStringProps(proj, mfproj, tbl);

                foreach (ProjectPropertyGroupElement pg in proj.Xml.PropertyGroups)
                {
                    foreach (ProjectPropertyElement bp in pg.Properties)
                    {
                        string cond = CombineConditionals(pg.Condition, bp.Condition);

                        switch (bp.Name)
                        {
                            case "AssemblyName":
                            case "MFSettingsFile":
                            case "ProjectGuid":
                            case "Description":
                            case "Documentation":
                                // handled by loadstringprops
                                break;
                            case "IsClrProject":
                                mfproj.IsClrProject = Boolean.Parse(bp.Value);
                                break;
                            case "EXEScatterFileDefinition":
                                {
                                    MFBuildFile file = new MFBuildFile();

                                    file.Condition = cond;
                                    file.File = bp.Value;
                                    file.ItemName = bp.Name;

                                    mfproj.ScatterFile = file;
                                }
                                break;
                            default:
                                {
                                    MFProperty prop = new MFProperty();
                                    prop.Name = bp.Name;
                                    prop.Value = bp.Value;
                                    prop.Condition = cond;
                                    mfproj.Properties.Add(prop);
                                }
                                break;
                        }
                    }
                }

                LoadCompileItems(proj, mfproj, path);

                Dictionary<string, MFComponent> libLookup = new Dictionary<string, MFComponent>();
                foreach (ProjectItemGroupElement big in proj.Xml.ItemGroups)
                {
                    foreach (ProjectItemElement bi in big.Items)
                    {
                        string cond = CombineConditionals(big.Condition, bi.Condition);

                        switch (bi.ItemType)
                        {
                            case "RequiredProjects":
                                string ext = Path.GetExtension(bi.Include).ToUpper();
                                if (ext == ".FEATUREPROJ" || ext == ".LIBCATPROJ")
                                {
                                    System.Diagnostics.Debug.Assert(false, ".FeatureProj and .LibCatProj files can only be imported");
                                }
                                else if (ext == ".PROJ")
                                {
                                    Library lib = m_helper.FindLibraryByProject(ExpandEnvVars(bi.Include, path));
                                    MFComponent comp = null;

                                    if (lib == null)
                                    {
                                        lib = LoadLibraryProj(bi.Include, path);
                                    }

                                    if (lib != null)
                                    {
                                        if (libLookup.ContainsKey(lib.Guid.ToLower()))
                                        {
                                            comp = libLookup[lib.Guid.ToLower()];

                                            if (string.IsNullOrEmpty(comp.Conditional))
                                            {
                                                comp.Conditional = cond;
                                            }
                                            break;
                                        }

                                        comp = new MFComponent(MFComponentType.Library, lib.Name, lib.Guid, bi.Include);
                                        comp.Conditional = cond;
                                    }

                                    if (comp != null)
                                    {
                                        mfproj.Libraries.Add(comp);

                                        libLookup[comp.Guid.ToLower()] = comp;
                                    }
                                    else
                                    {
                                        // we should pick this up in the driverlibs/platformlibs
                                        /*
                                        string name = Path.GetFileName(Path.GetDirectoryName(bi.Include));
                                        comp = new MFComponent(MFComponentType.Library, name, System.Guid.NewGuid().ToString("B"), bi.Include);
                                        comp.Conditional = cond;

                                        mfproj.Libraries.Add(comp);

                                        libLookup[comp.Guid.ToLower()] = comp;

                                        Console.WriteLine("Error: Library not found " + bi.Include);
                                        */
                                    }
                                }
                                else
                                {
                                    Console.WriteLine("Warning! Skipping dependency item " + bi.Include);
                                }
                                break;
                            case "InteropFeature":
                                mfproj.InteropFeatures.Add(bi.Include);
                                break;
                            case "PlatformIndependentLibs":
                                goto case "DriverLibs";
                            case "DriverLibs":
                                driverLibCheck.Add(new MFComponent(MFComponentType.Unknown, "", "", bi.Include, cond));
                                break;
                            case "MMP_DAT_CreateDatabase":
                                if (!mfproj.ExtraAssemblies.Contains(bi.Include))
                                {
                                    mfproj.ExtraAssemblies.Add(bi.Include);
                                }
                                break;
                            case "FastCompileCPPFile":
                            case "Compile":
                            case "HFiles":
                            case "IncludePaths":
                                // handled by LoadCompileItems
                                break;

                            // todo: do we want to get rid of subdirectories?
                            //case "SubDirectories":
                            //break;

                            default:
                                {
                                    MFBuildFile f = new MFBuildFile();
                                    f.Condition = cond;
                                    f.File = bi.Include;
                                    f.ItemName = bi.ItemType;
                                    mfproj.OtherFiles.Add(f);
                                }
                                break;
                        }
                    }
                }

                Hashtable featLookup = new Hashtable();

                foreach (ProjectImportElement imp in proj.Xml.Imports)
                {
                    string ext = Path.GetExtension(imp.Project).ToUpper();

                    if (ext == ".FEATUREPROJ")
                    {
                        Feature feat = LoadFeatureProj(imp.Project, path);
                        MFComponent comp = null;

                        if (feat == null)
                        {
                            feat = m_helper.FindFeatureByName(Path.GetFileNameWithoutExtension(imp.Project));
                        }

                        if (feat == null)
                        {
                            string name = Path.GetFileNameWithoutExtension(imp.Project);
                            comp = new MFComponent(MFComponentType.Feature, name, System.Guid.NewGuid().ToString("B"), imp.Project);
                            comp.Conditional = imp.Condition;

                            mfproj.Features.Add(comp);

                            featLookup.Add(comp.Guid.ToLower(), comp);

                            //Console.WriteLine("Error: Feature not found " + imp.Project);
                        }
                        else if(!featLookup.ContainsKey(feat.Guid.ToLower()))
                        {
                            comp = new MFComponent(MFComponentType.Feature, feat.Name, feat.Guid, imp.Project);
                            comp.Conditional = imp.Condition;

                            mfproj.Features.Add(comp);

                            featLookup.Add(feat.Guid.ToLower(), comp);
                        }
                    }
                    else if (ext == ".LIBCATPROJ")
                    {
                        LibraryCategory libcat = LoadLibraryCategoryProj(imp.Project, path);
                        MFComponent comp = null;

                        if (libcat == null)
                        {
                            libcat = m_helper.FindLibraryCategoryByName(Path.GetFileNameWithoutExtension(imp.Project));
                        }

                        if (libcat != null)
                        {
                            comp = new MFComponent(MFComponentType.LibraryCategory, libcat.Name, libcat.Guid, imp.Project);
                            comp.Conditional = imp.Condition;

                            mfproj.LibraryCategories.Add(comp);
                        }
                        else
                        {
                            string name = Path.GetFileNameWithoutExtension(imp.Project);
                            comp = new MFComponent(MFComponentType.LibraryCategory, name, System.Guid.NewGuid().ToString("B"), imp.Project);
                            comp.Conditional = imp.Condition;

                            mfproj.LibraryCategories.Add(comp);

                            Console.WriteLine("Error: LibraryCategory not found " + imp.Project);
                        }
                    }
                }


                ScatterfileWrapper sw = new ScatterfileWrapper(mfproj);
                string scatter = "";

                if (mfproj.ScatterFile != null && !string.IsNullOrEmpty(mfproj.ScatterFile.File))
                {
                    string tmp = ExpandEnvVars(mfproj.ScatterFile.File, "");
                    if (File.Exists(tmp))
                    {
                        scatter = tmp;
                    }
                }

                if (scatter == "")
                {
                    foreach (string scatterfile in Directory.GetFiles(Path.GetDirectoryName(projFile), "scatter*.xml"))
                    {
                        if (scatterfile.ToLower().Contains("ram_functions")) continue;
                        if (scatterfile.ToLower().Contains("_gcc.")) continue;

                        List<MemoryMap> maps = sw.LoadFromFile(scatterfile);

                        if(maps != null && maps.Count > 0)
                        {
                            mfproj.MemoryMap = maps[0];
                        }
                    }
                }
                else
                {
                    // todo add support for GCC?
                    if (!scatter.ToLower().Contains("_gcc"))
                    {
                        mfproj.MemoryMap = sw.LoadFromFile(scatter)[0];
                    }
                }

                foreach (ProjectTargetElement targ in proj.Xml.Targets)
                {
                    mfproj.Targets.Add(targ);
                }

                foreach(MFComponent comp in driverLibCheck)
                {
                    Library lib = m_helper.FindLibraryByFile(comp.ProjectPath);

                    if (lib == null)
                    {
                        lib = m_helper.FindLibraryByName(Path.GetFileNameWithoutExtension(comp.ProjectPath));
                    }

                    if (lib == null)
                    {
                        mfproj.Libraries.Add(comp);

                        libLookup[comp.Guid.ToLower()] = comp;

                        Console.WriteLine("Warning: Library not found " + comp.ProjectPath + ". Delay loading...");
                    }
                }

            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine("Error: loading project file: " + fullpath + "\r\n", e.Message);
                mfproj = null;
            }

            return mfproj;
        }
        internal MFAssembly LoadAssemblyProj(string asmProjFile, string path)
        {
            
            Project proj;
            string projname = Path.GetFileNameWithoutExtension(asmProjFile);
            string fullpath = ExpandEnvVars(asmProjFile, path);

            MFAssembly asm = m_helper.FindAssemblyByProject(fullpath);

            try
            {
                if (asm != null) return asm;

                if (!File.Exists(fullpath))
                {
                    // TODO: ERROR LOGGING
                    return null;
                }

                asm = new MFAssembly();

                asm.ProjectPath = ConvertPathToEnv(fullpath);

                proj = LoadProject(fullpath);

                path = Path.GetDirectoryName(fullpath);

                if (path.ToLower().Contains("\\framework\\tools\\")) return null;

                foreach (ProjectImportElement imp in proj.Xml.Imports)
                {
                    // no server assemblies
                    if (imp.Project.ToUpper().Contains("MICROSOFT.SPOT.CSHARP.HOST.TARGETS"))
                    {
                        return null;
                    }
                }

                foreach (ProjectPropertyGroupElement pg in proj.Xml.PropertyGroups)
                {
                    foreach (ProjectPropertyElement bp in pg.Properties)
                    {
                        switch (bp.Name)
                        {
                            case "AssemblyName":
                                string asmName = bp.Value;
                                asmName = asmName.Replace("$(MSBuildProjectName)", projname);
                                asm.Name = asmName;
                                asm.AssemblyFile = @"$(BUILD_TREE_CLIENT)\pe\" + asmName + ".pe";
                                break;
                            case "TinyCLR_Platform":
                                if (string.Compare(bp.Value, "Server", true) == 0)
                                {
                                    // we don't want to process server tools for now
                                    return null;
                                }
                                break;
                            case "ProjectGuid":
                                asm.Guid = bp.Value;
                                break;
                            case "Groups":
                                asm.Groups = bp.Value;
                                break;
                        }
                    }
                }

                if (string.IsNullOrEmpty(asm.Name)) asm.Name = projname;
                if (string.IsNullOrEmpty(asm.Guid)) asm.Guid = System.Guid.NewGuid().ToString("B");

                foreach (ProjectItemGroupElement big in proj.Xml.ItemGroups)
                {
                    foreach (ProjectItemElement bi in big.Items)
                    {
                        string cond = CombineConditionals(big.Condition, bi.Condition);

                        if (bi.ItemType == "Reference")
                        {
                            MFComponent asmRef = new MFComponent(MFComponentType.MFAssembly);
                            asmRef.Name = bi.Include;
                            asmRef.Conditional = cond;

                            asm.References.Add(asmRef);
                        }
                    }
                }

                MFAssembly dbAsm = m_helper.FindAssemblyByName(asm.Name);
                if (null == dbAsm)
                {
                    m_helper.DefaultInventory.Assemblies.Add(asm);
                }
                else
                {
                    asm = dbAsm;
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine("Error: loading assembly file: " + fullpath + "\r\n", e.Message);
                asm = null;
            }

            return asm;
        }
        internal Library LoadLibraryProj(string libProjFile, string path, bool fForceReload)
        {
            Project proj;
            string fullpath = ExpandEnvVars(libProjFile, path);
            Library lib = null;

            try
            {
                lib = m_helper.FindLibraryByProject(fullpath);
                Library dbLib = null;

                if (!fForceReload)
                {
                    if (lib != null)
                    {
                        return lib;
                    }
                }

                if (!File.Exists(fullpath))
                {
                    return null;
                }

                if (lib == null)
                {
                    lib = new Library();
                }


                proj = LoadProject(fullpath);

                path = Path.GetDirectoryName(fullpath);

                lib.ProjectPath = ConvertPathToEnv(fullpath);

                if (fullpath.ToUpper().Contains("\\CLR\\"))
                {
                    lib.Level = LibraryLevel.CLR;
                }
                else if (fullpath.ToUpper().Contains("\\SUPPORT\\"))
                {
                    lib.Level = LibraryLevel.Support;
                }
                else if (fullpath.ToUpper().Contains("\\PAL\\"))
                {
                    lib.Level = LibraryLevel.PAL;
                }
                else
                {
                    lib.Level = LibraryLevel.HAL;
                }

                if (Path.GetFileName(fullpath).ToUpper().Contains("_STUB") ||
                    fullpath.ToUpper().Contains("\\STUBS"))
                {
                    lib.IsStub = true;
                }

                Dictionary<string, string> tbl = new Dictionary<string, string>();
                tbl["AssemblyName"] = "Name";
                tbl["ProjectGuid"] = "Guid";

                LoadStringProps(proj, lib, tbl);

                if (!fForceReload)
                {
                    dbLib = m_helper.FindLibrary(lib.Guid);

                    if (dbLib != null)
                    {
                        if (!string.Equals(dbLib.Name, lib.Name, StringComparison.InvariantCultureIgnoreCase))
                        {
                            System.Diagnostics.Debug.WriteLine("WARNING!!! Loaded library name doesn't match database library (possible bad project file)");
                            System.Diagnostics.Debug.WriteLine(dbLib.Name + " != " + lib.Name);
                        }
                        return dbLib;
                    }

                    dbLib = m_helper.FindLibraryByName(lib.Name);
                    if (dbLib != null) return dbLib;
                }

                if (string.IsNullOrEmpty(lib.LibraryFile)) lib.LibraryFile = lib.Name + ".$(LIB_EXT)";
                if (string.IsNullOrEmpty(lib.ManifestFile)) lib.ManifestFile = lib.LibraryFile + ".manifest";

                foreach (ProjectPropertyGroupElement pg in proj.Xml.PropertyGroups)
                {
                    foreach (ProjectPropertyElement bp in pg.Properties)
                    {
                        string cond = CombineConditionals(pg.Condition, bp.Condition);

                        switch (bp.Name)
                        {
                            /*
                        case "OutputType":
                            // don't allow projects to be loaded as library
                            if (0 == string.Compare(bp.Value.Trim(), "Executable", true))
                            {
                                return null;
                            }
                            break;
                            */
                            case "Version":
                                string[] vers = bp.Value.Split('.');
                                if (vers != null)
                                {
                                    if (vers.Length > 0) lib.Version.Major = vers[0];
                                    if (vers.Length > 1) lib.Version.Minor = vers[1];
                                    if (vers.Length > 2) lib.Version.Revision = vers[2];
                                    if (vers.Length > 3) lib.Version.Build = vers[3];
                                }
                                break;
                            case "PlatformIndependentBuild":
                                {
                                    bool fPlatIndep = false;
                                    bool.TryParse(bp.Value, out fPlatIndep);
                                    lib.PlatformIndependent = fPlatIndep;
                                }
                                break;
                            default:
                                {
                                    MFProperty prop = new MFProperty();
                                    prop.Name = bp.Name;
                                    prop.Value = bp.Value;
                                    prop.Condition = cond;
                                    lib.Properties.Add(prop);
                                }
                                break;
                        }
                    }
                }

                if (string.IsNullOrEmpty(lib.Name))
                {
                    string dirName = Path.GetFileName(Path.GetDirectoryName(fullpath));
                    if (string.Compare(dirName, "GlobalLock") == 0)
                    {
                        lib.Name = dirName;
                    }
                    else
                    {
                        return null;
                    }
                }


                LoadCompileItems(proj, lib, path);

                if (string.IsNullOrEmpty(lib.Guid))
                {
                    lib.Guid = System.Guid.NewGuid().ToString("B");
                }

                foreach (ProjectItemGroupElement big in proj.Xml.ItemGroups)
                {
                    foreach (ProjectItemElement bi in big.Items)
                    {
                        string cond = CombineConditionals(big.Condition, bi.Condition);

                        switch (bi.ItemType)
                        {
                            case "RequiredProjects":
                                if (bi.Include.Trim().ToUpper().EndsWith(".PROJ"))
                                {
                                    Library lib2 = LoadLibraryProj(bi.Include, path);

                                    if (lib2 != null)
                                    {
                                        lib.Dependencies.Add(new MFComponent(MFComponentType.Library, lib2.Name, lib2.Guid, bi.Include));
                                    }
                                    else
                                    {
                                        System.Diagnostics.Debug.WriteLine("Warning! unknown library " + bi.Include);
                                        //System.Diagnostics.Debug.Assert(false);
                                    }
                                }
                                break;
                            case "LibraryCategories":
                                LibraryCategory libCat = LoadLibraryCategoryProj(bi.Include, path);
                                lib.Dependencies.Add(new MFComponent(MFComponentType.LibraryCategory, libCat.Name, libCat.Guid, bi.Include, cond));
                                break;
                            case "FastCompileCPPFile":
                            case "Compile":
                            case "HFiles":
                            case "IncludePaths":
                                // handled by LoadCompileItems
                                break;

                            case "SubDirectories":
                                break;

                            default:
                                {
                                    MFBuildFile f = new MFBuildFile();
                                    f.Condition = cond;
                                    f.File = bi.Include;
                                    f.ItemName = bi.ItemType;
                                    lib.OtherFiles.Add(f);
                                }
                                break;
                        }
                    }
                }

                if (lib.IsStub && lib.LibraryCategory != null && !string.IsNullOrEmpty(lib.LibraryCategory.Guid))
                {
                    LibraryCategory lc = m_helper.FindLibraryCategory(lib.LibraryCategory.Guid);
                    if (lc != null)
                    {
                        lc.StubLibrary = new MFComponent(MFComponentType.Library, lib.Name, lib.Guid, lib.ProjectPath);

                        if (lc.Level != LibraryLevel.CLR && lc.Level != LibraryLevel.Support && lc.Templates.Count == 0)
                        {
                            lc.Templates.Clear();

                            ApiTemplate api = new ApiTemplate();
                            api.FilePath = ConvertPathToEnv(fullpath);
                            lc.Templates.Add(api);

                            foreach (MFBuildFile bf in lib.SourceFiles)
                            {
                                api = new ApiTemplate();
                                api.FilePath = ConvertPathToEnv(Path.Combine(path, bf.File));
                                lc.Templates.Add(api);
                            }
                            foreach (MFBuildFile bf in lib.HeaderFiles)
                            {
                                if (Path.IsPathRooted(MsBuildWrapper.ExpandEnvVars(bf.File,"")) || bf.File.Contains("..")) continue;

                                api = new ApiTemplate();
                                api.FilePath = ConvertPathToEnv(Path.Combine(path, bf.File));
                                lc.Templates.Add(api);
                            }
                            foreach (MFBuildFile bf in lib.FastCompileFiles)
                            {
                                api = new ApiTemplate();
                                api.FilePath = ConvertPathToEnv(Path.Combine(path, bf.File));
                                lc.Templates.Add(api);
                            }
                        }

                    }
                }

                foreach (ProjectTargetElement targ in proj.Xml.Targets)
                {
                    lib.Targets.Add(targ);
                }

                foreach (ProjectImportElement imp in proj.Xml.Imports)
                {
                    switch (Path.GetExtension(imp.Project).ToUpper().Trim())
                    {
                        case ".LIBCATPROJ":
                            LibraryCategory lc = LoadLibraryCategoryProj(imp.Project, path);
                            if (lc != null)
                            {
                                MFComponent cmp = new MFComponent(MFComponentType.LibraryCategory, lc.Name, lc.Guid, lc.ProjectPath);
                                lib.Dependencies.Add(cmp);
                            }
                            else
                            {
                                System.Diagnostics.Debug.Assert(false);
                            }
                            break;
                    }
                }

                m_helper.AddLibraryToInventory(lib, false, m_helper.DefaultInventory);
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine("Error: loading Library file: " + fullpath + "\r\n", e.Message);
                lib = null;
            }

            return lib;
        }
        private void LoadStringProps(Project proj, object obj, Dictionary<string,string> tbl)
        {
            foreach (ProjectPropertyGroupElement bpg in proj.Xml.PropertyGroups)
            {
                foreach (ProjectPropertyElement bp in bpg.Properties)
                {
                    string name = bp.Name;

                    if (tbl.ContainsKey(name)) name = tbl[name];

                    PropertyInfo pi = obj.GetType().GetProperty(name);

                    if (pi != null)
                    {
                        if (pi.PropertyType == typeof(string))
                        {
                            pi.SetValue(obj, bp.Value, null);
                        }
                        else if (pi.PropertyType == typeof(List<string>))
                        {
                            string[] items = ((string)bp.Value).Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                            pi.SetValue(obj, new List<string>(items), null);
                        }
                        else if (pi.PropertyType == typeof(bool))
                        {
                            pi.SetValue(obj, bool.Parse(bp.Value), null);
                        }
                        else if (pi.PropertyType == typeof(MFComponent) && !string.IsNullOrEmpty(bp.Value))
                        {
                            MFComponent comp = null;
                            try
                            {
                                comp = (MFComponent)DeserializeXml(bp.Value, typeof(MFComponent));
                            }
                            catch
                            {
                                comp = new MFComponent(MFComponentType.Unknown, bp.Value);
                            }

                            if (pi.Name == "LibraryCategory") comp.ComponentType = MFComponentType.LibraryCategory;
                            if (pi.Name == "ISASpecific") comp.ComponentType = MFComponentType.ISA;
                            if (pi.Name == "ProcessorSpecific") comp.ComponentType = MFComponentType.Processor;
                            if (pi.Name == "Processor") comp.ComponentType = MFComponentType.Processor;
                            if (pi.Name == "DefaultISA") comp.ComponentType = MFComponentType.ISA;
                                
                            pi.SetValue(obj, comp, null);
                        }
                        else if (pi.PropertyType == typeof(LibraryLevel))
                        {
                            pi.SetValue(obj, Enum.Parse(typeof(LibraryLevel), bp.Value), null);
                        }
                    }
                }
            }
        }
            internal ComponentTreeNode(MFComponent comp, bool check)
            {
                Visible = true;
                Checked = check;
                Comp = comp;

                if (check)
                {
                    Comp.RefCount++;
                }
            }
        private void wpChooseProjects_CloseFromNext(object sender, Gui.Wizard.PageEventArgs e)
        {
            m_HasClrProj = false;

            Dictionary<string, MFProject> projLookup = new Dictionary<string, MFProject>();
            List<MFProject> projRemoveList = new List<MFProject>();

            foreach (MFProject prj in m_solution.Projects)
            {
                projLookup[prj.Name.ToLower()] = prj;
            }
            //m_solution.Projects.Clear();

            string solutionRoot = "$(SPOCLIENT)\\Solutions\\" + m_solution.Name + "\\";

            foreach (TreeNode tn in tv_SelectedProjects.Nodes["NativeProjects"].Nodes)
            {
                MFProject projClone = tn.Tag as MFProject;
                string key = projClone.Name.ToLower();

                if (tn.Checked)
                {
                    if (projLookup.ContainsKey(key))
                    {
                        continue;
                    }

                    MFProject proj = new MFProject();

                    projClone.CopyTo(proj, m_solution.Name);

                    if (proj != null)
                    {
                        proj.ProjectPath = solutionRoot + Path.GetFileName(proj.Directory) + "\\" + Path.GetFileName(proj.ProjectPath);

                        proj.SettingsFile = solutionRoot + m_solution.Name + ".settings";

                        m_solution.Projects.Add(proj);

                        projLookup[key] = proj;
                    }
                }
                else if (projLookup.ContainsKey(key))
                {
                    projRemoveList.Add(projLookup[key]);
                    projLookup.Remove(key);
                }
            }

            foreach (TreeNode tn in tv_SelectedProjects.Nodes["ClrProjects"].Nodes)
            {
                MFProject projClone = tn.Tag as MFProject;
                string key = projClone.Name.ToLower();

                if (tn.Checked)
                {
                    if (projLookup.ContainsKey(key))
                    {
                        m_HasClrProj = true;
                        continue;
                    }

                    MFProject proj = new MFProject();

                    projClone.CopyTo(proj, m_solution.Name);

                    if (proj != null)
                    {
                        proj.ProjectPath = solutionRoot + Path.GetFileName(proj.Directory) + "\\" + Path.GetFileName(proj.ProjectPath);

                        proj.SettingsFile = solutionRoot + m_solution.Name + ".settings";

                        m_solution.Projects.Add(proj);

                        m_HasClrProj = true;

                        projLookup[key] = proj;
                    }
                }
                else if (projLookup.ContainsKey(key))
                {
                    projRemoveList.Add(projLookup[key]);
                    projLookup.Remove(key);
                }
            }

            foreach (MFProject prj in projRemoveList)
            {
                m_solution.Projects.Remove(prj);
            }

            MFProject projAll = new MFProject();
            projAll.Name = Properties.Resources.AllProjects;
            projAll.Guid = m_allProjectsGuid;
            projAll.IsClrProject = true;

            m_solution.Projects.Insert(0, projAll); 

            if (m_solution.m_cloneSolution != null)
            {
                MFProject defProj = null;

                foreach (MFProject prj in m_solution.m_cloneSolution.Projects)
                {
                    string key = prj.Name.ToLower();

                    if (0 == string.Compare(key, "tinyclr"))
                    {
                        defProj = prj;
                    }

                    if (projLookup.ContainsKey(key))
                    {
                        projLookup[key].Features.AddRange(prj.Features);
                        projLookup[key].Libraries.AddRange(prj.Libraries);
                    }
                }

                if (defProj != null)
                {
                    foreach (MFProject proj in m_solution.Projects)
                    {
                        if (proj.IsClrProject && proj.Features.Count == 0)
                        {
                            foreach (MFComponent f in defProj.Features)
                            {
                                MFComponent fCopy = new MFComponent();
                                f.CopyTo(fCopy);
                                proj.Features.Add(fCopy);
                            }
                        }
                        // tinybooter has 1 library to start with
                        if (proj.Libraries.Count < 2)
                        {
                            foreach (MFComponent l in defProj.Libraries)
                            {
                                MFComponent lCopy = new MFComponent();
                                l.CopyTo(lCopy);
                                proj.Libraries.Add(lCopy);
                            }
                        }
                    }
                }
            }

            //tv_LibraryView.Nodes.Clear();
            //cbProjectSelect_Library.Items.Clear();

            if (m_HasClrProj)
            {
                tv_FeatureView.Nodes.Clear();
                cbProjectSelect_Feature.Items.Clear();

                e.Page = wpChooseFeatures;
            }
            else if (m_solution.Projects.Count > 0)
            {
                e.Page = wpChooseLibraries;
            }
            else
            {
                MessageBox.Show(this, Properties.Resources.ErrorNoProjects, Properties.Resources.SolutionWizard, MessageBoxButtons.OK, MessageBoxIcon.Error );
                e.Page = wpChooseProjects;
            }
        }
        private void addDependencyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            TreeNode tn = treeViewInventory.SelectedNode;

            if (tn == null) return;

            TreeNodeData tnd = treeViewInventory.SelectedNode.Tag as TreeNodeData;

            if (tnd != null)
            {
                List<MFComponent> items = tnd.Data as List<MFComponent>;

                if (items != null)
                {
                    switch (tn.Text)
                    {
                        case "FeatureAssociations":
                            MFComponent cmp = new MFComponent(MFComponentType.Feature, "Select Feature");
                            items.Add(cmp);
                            AddNodeEnumToPropertyGrid("Feature", cmp.Name, cmp, treeViewInventory.Nodes[0].Nodes["Features"], new ToolStripItemClickedEventHandler(OnFeatureSelect));
                            break;
                    }
                }
            }
        }
        /// <summary>
        /// Find a feature node in the feature view tree from the given root node (recursive)
        /// </summary>
        /// <param name="feature"></param>
        /// <param name="root"></param>
        /// <returns></returns>
        TreeNode FindFeatureNode(MFComponent feature, TreeNode root)
        {
            ComponentTreeNode ctn = root.Tag as ComponentTreeNode;

            if(ctn != null && (string.Compare(ctn.Comp.Guid, feature.Guid, true) == 0))
            {
                return root;
            }

            foreach (TreeNode tn in root.Nodes)
            {
                TreeNode found = FindFeatureNode(feature, tn);

                if (found != null)
                {
                    return found;
                }
            }

            return null;
        }
        /// <summary>
        /// Apply user "check/uncheck" to all project nodes if "All Projects" is selected, otherwise
        /// just to the selected project.
        /// </summary>
        /// <param name="pcdAll"></param>
        /// <param name="compGuid"></param>
        /// <param name="fAdd"></param>
        private void ApplyToAllProjects(ProjectComboData pcd, MFComponent comp, bool fCheck)
        {
            ApplyToProject(pcd, comp, fCheck, null, null);

            if (pcd == m_pcdAll)
            {
                foreach (ProjectComboData pcd2 in cbProjectSelect_Library.Items)
                {
                    if (pcd2 != pcd)
                    {
                        // change the component to a bootloader component if it exists
                        if (pcd2.Proj.IsBootloaderProject())
                        {
                            Library lib = m_helper.FindLibrary(comp);

                            if (lib != null && lib.HasLibraryCategory)
                            {
                                LibraryCategory lc = m_helper.FindLibraryCategory(lib.LibraryCategory.Guid);

                                if (lc != null)
                                {
                                    foreach (Library li in m_helper.GetLibrariesOfType(lc))
                                    {
                                        if (li.IsBootloaderLibrary())
                                        {
                                            comp = new MFComponent(MFComponentType.Library, li.Name, li.Guid, li.ProjectPath, comp.Conditional);
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                        ApplyToProject(pcd2, comp, fCheck, null, null);
                    }
                }
            }
            else if(pcd.Name.ToLower() == "tinyclr")
            {
                ApplyToProject(m_pcdAll, comp, fCheck, null, null);
            }
        }
        private void ApplyToProject(ProjectComboData pcd, MFComponent comp, bool fCheck, List<LibraryCategory> unresolvedItems, List<LibraryCategory>removedItems)
        {
            bool fActiveProj = (cbProjectSelect_Library.SelectedItem == pcd);

            bool fContainsLib = pcd.Proj.Libraries.Contains(comp);

            if (fCheck)
            {
                if (fContainsLib && pcd != m_pcdAll) return;
                pcd.Proj.Libraries.Add(comp);
            }
            else
            {
                if (!fContainsLib && pcd != m_pcdAll) return;
                pcd.Proj.RemoveLibrary(comp);
            }

            if (unresolvedItems == null || removedItems == null)
            {
                unresolvedItems = new List<LibraryCategory>();
                removedItems = new List<LibraryCategory>();

                pcd.Proj.AnalyzeLibraries(m_helper, m_solution, unresolvedItems, removedItems);
            }

            if (fActiveProj && tv_LibraryView.Nodes.Count > 0)
            {
                if (fCheck)
                {
                    foreach (LibraryCategory lc in unresolvedItems)
                    {
                        if (tv_LibraryView.Nodes.Find(lc.Guid.ToLower(), true).Length == 0)
                        {
                            AddGenerateTemplateNode(pcd, lc);

                            Library sel = AutoSelectLibrary(pcd, lc);

                            TreeNode lcNode = tv_LibraryView.Nodes[0].Nodes.Add(lc.Guid.ToLower(), lc.Name);
                            lcNode.Tag = new MFComponent(MFComponentType.LibraryCategory, lc.Name, lc.Guid, lc.ProjectPath);

                            foreach (Library lib in m_helper.GetLibrariesOfType(lc, pcd.Proj, m_solution))
                            {
                                if (pcd.Proj.ValidateLibrary(lib, m_solution, m_solutionProc, m_helper))
                                {
                                    TreeNode tnLib = lcNode.Nodes.Add(lib.Guid.ToLower(), lib.Name);
                                    tnLib.Tag = new MFComponent(MFComponentType.Library, lib.Name, lib.Guid, lib.ProjectPath);

                                    if (sel == lib)
                                    {
                                        tnLib.Checked = true;
                                    }
                                }
                            }

                            lcNode.Expand();
                        }
                    }
                }
                else
                {
                    foreach (LibraryCategory lc in removedItems)
                    {
                        TreeNode[] nds = tv_LibraryView.Nodes.Find(lc.Guid.ToLower(), true);
                        if (nds.Length > 0)
                        {
                            nds[0].Remove();
                        }
                    }
                }
            }
        }
        public Library FindLibrary(MFComponent comp)
        {
            if (comp.ComponentType != MFComponentType.Library) return null;

            Library l = FindLibrary(comp.Guid);

            if (l == null) l = FindLibraryByProject(comp.ProjectPath);
            if (l == null) l = FindLibraryByFile(comp.Name + ".$(LIB_EXT)");

            // some components are delay loaded, so fill in the data if need be
            if (l != null && (0 != string.Compare(comp.Guid, l.Guid, true)))
            {
                comp.Guid = l.Guid;
                comp.Name = l.Name;
                comp.ProjectPath = l.ProjectPath;
            }

            return l;
        }
 public MFComponentHash(Library lib, LibraryCategory type, MFComponent comp)
 {
     Library = lib;
     LibraryCategory = type;
     MFComponent = comp;
 }
        public bool RemoveLibrary(MFComponent compLibrary)
        {
            if (compLibrary.ComponentType != MFComponentType.Library) return false;

            return librariesField.Remove(FindLibrary(compLibrary.Guid));
        }
        internal Library LoadLibraryFromManifest(string libManifestFile)
        {
            Project proj;
            Library lib = null;

            string fullpath = ExpandEnvVars(libManifestFile, "");

            try
            {
                if (File.Exists(fullpath))
                {
                    lib = new Library();

                    proj = LoadProject(fullpath);

                    Dictionary<string, string> tbl = new Dictionary<string, string>();
                    tbl["AssemblyName"] = "Name";
                    tbl["ProjectGuid"] = "Guid";

                    LoadStringProps(proj, lib, tbl);

                    Library dbLib = m_helper.FindLibrary(lib.Guid);
                    if (dbLib != null)
                    {
                        System.Diagnostics.Debug.Assert(0 == string.Compare(lib.Guid, dbLib.Guid, true));
                        return dbLib;
                    }

                    foreach (ProjectImportElement imp in proj.Xml.Imports)
                    {
                        switch (Path.GetExtension(imp.Project).ToUpper().Trim())
                        {
                            case ".LIBCATPROJ":
                                LibraryCategory lc = LoadLibraryCategoryProj(imp.Project, Path.GetDirectoryName(fullpath));
                                if (lc != null)
                                {
                                    MFComponent cmp = new MFComponent(MFComponentType.LibraryCategory, lc.Name, lc.Guid, lc.ProjectPath);
                                    lib.Dependencies.Add(cmp);
                                }
                                else
                                {
                                    System.Diagnostics.Debug.Assert(false);
                                }
                                break;
                        }
                    }

                    m_helper.AddLibraryToInventory(lib, true, m_helper.DefaultInventory);
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine("Error: loading Library file: " + fullpath + "\r\n", e.Message);
                lib = null;
            }
            
            return lib;
        }
 public void CopyTo(MFComponent dest)
 {
     CopyHelper.CopyTo(this, dest);
 }
        private void RecurseFeatureDeps(MFComponent cmpFeat, List<MFComponent> features, InventoryHelper helper)
        {
            if (features.Contains(cmpFeat)) return;

            Feature feat = helper.FindFeature(cmpFeat.Guid);

            if(feat != null)
            {
                foreach (MFComponent depFeat in feat.FeatureDependencies)
                {
                    RecurseFeatureDeps(depFeat, features, helper);
                }

                features.Add(cmpFeat);
            }
            else
            {
                Console.WriteLine("Error: Feature not found: " + cmpFeat.Name);
            }
        }
        public void AnalyzeFeatures(InventoryHelper helper)
        {
            List<MFComponent> features = new List<MFComponent>();

            foreach (Feature feat in helper.GetRequiredFeatures())
            {
                MFComponent cmp = new MFComponent(MFComponentType.Feature, feat.Name, feat.Guid, feat.ProjectPath);

                if (!features.Contains(cmp))
                {
                    features.Add(cmp);
                }
            }

            foreach (MFComponent cmpFeat in featuresField)
            {
                RecurseFeatureDeps(cmpFeat, features, helper);
            }

            this.featuresField.Clear();
            foreach (MFComponent cmpFeat in features)
            {
                this.featuresField.Add(cmpFeat);
            }
        }
        internal Feature LoadFeatureProj(string featureProjFile, string path)
        {
            Project proj;
            string fullpath = ExpandEnvVars(featureProjFile, path);
            Feature feat = null;

            try
            {
                feat = m_helper.FindFeatureByProject(fullpath);

                if (feat != null) return feat;

                feat = new Feature();

                if (!File.Exists(fullpath))
                {
                    // TODO: add logging support
                    return null;
                }

                proj = LoadProject(fullpath);

                path = Path.GetDirectoryName(fullpath);
                feat.ProjectPath = ConvertPathToEnv(featureProjFile);

                Dictionary<string, string> tbl = new Dictionary<string, string>();
                tbl["FeatureName"] = "Name";
                tbl["Filter"] = "Filter";

                LoadStringProps(proj, feat, tbl);

                if (string.IsNullOrEmpty(feat.Guid)) feat.Guid = System.Guid.NewGuid().ToString("B");


                foreach (ProjectItemGroupElement big in proj.Xml.ItemGroups)
                {
                    foreach (ProjectItemElement bi in big.Items)
                    {
                        string cond = CombineConditionals(big.Condition, bi.Condition);

                        switch (bi.ItemType)
                        {
                            case "RequiredManagedProjects":
                                {
                                    MFAssembly asm = LoadAssemblyProj(bi.Include, path);

                                    if (asm != null)
                                    {
                                        MFComponent asmRef = new MFComponent(MFComponentType.MFAssembly);

                                        asmRef.Name = asm.Name;
                                        asmRef.Guid = asm.Guid;
                                        asmRef.ProjectPath = asm.ProjectPath;
                                        asmRef.Conditional = cond;

                                        feat.Assemblies.Add(asmRef);
                                    }
                                }
                                break;
                            case "RequiredProjects":
                                string test = Path.GetExtension(bi.Include).ToUpper();

                                switch (test)
                                {
                                    case ".FEATUREPROJ":
                                        System.Diagnostics.Debug.Assert(false, "Use ProjectImportElement for featureproj files");
                                        break;
                                    case ".LIBCATPROJ":
                                        System.Diagnostics.Debug.Assert(false, "Use ProjectImportElement for libcatproj files");
                                        break;
                                    case ".PROJ":
                                        Library lib = LoadLibraryProj(bi.Include, path);
                                        if (lib != null)
                                        {
                                            feat.ComponentDependencies.Add(new MFComponent(MFComponentType.Library, lib.Name, lib.Guid, bi.Include, cond));
                                        }
                                        else
                                        {
                                            //TODO: ERROR LOGGING
                                        }
                                        break;
                                }
                                break;
                            // ignore
                            case "MMP_DAT_CreateDatabase":
                            case "InteropFeature":
                                break;
                            default:
                                Console.WriteLine("Warning: Unknown ProjectItemElement " + bi.ItemType);
                                break;

                        }
                    }

                }

                // featureproj and libcatproj files are imported
                foreach (ProjectImportElement imp in proj.Xml.Imports)
                {
                    switch (Path.GetExtension(imp.Project).ToUpper())
                    {
                        case ".FEATUREPROJ":
                            Feature f2 = LoadFeatureProj(imp.Project, path);
                            feat.FeatureDependencies.Add(new MFComponent(MFComponentType.Feature, f2.Name, f2.Guid, imp.Project, imp.Condition));
                            break;
                        case ".LIBCATPROJ":
                            LibraryCategory libcat = LoadLibraryCategoryProj(imp.Project, path);
                            feat.ComponentDependencies.Add(new MFComponent(MFComponentType.LibraryCategory, libcat.Name, libcat.Guid, libcat.ProjectPath));
                            break;
                    }
                }

                Feature dbFeat = null;

                if (!string.IsNullOrEmpty(feat.Guid)) dbFeat = m_helper.FindFeature(feat.Guid);

                if (dbFeat == null) dbFeat = m_helper.FindFeatureByName(feat.Name);

                if (null == dbFeat)
                {
                    m_helper.DefaultInventory.Features.Add(feat);
                }
                else
                {
                    feat = dbFeat;
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine("Error: loading feature file: " + fullpath + "\r\n", e.Message);
                feat = null;
            }

            return feat;
        }
        private void RecurseLibCatDeps(
                    MFComponent cmp,
                    Dictionary<string, MFComponent> unresolvedCatList,
                    InventoryHelper helper,
                    bool fDependency)
        {
            string key = cmp.Guid.ToLower();

            if (unresolvedCatList.ContainsKey(key)) return;

            if (cmp.ComponentType == MFComponentType.Library)
            {
                Library lib = helper.FindLibrary(cmp);

                if (lib != null)
                {
                    foreach (MFComponent dep in lib.Dependencies)
                    {
                        RecurseLibCatDeps(dep, unresolvedCatList, helper, true);
                    }
                }
            }
            else if (cmp.ComponentType == MFComponentType.LibraryCategory)
            {
                if (!unresolvedCatList.ContainsKey(key))
                {
                    unresolvedCatList[key] = cmp;
                }
            }
        }
        internal void CopyTemplateFiles(LibraryCategory libType, MFSolution solution, MFComponent compLibTemplate)
        {
            const string c_FastCompile      = @"fastcompile.cpp";
            const string c_FastCompileTag   = @"FastCompileCPPFile";

            string dstPath = Path.Combine(ExpandEnvVars(Path.GetDirectoryName(solution.ProjectPath), ""), "DeviceCode\\");

            List<string> reloadProjs = new List<string>();

            //Regex expRelPath = new Regex("([\\w\\W]*\\\\)([^\\\\]+\\\\[^\\\\]+)");
            //Regex expRemoveDeviceCode = new Regex("\\\\DeviceCode\\\\", RegexOptions.IgnoreCase);
            //Regex expRemoveStubDir = new Regex("\\\\stub[s]?\\\\", RegexOptions.IgnoreCase);
            Regex expStubReplace = new Regex("(?<!Is)(stub[s]?)", RegexOptions.IgnoreCase);
            //string relPath = "";

            foreach (ApiTemplate api in libType.Templates)
            {
                string src = ExpandEnvVars( api.FilePath, Environment.GetEnvironmentVariable("SPOCLIENT") );
                
                //
                // Make relative path based on path after \DeviceCode\ if it exists, otherwise up to two directories deep
                //
                //relPath = Path.GetDirectoryName(src);
                //string devCode = "\\devicecode\\";

                /*
                int idx = relPath.ToLower().IndexOf(devCode);
                
                if (idx != -1)
                {
                    idx += devCode.Length;

                    relPath = relPath.Substring(idx, relPath.Length - idx);
                }
                else
                {
                    Match m = expRelPath.Match(Path.GetDirectoryName(api.FilePath));
                    relPath = m.Groups[1].Value.ToLower();
                }
                */

                string dst = dstPath + libType.Name + "\\" + Path.GetFileName(api.FilePath);

                bool isProcFile = src.ToLower().Contains("\\processor\\");

                try
                {
                    // ignore fast compiles
                    if (-1 != dst.IndexOf(c_FastCompile, StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }

                    //dst = expRemoveStubDir.Replace(dst, "\\");

                    if (isProcFile)
                    {
                        dst = expStubReplace.Replace(dst, solution.Processor.Name);
                    }
                    else
                    {
                        dst = expStubReplace.Replace(dst, solution.Name);
                    }

                    if (!Directory.Exists(Path.GetDirectoryName(dst)))
                    {
                        Directory.CreateDirectory(Path.GetDirectoryName(dst));
                    }

                    if (File.Exists(dst))
                    {
                        continue;
                    }

                    //
                    // The source file may refer to "stubs" for function names or includes, we need to replace this
                    // with the solution (or processor) name
                    //
                    TextWriter tw = File.CreateText(dst);
                    TextReader tr = File.OpenText(src);

                    try
                    {
                        string txt = tr.ReadToEnd();

                        if (isProcFile)
                        {
                            txt = expStubReplace.Replace(txt, solution.Processor.Name);
                        }
                        else
                        {
                            txt = expStubReplace.Replace(txt, solution.Name);
                        }

                        Regex exp = new Regex("<IsStub>([\\w\\W]+)</IsStub>", RegexOptions.IgnoreCase);

                        txt = exp.Replace(txt, "<IsStub>false</IsStub>");

                        tw.Write(txt);
                    }
                    finally
                    {
                        tr.Close();
                        tw.Close();
                    }

                    File.SetAttributes(dst, FileAttributes.Normal);

                    if (0 == string.Compare(".proj", Path.GetExtension(dst), true))
                    {
                        Project p = LoadProject(dst);
                        p.Xml.DefaultTargets = "Build";

                        compLibTemplate.ProjectPath = ConvertPathToEnv(dst);

                        foreach (ProjectPropertyGroupElement pg in p.Xml.PropertyGroups)
                        {
                            foreach (ProjectPropertyElement bp in pg.Properties)
                            {
                                switch (bp.Name.ToLower())
                                {
                                    case "directory":
                                        bp.Value = RemoveSpoClient(Path.GetDirectoryName(dst));
                                        break;
                                    case "assemblyname":
                                        bp.Value = compLibTemplate.Name;
                                        break;
                                    case "projectpath":
                                        bp.Value = ConvertPathToEnv(dst);
                                        break;
                                    case "projectguid":
                                        bp.Value = compLibTemplate.Guid;
                                        break;
                                    case "libraryfile":
                                        bp.Value = compLibTemplate.Name + ".$(LIB_EXT)";
                                        break;
                                    case "manifestfile":
                                        bp.Value = compLibTemplate.Name + ".$(LIB_EXT).manifest";
                                        break;

                                }
                            }
                        }
                        foreach (ProjectItemGroupElement ig in p.Xml.ItemGroups)
                        {
                            ArrayList remove_list = new ArrayList();
                            foreach (ProjectItemElement bi in ig.Items)
                            {
                                if (bi.ItemType == c_FastCompileTag)
                                {
                                    remove_list.Add(bi);
                                    continue;
                                }

                                //dst = expRemoveStubDir.Replace(dst, "\\");

                                if (-1 != src.IndexOf("\\processor\\", StringComparison.CurrentCultureIgnoreCase))
                                {
                                    bi.Include = expStubReplace.Replace(bi.Include, solution.Processor.Name);
                                }
                                else
                                {
                                    bi.Include = expStubReplace.Replace(bi.Include, solution.Name);
                                }
                            }
                            foreach (ProjectItemElement bi in remove_list)
                            {
                                ig.RemoveChild(bi);
                            }
                        }
                        p.Save(dst);

                        reloadProjs.Add(dst);
                    }
                }
                catch(Exception e)
                {
                    System.Diagnostics.Debug.Print(e.ToString());
                    System.Diagnostics.Debug.Print("Unable to copy file: " + src + " to " + dst );
                }
            }
            foreach (string prj in reloadProjs)
            {
                LoadLibraryProj(prj, "", true);
            }
        }
        private void UpdateProjectDependencies(ProjectComboData pcd, List<LibraryCategory> unresolvedItems, List<LibraryCategory> removedItems)
        {
            bool fReanalyze = true;
            int retries = 20;

            List<TreeNode> nodeList = new List<TreeNode>();

            Dictionary<string, MFComponent> resolveMap = new Dictionary<string, MFComponent>();

            while (fReanalyze && retries-- > 0)
            {
                unresolvedItems.Clear();
                removedItems.Clear();

                //LoadProjectLibraryData(pcd, m_pcdAll, true);
                pcd.Proj.AnalyzeLibraries(m_helper, m_solution, unresolvedItems, removedItems);

                fReanalyze = (removedItems.Count > 0);

                foreach (LibraryCategory lc in unresolvedItems)
                {
                    if (!resolveMap.ContainsKey(lc.Guid))
                    {
                        AddGenerateTemplateNode(pcd, lc);

                        Library sel = AutoSelectLibrary(pcd, lc);

                        if (sel != null)
                        {
                            fReanalyze = true;

                            MFComponent cmpNew = new MFComponent(MFComponentType.Library, sel.Name, sel.Guid, sel.ProjectPath);

                            resolveMap[lc.Guid] = cmpNew;

                            ApplyToProject(pcd, cmpNew, true, unresolvedItems, removedItems);
                        }
                    }
                    else
                    {
                        ApplyToProject(pcd, resolveMap[lc.Guid], true, unresolvedItems, removedItems);
                    }
                }
            }
        }