/// <summary>
 /// Writes delta for query sequences.
 /// </summary>
 /// <param name="delta">The Deltas.</param>
 /// <param name="sorter">Sorter instance.</param>
 private static void WriteUnsortedDelta(IEnumerable<DeltaAlignment> delta, DeltaAlignmentSorter sorter)
 {
     using (var writer = new StreamWriter(UnsortedDeltaFile))
     {
         long deltaPositionInFile = 0;
         foreach (DeltaAlignment deltaAlignment in delta)
         {
             deltaAlignment.Id = deltaPositionInFile;
             string deltaString = Helper.GetString(deltaAlignment);
             deltaPositionInFile += deltaString.Length;
             writer.Write(deltaString);
             sorter.Add(deltaAlignment.Id, deltaAlignment.FirstSequenceStart);
         }
     }
 }
        /// <summary>
        /// Resolve ambiguity in the delta alignments.
        /// </summary>
        public void ResolveAmbiguity()
        {
            TimeSpan repeatResolutionSpan = new TimeSpan();
            Stopwatch runRepeatResolution = new Stopwatch();

            runRepeatResolution.Restart();
            FileInfo inputFileinfo = new FileInfo(this.FilePath[1]);
            long inputFileLength = inputFileinfo.Length;
            runRepeatResolution.Stop();

            if (this.Verbose)
            {
                Console.Error.WriteLine();
                Console.Error.WriteLine("  Processed Query FastA file: {0}", Path.GetFullPath(this.FilePath[1]));
                Console.Error.WriteLine("            Read/Processing time: {0}", runRepeatResolution.Elapsed);
                Console.Error.WriteLine("            File Size           : {0}", inputFileLength);
            }

            inputFileinfo = new FileInfo(this.FilePath[0]);
            inputFileLength = inputFileinfo.Length;

            runRepeatResolution.Restart();
            DeltaAlignmentSorter sorter = null;
            using (var alignmentStream = File.OpenRead(this.FilePath[0]))
            using (var readStream = File.OpenRead(this.FilePath[1]))
            using (DeltaAlignmentCollection deltaCollection = new DeltaAlignmentCollection(alignmentStream, readStream))
            {
                runRepeatResolution.Stop();

                if (this.Verbose)
                {
                    Console.Error.WriteLine();
                    Console.Error.WriteLine("  Processed DeltaAlignment file: {0}", Path.GetFullPath(this.FilePath[0]));
                    Console.Error.WriteLine("            Read/Processing time: {0}", runRepeatResolution.Elapsed);
                    Console.Error.WriteLine("            File Size           : {0}", inputFileLength);
                }

                runRepeatResolution.Restart();
                IEnumerable<DeltaAlignment> outputDeltas = RepeatResolver.ResolveAmbiguity(deltaCollection);
                sorter = new DeltaAlignmentSorter();
                WriteUnsortedDelta(outputDeltas, sorter);
            }

            runRepeatResolution.Stop();
            repeatResolutionSpan = repeatResolutionSpan.Add(runRepeatResolution.Elapsed);
            runRepeatResolution.Restart();
            this.WriteDelta(sorter);
            runRepeatResolution.Stop();

            if (this.Verbose)
            {
                Console.Error.WriteLine("  Compute time: {0}", repeatResolutionSpan);
                Console.Error.WriteLine("  Write() time: {0}", runRepeatResolution.Elapsed);
            }
        }
        /// <summary>
        /// Writes delta for query sequences.
        /// </summary>
        /// <param name="sorter">Sorter instance.</param>
        /// <param name="unsortedDeltaStream">Unsorted Delta Filename.</param>
        /// <param name="queryParser">Query/read sequences parser.</param>
        /// <param name="outputStream">Output file name.</param>
        public static void WriteSortedDelta(DeltaAlignmentSorter sorter, Stream unsortedDeltaStream, FastASequencePositionParser queryParser, Stream outputStream)
        {
            if (sorter == null)
            {
                throw new ArgumentNullException("sorter");
            }

            using (DeltaAlignmentParser unsortedDeltaParser = new DeltaAlignmentParser(unsortedDeltaStream, queryParser))
            {
                using (StreamWriter writer = new StreamWriter(outputStream))
                {
                    long deltaPositionInFile = 0;
                    foreach (long id in sorter.GetSortedIds())
                    {
                        DeltaAlignment deltaAlignment = unsortedDeltaParser.GetDeltaAlignmentAt(id);
                        deltaAlignment.Id = deltaPositionInFile;
                        string deltaString = Helper.GetString(deltaAlignment);
                        deltaPositionInFile += deltaString.Length;
                        writer.Write(deltaString);
                    }

                    writer.Flush();
                }
            }
        }
        /// <summary>
        /// Writes delta for query sequences.
        /// </summary>
        /// <param name="sorter">The Deltas.</param>
        private void WriteDelta(DeltaAlignmentSorter sorter)
        {
            TextWriter textWriterConsoleOutSave = Console.Out;
            StreamWriter streamWriterConsoleOut = null;

            try
            {
                using (var reads = File.OpenRead(this.FilePath[1]))
                using (var unsortedDeltas = File.OpenRead(UnsortedDeltaFile))
                using (var sequenceParser = new FastASequencePositionParser(reads, true))
                using (var unsortedDeltaParser = new DeltaAlignmentParser(unsortedDeltas, sequenceParser))
                {
                    if (!string.IsNullOrEmpty(this.OutputFile))
                    {
                        streamWriterConsoleOut = new StreamWriter(this.OutputFile);
                        Console.SetOut(streamWriterConsoleOut);
                    }

                    long deltaPositionInFile = 0;

                    foreach (long id in sorter.GetSortedIds())
                    {
                        DeltaAlignment deltaAlignment = unsortedDeltaParser.GetDeltaAlignmentAt(id);

                        deltaAlignment.Id = deltaPositionInFile;
                        string deltaString = Helper.GetString(deltaAlignment);
                        deltaPositionInFile += deltaString.Length;
                        Console.Write(deltaString);
                    }

                    Console.Out.Flush();
                }
            }
            finally
            {
                if (streamWriterConsoleOut != null)
                    streamWriterConsoleOut.Dispose();
                Console.SetOut(textWriterConsoleOutSave);
            }
        }
        /// <summary>
        /// Writes delta for query sequences.
        /// </summary>
        /// <param name="delta">The Deltas.</param>
        /// <param name="sorter">Sorter instance.</param>
        /// <param name="outputStream">Output file name.</param>
        public static void WriteUnsortedDelta(IEnumerable<DeltaAlignment> delta, DeltaAlignmentSorter sorter, Stream outputStream)
        {
            using (StreamWriter writer = new StreamWriter(outputStream))
            {
                long deltaPositionInFile = 0;
                foreach (DeltaAlignment deltaAlignment in delta)
                {
                    deltaAlignment.Id = deltaPositionInFile;
                    string deltaString = Helper.GetString(deltaAlignment);
                    deltaPositionInFile += deltaString.Length;
                    writer.Write(deltaString);
                    sorter.Add(deltaAlignment.Id, deltaAlignment.FirstSequenceStart);
                }

                writer.Flush();
            }
        }
        /// <summary>
        /// Assemble the input sequences into the largest possible contigs. 
        /// </summary>
        /// <param name="referenceSequence">The sequence used as backbone for assembly.</param>
        /// <param name="queryParser">The parser to load the sequences to assemble.</param>
        /// <returns>IComparativeAssembly instance which contains list of assembled sequences.</returns>
        public IEnumerable<ISequence> Assemble(IEnumerable<ISequence> referenceSequence, FastASequencePositionParser queryParser)
        {
            if (referenceSequence == null)
            {
                throw new ArgumentNullException("referenceSequence");
            }

            if (queryParser == null)
            {
                throw new ArgumentNullException("queryParser");
            }

            Stream readAlignmentOutputStream = null;
            Stream unsortedRepeatResolutionOutputStream = null;
            Stream repeatResolutionOutputStream = null;
            Stream unsortedLayoutRefinmentOutputStream = null;
            Stream layoutRefinmentOutputStream = null;

            try
            {
                // Converting to list to avoid multiple parse of the reference file if its a yield return
                var refSequences = referenceSequence.ToList();

                // CacheSequencesForRandomAccess will ignore the call if called more than once.
                queryParser.CacheSequencesForRandomAccess();
                IEnumerable<ISequence> reads = queryParser.Parse();

                // Comparative Assembly Steps
                // 1) Read Alignment (Calling NUCmer for aligning reads to reference sequence)
                this.StatusEventStart(Properties.Resource.ReadAlignmentStarted);
                IEnumerable<DeltaAlignment> alignmentBetweenReferenceAndReads = this.ReadAlignment(refSequences, 
                            reads.Where(a => a.Count >= this.LengthOfMum));

                readAlignmentOutputStream = PlatformManager.Services.CreateTempStream();
                WriteDelta(alignmentBetweenReferenceAndReads, readAlignmentOutputStream);
                this.StatusEventEnd(Properties.Resource.ReadAlignmentEnded);

                // 2) Repeat Resolution
                this.StatusEventStart(Properties.Resource.RepeatResolutionStarted);
                DeltaAlignmentSorter sorter;

                unsortedRepeatResolutionOutputStream = PlatformManager.Services.CreateTempStream();
                using (var deltaAlignmentFromReadAlignment = new DeltaAlignmentCollection(readAlignmentOutputStream, queryParser))
                {
                    IEnumerable<DeltaAlignment> repeatResolvedDeltas = RepeatResolution(deltaAlignmentFromReadAlignment);
                    sorter = new DeltaAlignmentSorter(refSequences[0].Count);
                    WriteUnsortedDelta(repeatResolvedDeltas, sorter, unsortedRepeatResolutionOutputStream);
                }

                this.StatusEventEnd(Properties.Resource.RepeatResolutionEnded);
                this.StatusEventStart(Properties.Resource.SortingResolvedDeltasStarted);

                repeatResolutionOutputStream = PlatformManager.Services.CreateTempStream();
                WriteSortedDelta(sorter, unsortedRepeatResolutionOutputStream, queryParser, repeatResolutionOutputStream);
                this.StatusEventEnd(Properties.Resource.SortingResolvedDeltasEnded);

                // 3) Layout Refinement
                this.StatusEventStart(Properties.Resource.LayoutRefinementStarted);

                layoutRefinmentOutputStream = PlatformManager.Services.CreateTempStream();
                using (var unsortedDeltaCollectionForLayoutRefinment = new DeltaAlignmentCollection(repeatResolutionOutputStream, queryParser))
                {
                    unsortedLayoutRefinmentOutputStream = PlatformManager.Services.CreateTempStream();
                    IEnumerable<DeltaAlignment> layoutRefinedDeltas = LayoutRefinment(unsortedDeltaCollectionForLayoutRefinment);
                    sorter = new DeltaAlignmentSorter(refSequences[0].Count);
                    WriteUnsortedDelta(layoutRefinedDeltas, sorter, unsortedLayoutRefinmentOutputStream);
                    WriteSortedDelta(sorter, unsortedLayoutRefinmentOutputStream, queryParser, layoutRefinmentOutputStream);
                }

                this.StatusEventEnd(Properties.Resource.LayoutRefinementEnded);

                // 4) Consensus Generation
                this.StatusEventStart(Properties.Resource.ConsensusGenerationStarted);
                IList<ISequence> contigs;
                using (var delta = new DeltaAlignmentCollection(layoutRefinmentOutputStream, queryParser))
                {
                    contigs = this.ConsensusGenerator(delta).ToList();
                }
                this.StatusEventEnd(Properties.Resource.ConsensusGenerationEnded);

                if (this.ScaffoldingEnabled)
                {
                    // 5) Scaffold Generation
                    this.StatusEventStart(Properties.Resource.ScaffoldGenerationStarted);
                    IEnumerable<ISequence> scaffolds = this.ScaffoldsGenerator(contigs, reads);
                    this.StatusEventEnd(Properties.Resource.ScaffoldGenerationEnded);
                    return scaffolds;
                }
                else
                {
                    return contigs;
                }
            }
            finally
            {
                // Cleanup temp files.
                if (readAlignmentOutputStream != null)
                    readAlignmentOutputStream.Dispose();
                if (unsortedRepeatResolutionOutputStream != null)
                    unsortedRepeatResolutionOutputStream.Dispose();
                if (repeatResolutionOutputStream != null)
                    repeatResolutionOutputStream.Dispose();
                if (unsortedLayoutRefinmentOutputStream != null)
                    unsortedLayoutRefinmentOutputStream.Dispose();
                if (layoutRefinmentOutputStream != null)
                    layoutRefinmentOutputStream.Dispose();
            }
        }
        /// <summary>
        /// Refine layout in the delta alignments.
        /// </summary>
        public void RefineLayout()
        {
            TimeSpan timeSpan = new TimeSpan();
            Stopwatch runAlgorithm = new Stopwatch();

            runAlgorithm.Restart();
            FileInfo inputFileinfo = new FileInfo(this.FilePath[1]);
            long inputFileLength = inputFileinfo.Length;
            FastASequencePositionParser queryParser;
            using(var input = File.OpenRead(FilePath[1]))
            {
                queryParser = new FastASequencePositionParser(input, true);
                queryParser.CacheSequencesForRandomAccess();
            }
            runAlgorithm.Stop();

            if (this.Verbose)
            {
                Output.WriteLine(OutputLevel.Verbose);
                Output.WriteLine(OutputLevel.Verbose, "Processed Query FastA file: {0}", Path.GetFullPath(this.FilePath[1]));
                Output.WriteLine(OutputLevel.Verbose, "   Read/Processing time   : {0}", runAlgorithm.Elapsed);
                Output.WriteLine(OutputLevel.Verbose, "   File Size              : {0}", inputFileLength);
            }

            inputFileinfo = new FileInfo(this.FilePath[0]);
            inputFileLength = inputFileinfo.Length;
            runAlgorithm.Restart();
            using (var input = File.OpenRead(FilePath[0]))
            using (DeltaAlignmentCollection deltaCollection = new DeltaAlignmentCollection(input, queryParser))
            {
                runAlgorithm.Stop();

                if (this.Verbose)
                {
                    Output.WriteLine(OutputLevel.Verbose);
                    Output.WriteLine(OutputLevel.Verbose, "Processed DeltaAlignment file: {0}", Path.GetFullPath(this.FilePath[0]));
                    Output.WriteLine(OutputLevel.Verbose, "   Read/Processing time      : {0}", runAlgorithm.Elapsed);
                    Output.WriteLine(OutputLevel.Verbose, "   File Size                 : {0}", inputFileLength);
                }

                runAlgorithm.Restart();
                IEnumerable<DeltaAlignment> result = LayoutRefiner.RefineLayout(deltaCollection);
                DeltaAlignmentSorter sorter = new DeltaAlignmentSorter();
                WriteDelta(result, sorter, UnsortedLayoutRefinmentOutputFilename);
                runAlgorithm.Stop();
                timeSpan = timeSpan.Add(runAlgorithm.Elapsed);

                runAlgorithm.Restart();
                WriteSortedDelta(sorter, UnsortedLayoutRefinmentOutputFilename, queryParser, this.OutputFile);
                runAlgorithm.Stop();
            }

            if (this.Verbose)
            {
                Output.WriteLine(OutputLevel.Verbose);
                Output.WriteLine(OutputLevel.Verbose, "Compute time: {0}", timeSpan);
                Output.WriteLine(OutputLevel.Verbose, "Write time: {0}", runAlgorithm.Elapsed);
            }
        }
        /// <summary>
        /// Writes delta for query sequences.
        /// </summary>
        /// <param name="deltaAlignments">Delta alignments to write.</param>
        /// <param name="sorter"> </param>
        /// <param name="filename">File name to write.</param>
        private static void WriteDelta(IEnumerable<DeltaAlignment> deltaAlignments, DeltaAlignmentSorter sorter, string filename)
        {
            using (StreamWriter writer = new StreamWriter(filename))
            {
                long deltaPositionInFile = 0;

                foreach (DeltaAlignment deltaAlignment in deltaAlignments)
                {
                    deltaAlignment.Id = deltaPositionInFile;
                    string deltaString = Helper.GetString(deltaAlignment);
                    deltaPositionInFile += deltaString.Length;
                    writer.Write(deltaString);
                    sorter.Add(deltaAlignment.Id, deltaAlignment.FirstSequenceStart);
                }

                writer.Flush();
            }
        }
        /// <summary>
        /// Writes delta for query sequences.
        /// </summary>
        /// <param name="sorter">Sorter instance.</param>
        /// <param name="unsortedDeltaFilename">Unsorted Delta Filename.</param>
        /// <param name="queryParser">Query/Read parser</param>
        /// <param name="outputfilename">Output file name.</param>
        private static void WriteSortedDelta(DeltaAlignmentSorter sorter, string unsortedDeltaFilename, FastASequencePositionParser queryParser, string outputfilename)
        {
            using (var unsortedReads = File.OpenRead(unsortedDeltaFilename))
            using (DeltaAlignmentParser unsortedDeltaParser = new DeltaAlignmentParser(unsortedReads, queryParser))
            {
                TextWriter textWriterConsoleOutSave = Console.Out;
                StreamWriter streamWriterConsoleOut = null;
                try
                {
                    if (!string.IsNullOrEmpty(outputfilename))
                    {
                        Output.WriteLine(OutputLevel.Required);
                        streamWriterConsoleOut = new StreamWriter(outputfilename);
                        Console.SetOut(streamWriterConsoleOut);
                    }

                    long deltaPositionInFile = 0;
                    foreach (long id in sorter.GetSortedIds())
                    {
                        DeltaAlignment deltaAlignment = unsortedDeltaParser.GetDeltaAlignmentAt(id);
                        deltaAlignment.Id = deltaPositionInFile;
                        string deltaString = Helper.GetString(deltaAlignment);
                        deltaPositionInFile += deltaString.Length;
                        Console.Write(deltaString);
                    }

                    Console.Out.Flush();
                }
                finally
                {
                    if (streamWriterConsoleOut != null)
                        streamWriterConsoleOut.Dispose();
                    Console.SetOut(textWriterConsoleOutSave);
                }
            }
        }