public EditorContentObject(EditorApplication editor, string relativePath, string basePath, string currentPath)
     :base(editor)
 {
     RelativePath = relativePath;
     BasePath = basePath;
     CurrentPath = currentPath;
 }
        public EditorContentFile(EditorApplication editor, string relativePath, string basePath, string currentPath)
            : base(editor, relativePath, basePath, currentPath)
        {
            try
            {
                IsValid = File.Exists(currentPath);
            }
            catch (Exception ex)
            {
                ErrorString = ex.ToString();
                IsValid = false;
            } 
            
            var properties = GetContentInfo(false);

            if (properties != null)
            {
                processor = properties.Processor;
                importer = properties.Importer;
                buildAction = properties.BuildAction;
            }

            ResolveDefaultProcessorAndImporter();

        }
        public PackageBuilder(EditorApplication editor)
        {
            if (editor == null)
                throw new ArgumentNullException("editor");

            Editor = editor;
        }
 public EditorContentDirectory(EditorApplication editor, string relativePath, string basePath, string currentPath)
     :base(editor, relativePath, basePath, currentPath)
 {
     try
     {
         IsValid = Directory.Exists(currentPath);
     }
     catch (Exception ex)
     {
         ErrorString = ex.ToString();
         IsValid = false;
     }
 }
        private void Build_WrapBuildProcessTaskAsync(EditorApplication packageCopy, string contextId, Func<bool> buildTask)
        {
            Building = true;
            CanBuild = false;
            cancellationPending = false;
            BuildSucceeded = null;

            Editor.Status = "Building ...";

            System.Threading.Tasks.Task.Factory.StartNew(delegate
            {
                try
                {
                    try
                    {
                        XNAContextInit(packageCopy, contextId);

                        BuildSucceeded = buildTask();
                    }
                    catch (FatalBuildErrorException)
                    {
                        BuildSucceeded = false;
                    }
                    catch (Exception ex)
                    {
                        Build_Message(ex.ToString(), "BuildTask", BuildMessageSeverity.Error);
                        BuildSucceeded = false;
                    }

                    if (BuildSucceeded == true)
                        Build_Message("Build success", "BuildTask", BuildMessageSeverity.Information);
                    else
                        Build_Message("Build failed", "BuildTask", BuildMessageSeverity.Error);
                }
                finally
                {
                    XNAContextDispose();

                    CanBuild = true;
                    Building = false;

                    Editor.Status = BuildSucceeded == true ? "Build success" : "Build failed";
                }
            });
        }
        private static string GetOutputBaseDirectory(EditorApplication packageCopy)
        {
            var rootDirectory = Path.GetDirectoryName(packageCopy.CurrentPackagePath);

            var outputBaseDirectory = Path.IsPathRooted(packageCopy.CurrentPackage.OutputDirectory)
                ? packageCopy.CurrentPackage.OutputDirectory
                : Path.Combine(rootDirectory, packageCopy.CurrentPackage.OutputDirectory);
            return outputBaseDirectory;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="packageCopy"></param>
        /// <param name="contextId">contextId is used to isolate sub build configurations of the same package</param>
        private void XNAContextInit(EditorApplication packageCopy, string contextId)
        {
            var outputBaseDirectory = GetOutputBaseDirectory(packageCopy);

            XNAOutputDirectory = AbsoluteDirectoryConvert(Path.Combine(outputBaseDirectory, GetSafeContentDirectorySuffix(packageCopy)));

            /* each content has to have an independant intermediate directory, so we generate an unique key for them (approximately) */
            var xnaIntermediateSubDir = Path.Combine("obj", GenerateContentSubDirectory(packageCopy.CurrentPackagePath, contextId));
            XNAIntermediateDirectory = AbsoluteDirectoryConvert(Path.Combine(outputBaseDirectory, xnaIntermediateSubDir));

            if (!String.IsNullOrEmpty(contextId))
            {
                /* Because XNA always clear the content before compiling if it doesn't match its file, 
                 * we force a full rebuild when the context is not null (ie. SingleItemBuild)
                 */
                try
                {
                    var xnaContentXmlPath = Path.Combine(XNAIntermediateDirectory, "ContentPipeline.xml");

                    if (File.Exists(xnaContentXmlPath))
                        File.Delete(xnaContentXmlPath);
                }
                catch { }
            }

            XNALogger = new BuildLogger(this);
        }
        private string GetSafeContentDirectorySuffix(EditorApplication packageCopy)
        {
            string baseSuffix = packageCopy.CurrentPackage.ContentDirectorySuffix;

            if (String.IsNullOrEmpty(baseSuffix))
                baseSuffix = "Content";

            return baseSuffix;
        }
        private string GetOutputPathForFile(EditorApplication packageCopy, EditorContentFile file)
        {
            var rootDirectory = Path.GetDirectoryName(packageCopy.CurrentPackagePath);

            var outputBaseDirectory = Path.IsPathRooted(packageCopy.CurrentPackage.OutputDirectory)
                ? packageCopy.CurrentPackage.OutputDirectory
                : Path.Combine(rootDirectory, packageCopy.CurrentPackage.OutputDirectory);

            outputBaseDirectory += "\\" + GetSafeContentDirectorySuffix(packageCopy);

            var outputCompletePath = Path.Combine(outputBaseDirectory, file.RelativePath);

            var normalizedOutputCompletePath = Path.ChangeExtension(new FileInfo(outputCompletePath).FullName, CirrusContentManager.ContentFileExtention);

            return normalizedOutputCompletePath;
        }
        private bool XNA_Build_Execute(EditorApplication packageCopy, BuildContent build, IList<XNACirrusAsset> sourceAssets)
        {
            // the RootDirectory must contain the sourceFile to avoid an "%0" from being appended to the   
            // output file name  
            //  
            var computedRootDirectory = String.IsNullOrEmpty(packageCopy.CurrentPackage.BuildRootRelativeDirectory)
            ? GetContentBaseDirectory(packageCopy)
            : Path.Combine(GetContentBaseDirectory(packageCopy), packageCopy.CurrentPackage.BuildRootRelativeDirectory);

            Environment.CurrentDirectory = build.RootDirectory = computedRootDirectory;

            build.IntermediateDirectory = XNAIntermediateDirectory;
            build.LoggerRootDirectory = null;
            build.SourceAssets = (from sourceAsset in sourceAssets select sourceAsset.TaskItem).ToArray();

            for (int i = 0; i < sourceAssets.Count; ++i)
            {
                build.SourceAssets[i] = sourceAssets[i].TaskItem;
            }

            //const string xnaVersion = ", Version=2.0.0.0, PublicKeyToken=6d5c3888ef60e27d";  
            // TODO: Why is "Culture" required?  
            //const string xnaVersion = ", Version=3.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d";

            // Don't append .dll??? if loading from the GAC  
            build.PipelineAssemblies = (from xnaReference in packageCopy.CurrentPackage.XNAReferences select new TaskItem(ParseReferencePath(packageCopy, xnaReference.Reference))).ToArray();
            
            try
            {
                return build.Execute();
            }
            catch (Exception e)
            {
                Build_Message(e.Message, e.Source, BuildMessageSeverity.Error);
                return false;
            }
        }
        private string GetSourcePathForFile(EditorApplication packageCopy, EditorContentFile file)
        {
            var contentBaseDirectory = GetContentBaseDirectory(packageCopy);

            var inputCompletePath = Path.Combine(contentBaseDirectory, file.RelativePath);

            var normalizedInputCompletePath = new FileInfo(inputCompletePath).FullName;

            return normalizedInputCompletePath;
        }
        private bool ProcessPackageReference(EditorApplication packageCopy, string referencePath, string contextId, bool rebuild, bool compress, Predicate<EditorContentFile> filesFilter, List<string> callTree, List<string> builtPackages)
        {
            if (cancellationPending)
                return false;

            Build_Message(String.Format("--- Begin --- Referenced Package : {0}", referencePath), "PackageReferenceResolve", BuildMessageSeverity.Information);

            if (callTree.Contains(referencePath))
            {
                Build_Message("Circular reference identified, aborting", "PackageReferenceResolve", BuildMessageSeverity.Error);
                return false;
            }
            else
            {
                if (builtPackages.Contains(referencePath))
                {
                    Build_Message("--- Package already built. Skipping ...", "PackageReferenceResolve", BuildMessageSeverity.Information);
                    return true;
                }
                else
                {
                    var newCallTree = new List<string>();
                    newCallTree.AddRange(callTree);

                    EditorApplication referencedPackage;

                    using (var packageReferenceStream = new FileStream(referencePath, FileMode.Open, FileAccess.Read))
                    {
                        referencedPackage = Editor.LoadAndCreatePackageFromStream(packageReferenceStream, referencePath);
                    }

                    referencedPackage.CurrentPackage.OutputDirectory = GetOutputBaseDirectory(packageCopy);
                    referencedPackage.Builder.build_message_redirection = (msg, src, severity) =>
                    {
                        Build_Message(msg, src, severity);
                        referencedPackage.Builder.cancellationPending = cancellationPending;
                    };

                    var success = referencedPackage.Builder.Build_Sync_Execute(contextId, rebuild, compress, filesFilter, newCallTree, builtPackages);

                    if (success)
                    {
                        Build_Message(String.Format("--- End Success --- Referenced Package : {0}", referencePath), "PackageReferenceResolve", BuildMessageSeverity.Information);
                        return true;
                    }
                    else
                    {
                        Build_Message(String.Format("--- End Failed --- Referenced Package : {0}", referencePath), "PackageReferenceResolve", BuildMessageSeverity.Information);
                        return false;
                    }
                }
            }
        }
        private bool Build_Execute(EditorApplication packageCopy, string contextId, bool rebuild, bool compress, Predicate<EditorContentFile> filesFilter = null, List<string> callTree = null, List<string> builtPackages = null)
        {
            /* callTree is used to identify circular references */
            if (callTree == null)
                callTree = new List<string>();

            /* builtPackages is used to skip the recompilation of an already processed package reference */
            if (builtPackages == null)
                builtPackages = new List<string>();

            callTree.Add(packageCopy.CurrentPackagePath);

            /* first, processes referenced package */
            foreach (var packageReference in packageCopy.CurrentPackage.CirrusReferences)
            {
                if (!String.IsNullOrEmpty(packageReference.Reference))
                {
                    if (packageReference.Build)
                    {
                        var referencePath = ParseReferencePath(packageCopy, packageReference.Reference);

                        if (!ProcessPackageReference(packageCopy, referencePath, contextId, rebuild, compress, filesFilter, callTree, builtPackages))
                            return false;
                    }
                    else
                    {
                        Build_Message(String.Format("--- Ignore --- The package {0} has been ignored because not marked for Build", packageReference.Reference),
                            "PackageReferenceCondition", BuildMessageSeverity.Information);
                    }
                }
            }

            /* then process the current package*/
            var decodedAssets = new List<XNACirrusAsset>();

            bool success = Build_ActionForAllFiles(packageCopy, (file) =>
            {
                if (filesFilter == null || filesFilter(file))
                {
                    Build_ProcessFile(decodedAssets, packageCopy, file);
                }
                else
                    Build_Message("-- Skipped by filter");

                return true;
            });

            if (success)
            {
                var build = new BuildContent();
                // BuildEngine is used by TaskLoggingHelper, so an implementation must be provided  
                //  
                build.BuildEngine = new BuildEngine(this);
                build.RebuildAll = rebuild;
                build.CompressContent = compress;
                build.TargetProfile = GraphicsProfile.HiDef.ToString();
                build.BuildConfiguration = "Debug";
                build.TargetPlatform = TargetPlatform.Windows.ToString();

                build.OutputDirectory = XNAOutputDirectory;

                if (decodedAssets.Count > 0)
                {
                    success = XNA_Build_Execute(packageCopy, build, decodedAssets);
                }

                builtPackages.Add(packageCopy.CurrentPackagePath);
            }

            return success;
        }
        private string ParseReferencePath(EditorApplication packageCopy, string referenceName)
        {
            /* check to see if the reference is a local file */
            try
            {
                var fi = new FileInfo(Path.Combine(Path.GetDirectoryName(packageCopy.CurrentPackagePath), referenceName));
                if (fi.Exists)
                    return fi.FullName;
            }
            catch { }

            /* nope */
            return referenceName;
        }
 public EditorPackageContainerObject(EditorApplication editor)
     : base(editor)
 {
     AvailableXNATypes = new ObservableCollection<XNAAssemblyDescription>();
 }
        private void Build_ProcessFile(List<XNACirrusAsset> decodedAssets, EditorApplication packageCopy, EditorContentFile file)
        {
            var src = GetSourcePathForFile(packageCopy, file);
            var dst = GetOutputPathForFile(packageCopy, file);

            switch (file.BuildAction)
            {
                default:
                case Sora.GameEngine.Cirrus.Design.Packages.XmlBuildAction.None:
                    {
                        Build_Message("Ignored", "ProcessFile");
                        break;
                    }
                case Sora.GameEngine.Cirrus.Design.Packages.XmlBuildAction.Compile:
                    {
                        var importer = file.Importer;
                        var processor = file.Processor;

                        if (String.IsNullOrEmpty(importer) && String.IsNullOrEmpty(processor))
                        {
                            Build_Message("No importer or processor specified, copying to output");
                            goto case Sora.GameEngine.Cirrus.Design.Packages.XmlBuildAction.CopyToOutput;
                        }
                        else
                        {
                            //Build_Message(String.Format("Compiling {0} to {1}", src, dst), "ProcessFile");
                            //XNAFileCompile(packageCopy, file, src, dst);
                            decodedAssets.Add(new XNACirrusAsset(packageCopy, file));
                        }
                        break;
                    }
                case Sora.GameEngine.Cirrus.Design.Packages.XmlBuildAction.CopyToOutput:
                    {
                        Build_Message(String.Format("Copying {0} to {1}", src, dst), "ProcessFile");

                        var outDirectory = Path.GetDirectoryName(dst);
                        if (!Directory.Exists(outDirectory))
                            Directory.CreateDirectory(outDirectory);

                        File.Copy(src, dst, true);
                        break;
                    }
            }
        }
 public EditorPackageReferencesObject(EditorApplication editor)
     :base(editor)
 {
     Title = "Package References";
 }
        private bool Build_ActionForAllFiles(EditorApplication buildPackageApplication, Func<EditorContentFile, bool> action)
        {
            if (action != null)
            {
                /* We process files using depth traversal to ensure that lower level files will be evaluated before all
                 * high level files
                 * 
                 * This allows to build Levels depending on sub components placed below in the graph
                 */
                var enumeratorStack = new Stack<EditorContentObject>();

                /* we add the root files */
                enumeratorStack.Push(from obj in buildPackageApplication.PackageContainer[0].Content where obj is EditorContentFile select (EditorContentFile)obj);

                /* root directories */
                enumeratorStack.Push(from obj in buildPackageApplication.PackageContainer[0].Content where obj is EditorContentDirectory select (EditorContentDirectory)obj);


                /* and here we go */
                while (enumeratorStack.Count > 0)
                {
                    var current = enumeratorStack.Pop();
                    var as_file = current as EditorContentFile;
                    var as_directory = current as EditorContentDirectory;

                    if (as_directory != null)
                    {
                        Build_Message(String.Format("Directory - {0}", as_directory.RelativePath), "Build_EnumFiles", BuildMessageSeverity.Information);
                        
                        /* sub files */
                        enumeratorStack.Push(from element in as_directory.Content where element is EditorContentFile select (EditorContentObject)element);

                        /* sub directories */
                        enumeratorStack.Push(from element in as_directory.Content where element is EditorContentDirectory orderby ((EditorContentDirectory)element).BuildOrder select (EditorContentObject)element);


                        if (!as_directory.IsValid)
                            Build_Message(String.Format("Directory {0} was marked as invalid", as_directory.RelativePath), "Build_EnumFiles", BuildMessageSeverity.Warning);
                    }
                    else if (as_file != null)
                    {
                        Build_Message(String.Format("File - {0}", as_file.RelativePath), "Build_EnumFiles", BuildMessageSeverity.Information);

                        if (cancellationPending)
                        {
                            Build_Message("Compilation aborted", "Build_EnumFiles", BuildMessageSeverity.Error);
                            return false;
                        }

                        if (!as_file.IsValid)
                            Build_Message(String.Format("File {0} was marked as invalid", as_file.RelativePath), "Build_EnumFiles", BuildMessageSeverity.Warning);
                        else
                        {
                            var process_result = action(as_file);

                            if (!process_result)
                            {
                                Build_Message(String.Format("File {0} aborted the compilation", as_file.RelativePath), "Build_EnumFiles", BuildMessageSeverity.Error);
                                return false;
                            }
                        }
                    }

                    if (cancellationPending)
                    {
                        Build_Message("Compilation aborted", "Build_EnumFiles", BuildMessageSeverity.Error);
                        return false;
                    }
                }

                return true;
            }
            else
                return true;
        }