static MangaGamerInstruction ParseMangaGamerInstruction(string s, bool isPS3)
        {
            MGFadeOutBGM fadeOutBGM = TryParseFadeOutBGM(s, isPS3: isPS3);

            if (fadeOutBGM != null)
            {
                return(fadeOutBGM);
            }

            MGPlayBGM playBGM = TryParsePlayBGM(s, isPS3: isPS3);

            if (playBGM != null)
            {
                return(playBGM);
            }

            MGPlaySE playSE = TryParsePlaySE(s, isPS3: isPS3);

            if (playSE != null)
            {
                return(playSE);
            }

            return(new GenericInstruction(s, false));
        }
        public static void InsertMGLinesUsingPS3XML(string mergedMGScriptPath, string outputPath, MergerConfiguration configuration, Counter counter)
        {
            const bool USE_OLD_METHOD_FOR_INSERT_BGM = false;

            Console.WriteLine($"--------- Begin Applying Postprocessing Stage 1 to {mergedMGScriptPath} ------");

            //Detect the BGM channel of the original Manga Gamer script. This is used for BGM insertion and FadeOut insertion
            int bgmChannelNumber = MGScriptBGMChannelDetector.DetectBGMChannelOrDefault(mergedMGScriptPath, configuration, defaultChannel: 2, PrintOnFoundChannelAndWarnings: true);


            // --------- Perform stage 1 - this converts the raw merged script into a list of MangaGamerInstructions ---------
            //Iterate over the the Manga Gamer chunks and the PS3 XML Instructions Chunks of the merged script
            int debug_i = 0;
            List <InstructionAssociation> workingInstructionAssociations = new List <InstructionAssociation>();

            List <MangaGamerInstruction> newChunk = new List <MangaGamerInstruction>();

            foreach (var chunk in PS3XMLChunkFinder.GetAllChunksFromMergedScript(mergedMGScriptPath))
            {
                if (chunk.isPS3Chunk)
                {
                    //PS3 XML reader doesn't care about newlines, so just join each line directly to next line
                    HandlePS3Chunk(String.Join("", chunk.lines), newChunk, bgmChannelNumber);

                    HandleChunk(workingInstructionAssociations, newChunk);
                    newChunk = new List <MangaGamerInstruction>();
                }
                else
                {
                    //handle a mangagamer chunk
                    foreach (string mgScriptLine in chunk.lines)
                    {
                        newChunk.Add(ParseMangaGamerInstruction(mgScriptLine, false));
                    }
                }
            }

            //If there are any leftovers (probably just mangagamer original instructions), just add them to the output.
            HandleChunk(workingInstructionAssociations, newChunk);

            // Extract BGM associations of mgBGM -> ps3BGM
            ExtractBGMAssociations(workingInstructionAssociations, counter);

            // Convert the instruction associations to regular mangagamer instructions for stage 2
            List <MangaGamerInstruction> outputStage1 = new List <MangaGamerInstruction>();

            foreach (var instructionAssociation in workingInstructionAssociations)
            {
                outputStage1.Add(instructionAssociation.mgOriginalInstruction);

                //check for a "failed" section. If failed section, just insert the whole section.
                bool failed = false;
                foreach (var inst in instructionAssociation.associatedPS3Instructions)
                {
                    if (inst is FailInstruction)
                    {
                        failed = true;
                    }
                }

                if (failed)
                {
                    outputStage1.AddRange(instructionAssociation.associatedPS3Instructions);
                    continue;
                }


                foreach (var ps3Inst in instructionAssociation.associatedPS3Instructions)
                {
                    MangaGamerInstruction outputInstruction = ps3Inst;

                    switch (ps3Inst)
                    {
                    case MGPlayBGM ps3MGPlayBGM:
                        if (instructionAssociation.mgOriginalInstruction is MGPlayBGM)
                        {
                            MGPlayBGM mgPlayBGM = (MGPlayBGM)instructionAssociation.mgOriginalInstruction;
                            outputInstruction = mgPlayBGM.CloneWithFilename(ps3MGPlayBGM.bgmFileName, ps3MGPlayBGM.IsPS3());
                        }
                        break;

                    case MGPlaySE ps3MGPlaySE:
                        if (instructionAssociation.mgOriginalInstruction is MGPlaySE)
                        {
                            MGPlaySE mgPlaySE = (MGPlaySE)instructionAssociation.mgOriginalInstruction;
                            outputInstruction = mgPlaySE.CloneWithFilename(ps3MGPlaySE.filename, ps3MGPlaySE.IsPS3());
                        }
                        break;
                    }

                    outputStage1.Add(outputInstruction);
                }
            }

            // --------- Perform stage 2 filtering to 'tidy up' the script ---------
            //This section runs filters after all the other filters have run.
            //This stage converts the list of MangaGamerInstructions to a list of strings
            List <string> outputStage2 = new List <string>();

            foreach (MangaGamerInstruction inst in outputStage1)
            {
                //TODO: correctly interpret mangagamer instructions instead of using regexes to determine the line typ
                if (inst.IsPS3())
                {
                    //Disable PS3 fade instructions for now
                    if (!(inst is MGFadeOutBGM))
                    {
                        //wrap all ps3-origin instructions in GAltBGMflow
                        outputStage2.Add($"\tif (GetGlobalFlag(GAltBGMflow) == 1) {{ {inst.GetInstruction()} }}");
                    }
                }
                else if (//fadeOutBGMMusicRegex.IsMatch(inst.GetInstruction()) ||
                    playBGMMusicRegex.IsMatch(inst.GetInstruction()) ||
                    playSERegex.IsMatch(inst.GetInstruction()))
                {
                    //wrap only the above types of MG-origin instructions in GAltBGMflow
                    outputStage2.Add($"\tif (GetGlobalFlag(GAltBGMflow) == 0) {{ {inst.GetInstruction()} }}");
                }
                else
                {
                    //all other MG-origin instructions are output as-is
                    outputStage2.Add(inst.GetInstructionStandalone());
                }
            }

            // --------- Finally, write the output to file. ---------
            File.WriteAllLines(outputPath, outputStage2);
        }