// ========================================================================
//
// Copyright (C) 2013-2014 MARC CHEVALDONNE
//                         marc.chevaldonne.free.fr
//
// Module        : Mélodie.cs
// Author        : Marc Chevaldonné
// Creation date : 2014-05-07
//
// ========================================================================

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MusiqueEnConsole
{
    abstract class Mélodie
    {
        public enum Tone
        {
            REST = 0,
            GbelowC = 196,
            A2 = 220,
            A2sharp = 233,
            B2 = 247,
            C = 262,
            Csharp = 277,
            D = 294,
            Dsharp = 311,
            E = 330,
            F = 349,
            Fsharp = 370,
            G = 392,
            Gsharp = 415,
            A = 440,
            B = 494,
            C4 = 523
        }

        public struct Note
        {
            private Tone mTone;

            public Tone Tone
            {
                get { return mTone; }
            }

            private int mDuration;

            public int Duration
            {
                get { return mDuration; }
            }
            
            public Note(Tone tone, int duration)
            {
                mTone = tone;
                mDuration = duration;
            }
        }

        protected List<Note> Notes
        {
            get;
            private set;
        }

        protected Mélodie()
        {
            Notes = new List<Note>();

        }

        public double PulsationsParMinute
        {
            get
            {
                return mMetronome.PulsationsParMinute;
            }
            set
            {
                mMetronome.PulsationsParMinute = value;
            }
        }

        int mDurationOfLastNote;

        Note? mLastNote;

        void metronome_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (!mLastNote.HasValue || mLastNote.Value.Duration == mDurationOfLastNote)
            {
                mLastNote = NextNote;
                if (!mLastNote.HasValue)
                {
                    Arrêter();
                } 
                mDurationOfLastNote = 1;
                OnNoteLue(new MélodieEventArgs(mLastNote.Value, (60000.0/mMetronome.PulsationsParMinute)*0.9));
                return;
            }
            mDurationOfLastNote++;
        }

        public void Démarrer()
        {
            mMetronome.NouvellePulsation += metronome_Elapsed;
            mMetronome.Démarrer();
        }

        public void Arrêter()
        {
            mMetronome.Arrêter();
            mMetronome.NouvellePulsation -= metronome_Elapsed;
        }

        private int mIdNextNote;

        private Note? NextNote
        {
            get
            {
                while (mIdNextNote < Notes.Count)
                {
                    return Notes[mIdNextNote++];
                }
                return null;
            }
        }

        Metronome mMetronome = new Metronome();

        public class MélodieEventArgs : EventArgs
        {
            public int NoteFrequency
            {
                get;
                private set;
            }

            public int Duration
            {
                get;
                private set;
            }

            public MélodieEventArgs(Note note, double interval)
            {
                NoteFrequency = (int)note.Tone;
                Duration = note.Duration * (int)interval;
            }
        }

        public event EventHandler<MélodieEventArgs> NoteLue;

        virtual protected void OnNoteLue(MélodieEventArgs args)
        {
            if (NoteLue != null)
            {
                NoteLue(this, args);
            }
        }
    }
}
