//Rozdział 23.
Strategia


//Strategia dynamiczna

public enum OutputFormat
{
    Markdown,
    Html
}

public interface IListStrategy
{
    void Start(StringBuilder sb);
    void AddListItem(StringBuilder sb, string item);
    void End(StringBuilder sb);
}

public class TextProcessor
{
    private StringBuilder sb = new StringBuilder();
    private IListStrategy listStrategy;
    public void AppendList(IEnumerable<string> items)
    {
        listStrategy.Start(sb);
        foreach (var item in items)
            listStrategy.AddListItem(sb, item);
        listStrategy.End(sb);
    }
    public override string ToString() => sb.ToString();
}

public class HtmlListStrategy : IListStrategy
{
    public void Start(StringBuilder sb) => sb.AppendLine("<ul>");
    public void End(StringBuilder sb) => sb.AppendLine("</ul>");
    public void AddListItem(StringBuilder sb, string item)
    {
        sb.AppendLine($" <li>{item}</li>");
    }
}

public class MarkdownListStrategy : IListStrategy
{
// format markdown nie wymaga otwierającego i zamykającego znacznika listy
    public void Start(StringBuilder sb) {}
    public void End(StringBuilder sb) {}
    public void AddListItem(StringBuilder sb, string item)
    {
        sb.AppendLine($" * {item}");
    }
}

var tp = new TextProcessor();
tp.SetOutputFormat(OutputFormat.Markdown);
tp.AppendList(new []{"foo", "bar", "baz"});
WriteLine(tp);

// Wynik:
// * foo
// * bar
// * baz

public void SetOutputFormat(OutputFormat format)
{
    switch (format) {
        case OutputFormat.Markdown:
            listStrategy = new MarkdownListStrategy();
            break;
        case OutputFormat.Html:
            listStrategy = new HtmlListStrategy();
            break;
        default:
        throw new ArgumentOutOfRangeException(nameof(format),
        format, null);
    }
}

tp.Clear(); // czyścimy bufor
tp.SetOutputFormat(OutputFormat.Html);
tp.AppendList(new[] { "foo", "bar", "baz" });
WriteLine(tp);

// Wynik:
// <ul>
// <li>foo</li>
// <li>bar</li>
// <li>baz</li>
// </ul>

//Strategia statyczna
public class TextProcessor<LS>
where LS : IListStrategy, new()
{
    private StringBuilder sb = new StringBuilder();
    private IListStrategy listStrategy = new LS();
    public void AppendList(IEnumerable<string> items)
    {
        listStrategy.Start(sb);
        foreach (var item in items)
            listStrategy.AddListItem(sb, item);
        listStrategy.End(sb);
    }

    public override string ToString() => return sb.ToString();
}
var tp = new TextProcessor<MarkdownListStrategy>();
tp.AppendList(new []{"foo", "bar", "baz"});
WriteLine(tp);

var tp2 = new TextProcessor<HtmlListStrategy>();
tp2.AppendList(new[] { "foo", "bar", "baz" });
WriteLine(tp2);
// Strategia funkcyjna
let processList items startToken itemAction endToken =
    let mid = items |> (Seq.map itemAction) |> (String.concat "\n")
    [startToken; mid; endToken] |> String.concat "\n"
let processListHtml items =
    processList items "<ul>" (fun i -> "<li>" + i + "</li>") "</ul>"
let processListMarkdown items =
    processList items "" (fun i -> " * " + i) ""
 let items = ["witaj"; "świecie"]
printfn "%s" (processListHtml items)
printfn "%s" (processListMarkdown items)
 
