using System;
using System.Threading;
using Microsoft.DirectX.AudioVideoPlayback;

namespace Icarus.SoundEngine {
    /// <summary>
    /// Manages and plays an audio file
    /// </summary>
    public class MusicStream {
		
        #region Instance Variables
        /// <summary>
        /// Reference to singleton SoundSettings class.
        /// </summary>
        private SoundSettings settings = null;
        /// <summary>
        /// Responsible for MP3 music playback.
        /// </summary>
        private Audio mp3Player = null;
        /// <summary>
        /// Thread that sleeps the duration a song plays, and replays the music file.
        /// </summary>
        private Thread musicLoopThread = null;
        /// <summary>
        /// Music filename to be replayed.
        /// </summary>
        private string musicFilename = null;
        /// <summary>
        /// Duration a music file has left to play.
        /// </summary>    
        private int duration = 0;
        /// <summary>
        /// Whether or not the music file being played should loop.
        /// </summary>
        private bool looping = true;
        #endregion

        #region Accessors/Modifiers
        /* ------------------- */
        /* Accessors/Modifiers */
        /* ------------------- */

        /// <summary>
        /// This sets and accesses the filename for this music stream.
        /// </summary>
        public string gs_musicFilename {
            get { return this.musicFilename; }
			set 
			{
				this.musicFilename = value;

				/*Dispose of any previous playing files*/
				if (mp3Player != null) 
				{
					mp3Player.Stop();
					mp3Player.Dispose();
				}

				if (this.musicFilename == null) return;

				/*Load file into the player buffer and set volume*/
				try 
				{        
					mp3Player = new Audio(musicFilename);
					mp3Player.Volume = (settings.gs_musicVolume - 100) * 50;
				} 
				catch 
				{
					Console.WriteLine("MP3 player could not load file: " + musicFilename);
					return;
				}
			}
        }

        /// <summary>
        /// Sets the volume this music stream should play at.
        /// </summary>
        /// <param name="vol">Volume to play at.</param>
        public void SetVolume(int vol) {
            if (mp3Player != null) {
                mp3Player.Volume = (vol);
            }
        }

        /// <summary>
        /// Sets whether or not this music stream should loop.
        /// </summary>
        /// <param name="loop">Whether or not this music stream should loop.</param>
        public void Loop(bool loop) {
            looping = loop;
        }
        #endregion

        #region Initialization
        
        /// <summary>
        /// Generate a new Music Stream
        /// </summary>
        public MusicStream() {
            settings = SoundSettings.Instance;
        }
        #endregion

        #region Music Playing
        /* ------------- */
        /* Music Playing */
        /* ------------- */

        /// <summary>
        /// Used by a newly created thread to loop music.
        /// </summary>
        private void WaitAndLoop() {
            Thread.Sleep(duration);      
            if(looping) {
                PlayMusic();
            }
        }

        /// <summary>
        /// Plays the music file looping at the established volume.
        /// </summary>
        /// <param name="filename">Music file to be played.</param>
        public void PlayMusic(string filename) {
            PlayMusic(filename, true);
        }

        /// <summary>
        /// Plays the music file at the established volume.
        /// </summary>
        /// <param name="filename">Music file to be played.</param>
        /// <param name="loop">Whether or not the file will be played looping.</param>
        public void PlayMusic(string filename, bool loop) {
            this.gs_musicFilename = filename;
            looping = loop;
            PlayMusic();
        }

        /// <summary>
        /// Plays the established music file at the established music volume.
        /// </summary>
        public void PlayMusic() {
            Thread oldLoopThread = musicLoopThread;

            if (musicFilename == null || mp3Player == null) {
                return;
            }

            /*Play file and start loop thread*/
            //if (mp3Player != null) {...}
            mp3Player.Play();
            duration = (int) (mp3Player.Duration * 1000);      
            musicLoopThread = new Thread(new ThreadStart(WaitAndLoop));      
            musicLoopThread.Start();
            if (oldLoopThread != null) {
                oldLoopThread.Abort();
            }      
        }

        /// <summary>
        /// Stops any currently playing music.
        /// </summary>
        public void StopMusic() {      
            if (mp3Player != null) {
                mp3Player.Stop();
            }
            if (musicLoopThread != null) {
                musicLoopThread.Abort();
            }
        }

        /// <summary>
        /// Pauses music when music is currently playing.
        /// Resumes music when music is paused.
        /// </summary>
        public void PauseMusic() {
            if (mp3Player != null) {
                if (mp3Player.Paused) {
                    mp3Player.Play();
                    duration = (int) ((mp3Player.Duration - mp3Player.CurrentPosition) * 1000);      
                    musicLoopThread = new Thread(new ThreadStart(WaitAndLoop));      
                    musicLoopThread.Start();
                } else {
                    mp3Player.Pause();
                    musicLoopThread.Abort();
                }
            }
        }
        #endregion
    }
}