using System;
using System.IO;
using Jellyfish.Virtu.Services;

namespace Jellyfish.Virtu
{
    public sealed class Speaker : MachineComponent
    {
		public Speaker() { }
        public Speaker(Machine machine) :
            base(machine)
        {
            _flushOutputEvent = FlushOutputEvent; // cache delegates; avoids garbage
        }

        public override void Initialize()
        {
			AudioService = new Services.AudioService();

            Machine.Events.AddEvent(CyclesPerFlush * Machine.Cpu.Multiplier, _flushOutputEvent);
        }

        public override void Reset()
        {
            _isHigh = false;
            _highCycles = _totalCycles = 0;
        }

        public void ToggleOutput()
        {
            UpdateCycles();
            _isHigh ^= true;
        }

        private void FlushOutputEvent()
        {
            UpdateCycles();
			// TODO: better than simple decimation here!!
            AudioService.Output(_highCycles * short.MaxValue / _totalCycles);
            _highCycles = _totalCycles = 0;

            Machine.Events.AddEvent(CyclesPerFlush * Machine.Cpu.Multiplier, _flushOutputEvent);
        }

        private void UpdateCycles()
        {
            int delta = (int)(Machine.Cpu.Cycles - _lastCycles);
            if (_isHigh)
            {
                _highCycles += delta;
            }
            _totalCycles += delta;
            _lastCycles = Machine.Cpu.Cycles;
        }

        private const int CyclesPerFlush = 23;

        private Action _flushOutputEvent;

        private bool _isHigh;
        private int _highCycles;
        private int _totalCycles;
        private long _lastCycles;

		public AudioService AudioService { get; private set; }
    }
}
