/// <summary>
 /// Initializes a new instance of the <see cref="Breathing"/> class starting at the given state.
 /// A breathing is composed of three state. The first is "inspiration", the second in "holding breath" and the last one is "expiration".
 /// </summary>
 /// <param name="startVolume">The volume at which we start the breathing (before inspiration). As all volume, 0 is for empty lungs and 1 for full ones (which in this case: before inspiration; is irrelevant).</param>
 /// <param name="maxVolume">The volume at which we end the inspiration and start the holding breath. As all volume, 0 is for empty (which in this case: after inspiration; is irrelevant) lungs and 1 for full ones.</param>
 /// <param name="endVolume">The volume at which we end the breathing (the end of the expiration). As all volume, 0 is for empty lungs and 1 for full ones (which in this case: after expiration; is irrelevant).</param>
 /// <param name="holdingBreathTime">The time (is seconds) the patient should hold his breath after an inspiration.</param>
 /// <param name="inspirationTime">The time (is seconds) the patient should inspiring (from <see cref="startVolume"/> to <see cref="maxVolume"/>).</param>
 /// <param name="expirationTime">The time (is seconds) the patient should expiring (from <see cref="maxVolume"/> to <see cref="endVolume"/>).</param>
 /// <param name="startState">The state at which this breathing starts.</param>
 public Breathing(float startVolume, float maxVolume, float endVolume, float inspirationTime, float holdingBreathTime, float expirationTime, BreathingState startState, InputController_I inputController)
 {
     this.startVolume = startVolume;
     this.maxVolume = maxVolume;
     this.endVolume = endVolume;
     this.inspirationTime = inspirationTime;
     this.holdingBreathTime = holdingBreathTime;
     this.expirationTime=expirationTime;
     this.inputController = inputController;
     ResetTo (startState);
 }
    /// <summary>
    /// Gets the BreathingState :
    /// expiration if patient is blowing and inspiration is over.
    /// inspiration if patient wasn't reach the actual breathing's maximum volume.
    /// holding breath if the patient isn't blowing but is at the actual breathing's maximum volume.
    /// </summary>
    public BreathingState GetInputState()
    {
        if (isBlowing () && state!=BreathingState.INSPIRATION) {
            state= BreathingState.EXPIRATION;
        } else {
            float deltaFloatComp=0.001f;
            if(exercice.Volume <= exercice.ActualBreathing.MaxVolume-deltaFloatComp){
                state=BreathingState.INSPIRATION;
            }
            else {
                state=BreathingState.HOLDING_BREATH;
            }
        }

        return state;
    }
    /// <summary>
    /// Check the progress of the patient in this breathing and compute his actual lungs volume.
    /// </summary>
    /// <returns>The patient actual lungs volume (0 for empty and 1 for full).</returns>
    /// <param name="newState">The new breathing state (retrieve from the input controller). Can be the same as the actual state.</param>
    /// <param name="strength">The strength of the player inhale or exhale (depends on <see cref="newState"/>).</param>
    /// <param name="volumeRatio">The old volume value which will be updated and returned.</param>
    /// <param name="deltaTime">The time in seconds elapsed since the last call.</param>
    public float CheckProgress(BreathingState newState, float strength, float volumeRatio, float volumeMaxCalibrated, float deltaTime)
    {
        strength = CallibrateStrength (strength, volumeMaxCalibrated);
        if (isBreathingEnded) {
            return volumeRatio;
        }
        lastState = state;
        state = newState;

        if(lastState==GetSupposedLastState(state)){
            if(state==BreathingState.INSPIRATION && hasBreathingStarted){
                isBreathingEnded=true;
                return volumeRatio;
            }
            if(!dictStateStartTimes.ContainsKey(state)){
                dictStateStartTimes.Add(state, DateTime.Now);
            }
            CheckProgress(state, strength, volumeRatio, volumeMaxCalibrated, deltaTime);
        }
        else if(lastState == state){
            hasBreathingStarted=true;
            switch (state) {

            case BreathingState.EXPIRATION://We expire
                volumeRatio-=strength*deltaTime*ExpirationSpeed;
                if(volumeRatio<endVolume){
                    volumeRatio=endVolume;
                }
                dictStatePercentages[state]=(volumeRatio-maxVolume)/(endVolume-maxVolume);
                break;

            case BreathingState.INSPIRATION://We inspire
                volumeRatio+=strength*deltaTime*InspirationSpeed;
                if(volumeRatio>maxVolume){
                    volumeRatio=MaxVolume;
                }
                float newPercentage=(volumeRatio-startVolume)/(maxVolume-startVolume);
                dictStatePercentages[state]=newPercentage;
                break;

            case BreathingState.HOLDING_BREATH://We hold our breath
                dictStatePercentages[state]=((float)(DateTime.Now-dictStateStartTimes[state]).TotalSeconds)/(holdingBreathTime);
                if(dictStatePercentages[state]>1.0f){
                    dictStatePercentages[state]=1.0f;
                }
                break;
            }
        }
        else{
            state=GetSupposedLastState(state);
        }

        return volumeRatio;
    }
 /// <summary>
 /// Reset this breathing to the given initial state.
 /// </summary>
 /// <param name="stateToResetAt">State to reset at.</param>
 public void ResetTo(BreathingState stateToResetAt)
 {
     this.state = stateToResetAt;
     this.lastState = GetSupposedLastState (stateToResetAt);
     this.dictStateStartTimes.Clear ();
     this.dictStateStartTimes [stateToResetAt] = DateTime.Now;
     this.dictStatePercentages.Clear ();
     this.dictStatePercentages.Add (BreathingState.INSPIRATION, 0.0f);
     this.dictStatePercentages.Add (BreathingState.HOLDING_BREATH, 0.0f);
     this.dictStatePercentages.Add (BreathingState.EXPIRATION, 0.0f);
     this.hasBreathingStarted = false;
     this.isBreathingEnded = false;
 }
 /// <summary>
 /// Gets the usual state that precedes the given one.
 /// </summary>
 /// <returns>The usual state that precedes the given one.</returns>
 /// <param name="state">The state we want to know its prior.</param>
 public static BreathingState GetSupposedLastState(BreathingState state)
 {
     switch (state) {
     case BreathingState.INSPIRATION:
         return BreathingState.EXPIRATION;
     case BreathingState.HOLDING_BREATH:
         return BreathingState.INSPIRATION;
     case BreathingState.EXPIRATION:
         return BreathingState.HOLDING_BREATH;
     }
     return BreathingState.INSPIRATION;
 }