//
// Copyright (c) 2019-2021 Ryujinx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see .
//
using Ryujinx.Audio.Renderer.Common;
using Ryujinx.Audio.Renderer.Utils;
using System;
using System.Diagnostics;
namespace Ryujinx.Audio.Renderer.Server.Voice
{
    /// 
    /// Voice context.
    /// 
    public class VoiceContext
    {
        /// 
        /// Storage of the sorted indices to .
        /// 
        private Memory _sortedVoices;
        /// 
        /// Storage for .
        /// 
        private Memory _voices;
        /// 
        /// Storage for .
        /// 
        private Memory _voiceChannelResources;
        /// 
        /// Storage for  that are used during audio renderer server updates.
        /// 
        private Memory _voiceUpdateStatesCpu;
        /// 
        /// Storage for  for the .
        /// 
        private Memory _voiceUpdateStatesDsp;
        /// 
        /// The total voice count.
        /// 
        private uint _voiceCount;
        public void Initialize(Memory sortedVoices, Memory voices, Memory voiceChannelResources, Memory voiceUpdateStatesCpu, Memory voiceUpdateStatesDsp, uint voiceCount)
        {
            _sortedVoices = sortedVoices;
            _voices = voices;
            _voiceChannelResources = voiceChannelResources;
            _voiceUpdateStatesCpu = voiceUpdateStatesCpu;
            _voiceUpdateStatesDsp = voiceUpdateStatesDsp;
            _voiceCount = voiceCount;
        }
        /// 
        /// Get the total voice count.
        /// 
        /// The total voice count.
        public uint GetCount()
        {
            return _voiceCount;
        }
        /// 
        /// Get a reference to a  at the given .
        /// 
        /// The index to use.
        /// A reference to a  at the given .
        public ref VoiceChannelResource GetChannelResource(int id)
        {
            return ref SpanIOHelper.GetFromMemory(_voiceChannelResources, id, _voiceCount);
        }
        /// 
        /// Get a  at the given .
        /// 
        /// The index to use.
        /// A  at the given .
        /// The returned  should only be used when updating the server state.
        public Memory GetUpdateStateForCpu(int id)
        {
            return SpanIOHelper.GetMemory(_voiceUpdateStatesCpu, id, _voiceCount);
        }
        /// 
        /// Get a  at the given .
        /// 
        /// The index to use.
        /// A  at the given .
        /// The returned  should only be used in the context of processing on the .
        public Memory GetUpdateStateForDsp(int id)
        {
            return SpanIOHelper.GetMemory(_voiceUpdateStatesDsp, id, _voiceCount);
        }
        /// 
        /// Get a reference to a  at the given .
        /// 
        /// The index to use.
        /// A reference to a  at the given .
        public ref VoiceState GetState(int id)
        {
            return ref SpanIOHelper.GetFromMemory(_voices, id, _voiceCount);
        }
        public ref VoiceState GetSortedState(int id)
        {
            Debug.Assert(id >= 0 && id < _voiceCount);
            return ref GetState(_sortedVoices.Span[id]);
        }
        /// 
        /// Update internal state during command generation.
        /// 
        public void UpdateForCommandGeneration()
        {
            _voiceUpdateStatesDsp.CopyTo(_voiceUpdateStatesCpu);
        }
        /// 
        /// Sort the internal voices by priority and sorting order (if the priorities match).
        /// 
        public void Sort()
        {
            for (int i = 0; i < _voiceCount; i++)
            {
                _sortedVoices.Span[i] = i;
            }
            int[] sortedVoicesTemp = _sortedVoices.Slice(0, (int)GetCount()).ToArray();
            Array.Sort(sortedVoicesTemp, (a, b) =>
            {
                ref VoiceState aState = ref GetState(a);
                ref VoiceState bState = ref GetState(b);
                int result = aState.Priority.CompareTo(bState.Priority);
                if (result == 0)
                {
                    return aState.SortingOrder.CompareTo(bState.SortingOrder);
                }
                return result;
            });
            sortedVoicesTemp.AsSpan().CopyTo(_sortedVoices.Span);
        }
    }
}