private LessonInstructions ParseInstructions(StringWithIndex text)
        {
            text = text.Trim();

            var instructions = new LessonInstructions(text);

            var paragraphs = GetParagraphs(text);

            // Remove blank paragraphs
            paragraphs = paragraphs.Where(p => p.Phrases.Count > 0);

            instructions.AddChildren(paragraphs);

            return(instructions);
        }
        private LessonFile ParseFile(StringWithIndex text)
        {
            text = text.Trim();

            var file = new LessonFile(text);

            var parts = text.SplitAfterFirstLine();

            // Parse the title
            var titlePart = parts[0];

            file.Children.Add(new LessonFileMethodReference(titlePart));

            var codePart = parts[1];

            file.Children.Add(new LessonCode(codePart));

            return(file);
        }
        private LessonTest ParseTest(StringWithIndex text)
        {
            text = text.Trim();

            var test = new LessonTest(text);

            var parts = text.SplitAfterFirstLine();

            // Parse the title
            var titlePart = parts[0];

            test.Children.Add(new LessonBlankTitlePlaceholder(titlePart, "## TEST", "\r\n"));

            var codePart = parts[1];

            test.Children.Add(new LessonCode(codePart));

            return(test);
        }
        private LessonCodeExplanation ParseCodeExplanation(StringWithIndex text)
        {
            text = text.Trim();

            var codeExp = new LessonCodeExplanation(text);

            var parts = text.SplitAfterFirstLine();

            // Parse the title
            var titlePart = parts[0];

            codeExp.Children.Add(new LessonCodeExplanationQuote(titlePart));

            // Parse the phrases
            var phraseTexts = parts[1].SplitWithoutModification("-");
            var phrases     = phraseTexts.Select(t => new LessonPhrase(t.Trim()));

            codeExp.AddChildren(phrases);

            return(codeExp);
        }
        private LessonExplanation ParseExplanation(StringWithIndex text)
        {
            text = text.Trim();

            var explanation = new LessonExplanation(text);

            var parts = text.SplitAfterFirstLine();

            // Parse the title
            var titlePart = parts[0];

            explanation.Children.Add(new LessonBlankTitlePlaceholder(titlePart, "## EXPLANATION", "\r\n"));

            // Parse explanation
            // Divide the parts
            var codeExplanationTexts = parts[1].SplitWithoutModification("\n*");
            var codeExplanations     = codeExplanationTexts.Where(t => !StringHelper.IsNullOrWhiteSpace(t.Text)).Select(t => ParseCodeExplanation(t));

            explanation.AddChildren(codeExplanations);

            return(explanation);
        }
        private LessonSummary ParseSummary(StringWithIndex text)
        {
            text = text.Trim();

            var summary = new LessonSummary(text);

            var parts = text.SplitAfterFirstLine();

            // Parse the title
            var titlePart = parts[0];

            summary.Children.Add(new LessonBlankTitlePlaceholder(titlePart, "## SUMMARY", "\r\n"));

            var paragraphs = GetParagraphs(parts[1]);

            // Remove blank paragraphs
            paragraphs = paragraphs.Where(p => p.Phrases.Count > 0 || p.Code != null);

            summary.AddChildren(paragraphs);

            return(summary);
        }
        private LessonGoal ParseGoal(StringWithIndex text)
        {
            text = text.Trim();

            var goal = new LessonGoal(text);

            var parts = text.SplitAfterFirstLine();

            // Parse the title
            var titlePart = parts[0];

            goal.Children.Add(new LessonBlankTitlePlaceholder(titlePart, "## GOAL", "\r\n"));

            var paragraphs = GetParagraphs(parts[1]);

            // Remove blank paragraphs
            paragraphs = paragraphs.Where(p => p.Phrases.Count > 0 || p.Code != null);

            goal.AddChildren(paragraphs);

            return(goal);
        }
        private LessonNode ParseStep(StringWithIndex text)
        {
            text = text.Trim();
            var step = new LessonStep(text);

            // Divide the parts
            var parts = text.SplitWithoutModification("\n#");

            // The header includes the title and the instructions
            var header      = parts[0];
            var headerParts = header.SplitAfterFirstLine();

            // Parse the step title
            var titlePart = headerParts[0];

            step.Children.Add(new LessonStepTitle(titlePart.TrimStart("# STEP = ")));

            // Add instructions - the first section (no header)
            var instructionsPart = headerParts[1];

            step.Children.Add(ParseInstructions(instructionsPart));

            // Add Goal
            var goalPart = parts.First(p => p.Text.StartsWith("\n## GOAL"));

            step.Children.Add(ParseGoal(goalPart));

            // Add Summary
            var summaryPart = parts.First(p => p.Text.StartsWith("\n## SUMMARY"));

            step.Children.Add(ParseSummary(summaryPart));

            // Add Test
            var testPart = parts.FirstOrDefault(p => p.Text.StartsWith("\n## TEST"));

            if (testPart != null)
            {
                step.Children.Add(ParseTest(testPart));
            }

            // Add Explanation
            var explanationPart = parts.FirstOrDefault(p => p.Text.StartsWith("\n## EXPLANATION"));

            if (explanationPart != null)
            {
                step.Children.Add(ParseExplanation(explanationPart));
            }

            // Add File
            var filePart = parts.FirstOrDefault(p => p.Text.StartsWith("\n## FILE = "));

            if (filePart != null)
            {
                step.Children.Add(ParseFile(filePart));
            }


            // TODO: Add other parts

            // Order children
            var ordered = step.Children.OrderBy(c => c.Content.Index).ToList();

            step.Children.Clear();
            step.AddChildren(ordered);

            return(step);
        }