#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using ANX.Framework.Content.Pipeline.Serialization.Compiler;
using ANX.Framework.Graphics;

#endregion

// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
// For details see: http://anxframework.codeplex.com/license

namespace ANX.Framework.Content.Pipeline.Tasks
{
    public class BuildContent
    {
        private ImporterManager importerManager;
        private ProcessorManager processorManager;
        private ContentCompiler contentCompiler;

        public BuildContent()
        {
            OutputDirectory = Environment.CurrentDirectory;
            TargetPlatform = TargetPlatform.Windows;
            CompressContent = false;
            TargetProfile = GraphicsProfile.HiDef;
        }

        public ImporterManager ImporterManager
        {
            get
            {
                if (this.importerManager == null)
                {
                    this.importerManager = new ImporterManager();
                }

                return this.importerManager;
            }
        }

        public ProcessorManager ProcessorManager
        {
            get
            {
                if (this.processorManager == null)
                {
                    this.processorManager = new ProcessorManager();
                }

                return this.processorManager;
            }
        }

        public ContentCompiler ContentCompiler
        {
            get
            {
                if (this.contentCompiler == null)
                {
                    this.contentCompiler = new ContentCompiler();
                }

                return this.contentCompiler;
            }
        }

        public string OutputDirectory
        {
            get;
            set;
        }

        public TargetPlatform TargetPlatform
        {
            get;
            set;
        }

        public bool CompressContent
        {
            get;
            set;
        }

        public GraphicsProfile TargetProfile
        {
            get;
            set;
        }

        public ContentBuildLogger BuildLogger
        {
            get;
            set;
        }

        public void Execute(IEnumerable<BuildItem> itemsToBuild)
        {
            foreach (BuildItem buildItem in itemsToBuild)
            {
                var importedObject = ImportAsset(buildItem);

                if (String.IsNullOrEmpty(buildItem.BuildRequest.ProcessorName))
                {
                    buildItem.BuildRequest.ProcessorName = ProcessorManager.GetProcessorForType(importedObject.GetType());
                }

                var buildedItem = Process(buildItem, importedObject);

                SerializeAsset(buildItem, buildedItem);
            }
        }

        private object ImportAsset(BuildItem item)
        {
            IContentImporter instance = this.ImporterManager.GetInstance(item.BuildRequest.ImporterName);
            ContentImporterContext context = new AnxContentImporterContext(this, item, BuildLogger);
            BuildLogger.LogMessage("building {0} of type {1}", new object[]
            {
                item.BuildRequest.SourceFilename,
                instance.GetType()
            });
            return instance.Import(item.BuildRequest.SourceFilename, context);
        }

        private object Process(BuildItem item, object importedObject)
        {
            if (String.IsNullOrEmpty(item.BuildRequest.ProcessorName) == false)
            {
                IContentProcessor instance = this.ProcessorManager.GetInstance(item.BuildRequest.ProcessorName);
                ContentProcessorContext context = new AnxContentProcessorContext(item, BuildLogger, TargetPlatform, TargetProfile, "");
                context.OutputDirectory = OutputDirectory;
                context.OutputFilename = item.OutputFilename;
                return instance.Process(importedObject, context);
            }
            else
            {
                return importedObject;
            }
        }

        private void SerializeAsset(BuildItem item, object assetData)
        {
            string outputFilename = Path.Combine(OutputDirectory, item.OutputFilename);

            BuildLogger.LogMessage("serializing {0}", new object[] { item.OutputFilename });
            using (Stream stream = new FileStream(outputFilename, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                this.ContentCompiler.Compile(stream, assetData, TargetPlatform, TargetProfile, CompressContent, OutputDirectory, outputFilename);
            }
            //this.rebuiltFiles.Add(outputFilename);
        }

    }
}