using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using NUnit.Framework;

namespace m3uTool.Tests
{
    [TestFixture]
    public class TranscodeTest : ProgressCallbackTestBase
    {
        private const string inputMp3 = "Disc 01 - 04.mp3";
        private readonly string outputAac = inputMp3.Replace(".mp3", ".aac");
        private readonly string outputWav = inputMp3.Replace(".mp3", ".wav");
        private readonly ReaderProgress mReaderProgress = new ReaderProgress();
        private readonly WriterProgress mWriterProgress = new WriterProgress();

        private Stream _pipeStream;

        private void Mp3ReadThread()
        {
            //int skip = 3;
            //int limit = 1;
            //string directory = @"C:\tmp\venus bak\media\audiobooks\Bret Easton Ellis - Lunar Park";
            //// string directory = @"C:\tmp\venus bak\media\audiobooks\Clarke, Arthur C. - Space Odyssey 01 - 2001, A Space Odyssey";
            //// string directory = @"C:\tmp\venus bak\media\audiobooks\Guitar Gym\Part 1 - Alternate Picking (Mp3 And Tab)";
            //string[] files = Directory.GetFiles(directory);
            var mp3Files = new[] {inputMp3};
            foreach (var mp3File in mp3Files)
            {
                //if (skip-- > 0)
                //    continue;
                //if (limit-- == 0)
                //    break;
                Debug.WriteLine(mp3File);
                var fp = new Mp3FileProperties(mp3File);
                Debug.WriteLine(fp.ToString());
                // Mp3 to wav
                using (var fileStream = new FileStream(mp3File, FileMode.Open))
                {
                    var opts = new Mp3EncodingOptions
                                   {
                                       Infile = "-", 
                                       Outfile = "-", 
                                       Mp3Input = true, 
                                       DecodeWav = true
                                   };
                    // opts.BitRate = BitRate.KBPS_32;
                    // opts.Freeformat = true;
                    // opts.DisableWavHeader = true;
                   
                    Debug.WriteLine("MP3 : " + opts.GetCommandLineArguments());
                    
                    // opts.Freeformat = true;
                    // read from the sr, and write to the memory stream
                    using (var encoder = new Mp3Encoder(opts, _pipeStream))
                    {
                        encoder.ProgressCallback = mReaderProgress;
                        encoder.ProcessInput(fileStream);
                    }
                }
            }
        }

        private void WavWriteThread()
        {
            using (var fs = new FileStream(outputWav, FileMode.OpenOrCreate))
            using (var sw = new StreamWriter(fs, Encoding.Default))
            using (var sr = new StreamReader(_pipeStream, Encoding.Default))
            {
                var buffer = new char[1024*1024];

                while (!sr.EndOfStream)
                {
                    var readCount = sr.Read(buffer, 0, buffer.Length);
                    sw.Write(buffer, 0, readCount);
                    mWriterProgress.SetText("Wrote " + buffer.Length);
                }
            }
        }

        private void AacWriteThread()
        {
            var mp4Opts = new Mp4EncodingOptions
                              {
                                  OutputFilename = outputAac,
                                  RawPCMSwapInputBytes = true,
                                  RawPCMInputMode = true,
                                  RawPCMInputSampleRate = 16,
                                  RawPCMInputSampleSize = SampleRateFrequency.Hz_44100,
                                  RawInputChannels = ChannelMode.Stereo
                              };
            Debug.WriteLine("AAC : " + mp4Opts.GetCommandLineArguments());

            using (var encoder = new Mp4Encoder(mp4Opts))
            {
                encoder.ProgressCallback = mWriterProgress;
                encoder.ProcessInput(_pipeStream);
            }
        }


        private class ReaderProgress : ProgressCallbackTestBase
        {
            public ReaderProgress()
            {
                mPreface = "Reader: ";
            }

            /// <summary>
            /// Call this method from the worker thread to increase the progress 
            /// counter by a specified value.
            /// </summary>
            public override void StepTo(int val)
            {
                if (val%10 == 0)
                {
                    base.StepTo(val);
                }
            }
        }

        private class WriterProgress : ProgressCallbackTestBase
        {
            public WriterProgress()
            {
                mPreface = "\t\t\t\tWriter: ";
            }

            /// <summary>
            /// Call this method from the worker thread to increase the progress 
            /// counter by a specified value.
            /// </summary>
            public override void StepTo(int val)
            {
                if (val%10 == 0)
                {
                    base.StepTo(val);
                }
            }
        }

        [Test]
        public void TranscodeMultiThreadTest()
        {
            //_pipeStream = new BridgeStream();
            _pipeStream = new PipeStream.PipeStream();
            (_pipeStream as PipeStream.PipeStream).BlockLastReadBuffer = true;
            (_pipeStream as PipeStream.PipeStream).MaxBufferLength = 1*PipeStream.PipeStream.MB;

            // _pipeStream.MaxBufferLength = 100;

            var writeThread = new Thread(AacWriteThread);
            writeThread.Start();

            var readThread = new Thread(Mp3ReadThread);
            readThread.Start();

            readThread.Join();
            (_pipeStream as PipeStream.PipeStream).BlockLastReadBuffer = false;
            writeThread.Join();
        }

        [Test]
        public void TranscodeSingleThreadTest()
        {
            var mp3Info = new Mp3FileProperties(inputMp3);
            Debug.WriteLine(mp3Info);

            _pipeStream = new MemoryStream();

            Mp3ReadThread();
            if (_pipeStream.CanSeek)
                _pipeStream.Seek(0, SeekOrigin.Begin);
            WavWriteThread();
        }
    }
}