using System;
using SFML.Graphics;
using SFML.System;
using FluidSim.Core;

namespace FluidSim.Tests
{
    public class TestScenario : Scenario
    {
        private PipeSystem pipeSystem;
        private BoundarySystem boundaries;
        private Solver solver;

        private int[] pipeStart = { 0 };
        private int[] pipeEnd;

        private double dt;
        private int stepCount;

        // Sound output: use pressure at open end
        private SoundProcessor openEndSound;
        private int openEndIdx = 0;   // index of the open end in BoundarySystem (we added only one)

        public override void Initialize(int sampleRate)
        {
            dt = 1.0 / sampleRate;

            const int cellCount = 200;
            float length = 2f;
            float dia = 0.02f;
            float area = MathF.PI * 0.25f * dia * dia;

            float[] areas = new float[cellCount];
            float[] dxs = new float[cellCount];
            float dx = length / cellCount;
            for (int i = 0; i < cellCount; i++)
            {
                areas[i] = area;
                dxs[i] = dx;
            }

            pipeEnd = new[] { cellCount };

            float rho0 = 101325f / (287f * 300f);
            pipeSystem = new PipeSystem(cellCount, pipeStart, pipeEnd, areas, dxs,
                                        rho0, 0f, 101325f);
            pipeSystem.DampingMultiplier = 0f;
            pipeSystem.EnergyRelaxationRate = 0f;
            pipeSystem.AmbientPressure = 101325f;

            // Pressure bubble near right end
            float pBubble = 10f * 101325f;
            float TBubble = 2000f;
            float rhoBubble = pBubble / (287f * TBubble);
            for (int i = 0; i <= 10; i++)
                pipeSystem.SetCellState(i, rhoBubble, 0f, pBubble);

            // Boundaries: left closed, right open
            boundaries = new BoundarySystem(pipeSystem, maxOrifices: 1, maxOpenEnds: 1);
            boundaries.AddOrifice(null, pipeIndex: 0, isLeftEnd: true, areaIndex: 0, 1f);
            boundaries.AddOpenEnd(pipeIndex: 0, isLeftEnd: false, 101325f, area);
            float[] orificeAreas = new float[1] { 0f };
            boundaries.SetOrificeAreas(orificeAreas);

            solver = new Solver { SubStepCount = 3};
            solver.SetTimeStep(dt);
            solver.SetPipeSystem(pipeSystem);
            solver.SetBoundarySystem(boundaries);

            solver.EnableProfiling = true;
            pipeSystem.EnableProfiling = true;

            // Simple sound processor: convert mass flow rate to audio
            openEndSound = new SoundProcessor(sampleRate, 1f) { Gain = 2f };

            Console.WriteLine("Pulse test ready.");
            stepCount = 0;
        }

        public override float Process()
        {
            solver.Step();
            stepCount++;

            float flow = boundaries.GetOpenEndMassFlow(openEndIdx);
            float sample = openEndSound.Process(flow);

            return sample;
        }

        public override void Draw(RenderWindow target)
        {
            float winW = target.GetView().Size.X;
            float winH = target.GetView().Size.Y;

            float startX = 50f;
            float endX = winW - 50f;
            float y = winH / 2f;
            DrawPipe(target, pipeSystem, 0, y, startX, endX);
        }
    }
}