public void AnalyseCurrentPattern()
 {
     for (int i = 0; i < eventList.Length; i++)
     {
         if (ArrayComparrison.CompareArrays <bool>(myBeatController.activeBeats, eventList[i].controllerPattern))
         {
             eventList[i].linkedEvent.Invoke();
             break;
         }
     }
 }
    /// <summary>
    /// To be run after the player has had a chance to enter a pattern. Once the final editable beat is passed, the UI will close and that
    /// beat pattern will be locked in.
    /// </summary>
    public void CloseEditor()
    {
        if (ArrayComparrison.CompareArrays <bool>(previousPattern, beatController.activeBeats) == false)
        {
            beatController.OnPatternChange.Invoke();
        }

        editMode = false;

        inputBeatUI.UpdateInteractableState(false);
        inputBeatUI.UIVisible = false;


        beatController.AnalyseBeats();
    }
    /// <summary>
    /// To be called once the player exits the puzzle portion of a level and enters the solely platforming section.
    /// </summary>
    public void OnLevelComplete()
    {
        // This will store the index of the solution the player is using from our possibleSolutions array.
        // If it remains -1, the player has found a new solution to the level.
        int solutionIndex = -1;

        // If a solution is found, it may be the correct pattern but shifted a number of beats forward. This variable will store the number of
        // beats the solution is shifted, allowing us to play the solution audio at the correct time.
        int solutionShift = -1;

        // Firstly, we need to go through all the plausible solutions and check them against the current activeBeat setup in the level.
        for (int i = 0; i < BeatTimingManager.btmInstance.currentSong.possibleSolutions.Length; i++)
        {
            // The first beat pattern stored in a solution should always be the longest one
            // We create a new bool array that will represent which of the shifted versions of the beat controller's array
            // match our current solution. If any beat controller's shifted pattern at a certain index does not match the solution array of that colour
            // that index will get set to false. Analysing the arry at the end, any indeces still set to 'True' represent matches to our predicted
            // solution that have been shifted 'index' beats forward in time.
            bool[] possibleShifts = new bool[BeatTimingManager.btmInstance.currentSong.possibleSolutions[i].correctPatterns[0].pattern.Length];

            // We'll initialise the whole array as true, then set it's values to false as we find mismatches.
            for (int j = 0; j < possibleShifts.Length; j++)
            {
                possibleShifts[j] = true;
            }


            // We want to loop through all our beat controllers, checking if their current active beats array setup is the same
            // as the boolean array of the same colour within the solution being analysed.
            for (int j = 0; j < BeatTimingManager.btmInstance.beatControllers.Length; j++)
            {
                // We'll loop through all the categories (colours) in our solutions array of beat patterns, finding the one that matches the
                // current beatController colour
                for (int k = 0; k < BeatTimingManager.btmInstance.currentSong.possibleSolutions[i].correctPatterns.Length; k++)
                {
                    // First we make sure we're checking setups of the same colour - we only want to compare arrays of the same category
                    if (BeatTimingManager.btmInstance.currentSong.possibleSolutions[i].correctPatterns[k].beatColour ==
                        BeatTimingManager.btmInstance.beatControllers[j].controllerColour)
                    {
                        // We creates a teporary copy of the ActiveBeats array which we can freely shift without affecting the player's current setup.
                        bool[] tempPattern = BeatTimingManager.btmInstance.beatControllers[j].activeBeats;



                        // But we can't just compare the arrays blindly - we need to check if the player has found a solution that's been shifted by some value.
                        for (int h = 0; h < possibleShifts.Length; h++)
                        {
                            // If this index is false, it implies we've already found a mismatch here before and there's no point in checking a different colour's array.
                            if (possibleShifts[h] != false)
                            {
                                // We check if the beat pattern arrays of each are the same
                                if (ArrayComparrison.CompareArrays <bool>(BeatTimingManager.btmInstance.currentSong.possibleSolutions[i].correctPatterns[k].pattern,
                                                                          tempPattern) == false)
                                {
                                    // If not, we remember that a mimatch was found at this shifted index.
                                    possibleShifts[h] = false;
                                }
                            }

                            ShiftArrayValuesRight <bool>(ref tempPattern);
                        }

                        // We've already found the correct coloured pattern to compare, there's no need to look at the rest, so we'll leave
                        // this internal colour-matching loop.
                        break;
                    }
                }

                // If all possible shift positions are false already, there's no need to keep analysing this solution.
                // So we loop through our possible shifts array looking for any values that are still true.
                bool allPossibleShiftsMismatched = true;

                for (int k = 0; k < possibleShifts.Length; k++)
                {
                    if (possibleShifts[k])
                    {
                        allPossibleShiftsMismatched = false;
                        break;
                    }
                }

                // If so, no true values were found and we can move on to the next solution.
                if (allPossibleShiftsMismatched)
                {
                    break;
                }
            }


            // At this point, we've either checked all the combinations of beat controllers or we have a shifts array filled with falses. However, if there
            // is even a single 'true' value in the array, it implies this was the predefined solution the player has found, and it's been shifted by a number
            // of beats equal to the index of that 'true' value.
            bool solutionFound = false;

            for (int k = 0; k < possibleShifts.Length; k++)
            {
                if (possibleShifts[k])
                {
                    solutionFound = true;
                    solutionShift = k;
                    break;
                }
            }

            if (solutionFound)
            {
                solutionIndex = i;
                break;
            }

            // Otherwise, we loop on and check the next possible solution
        }



        // this implies a matching solution was found
        if (solutionIndex != -1)
        {
            // So we tell our music manager which composition it should play to match said solution
            MusicManager.MMInstance.compositionAudioSource.clip =
                BeatTimingManager.btmInstance.currentSong.possibleSolutions[solutionIndex].solutionCompositionIntro;
            MusicManager.MMInstance.OnLevelCompleted(solutionIndex, solutionShift);
        }
        else
        {
            // if no solution found, play default composition and record the unkown solution.
            MusicManager.MMInstance.compositionAudioSource.clip =
                BeatTimingManager.btmInstance.currentSong.possibleSolutions[0].solutionCompositionIntro;
            MusicManager.MMInstance.OnLevelCompleted(-1, 0);

            UnexpectedSolutionRecorded.StoreNewSolution();
        }

        OnSolutionFound.Invoke();
    }