//CZĘŚĆ IV.
//Wzorce zachowań
  
//ROZDZIAŁ 14.
//Łańcuch odpowiedzialności

public class Creature
{
    public string Name;
    public int Attack, Defense;
    public Creature(string name, int attack, int defense) { ... }
}

//Łańcuch metod

public class CreatureModifier
{
    protected Creature creature;
    protected CreatureModifier next;
    public CreatureModifier(Creature creature)
    {
        this.creature = creature;
    }
    public void Add(CreatureModifier cm)
    {
        if (next != null) next.Add(cm);
        else next = cm;
    }
    public virtual void Handle() => next?.Handle();
}

public class DoubleAttackModifier : CreatureModifier
{
    public DoubleAttackModifier(Creature creature)
        : base(creature) {}
    public override void Handle()
    {
        WriteLine($"Podwajanie siły ataku postaci {creature.Name}");
        creature.Attack *= 2;
        base.Handle();
    }
}

public class IncreaseDefenseModifier : CreatureModifier
{
    public IncreaseDefenseModifier(Creature creature)
        : base(creature) {}
    public override void Handle()
    {
        if (creature.Attack <= 2)
        {
            WriteLine($"Zwiększenie siły obrony postaci {creature.Name}");
            creature.Defense++;
        }
        base.Handle();
    }
}

var goblin = new Creature("Goblin", 1, 1);
WriteLine(goblin); // Nazwa: Goblin, atak: 1, obrona: 1
var root = new CreatureModifier(goblin);
root.Add(new DoubleAttackModifier(goblin));
root.Add(new DoubleAttackModifier(goblin));
root.Add(new IncreaseDefenseModifier(goblin));
//ostatecznie...
root.Handle();
WriteLine(goblin); // Nazwa: Goblin, atak: 4, obrona: 1

public class NoBonusesModifier : CreatureModifier
{
    public NoBonusesModifier(Creature creature)
        : base(creature) {}
    public override void Handle()
    {
        WriteLine("Brak bonusa dla Ciebie!");
        // nie ma tu wywołania base.Handle()
    }
}

// Łańcuch brokerów

public class Game // wzorzec mediator
{
    public event EventHandler<Query> Queries; // effectively a chain
    public void PerformQuery(object sender, Query q)
    {
        Queries?.Invoke(sender, q);
    }
}

public class Query
{
    public string CreatureName;
    public enum Argument
    {
        Attack, Defense
    }
    public Argument WhatToQuery;
    public int Value; // dwukierunkowo!
}

public class Creature
{
    private Game game;
    public string Name;
    private int attack, defense;
    public Creature(Game game, string name, int attack, int defense)
    {
        //tutaj oczywiste rzeczy
    }
    // tutaj pozostałe składowe
}

public int Attack
{
    get
    {
        var q = new Query(Name, Query.Argument.Attack, attack);
        game.PerformQuery(this, q);
        return q.Value;
    }
}

public abstract class CreatureModifier : IDisposable
{
    protected Game game;
    protected Creature creature;
    protected CreatureModifier(Game game, Creature creature)
    {
        this.game = game;
        this.creature = creature;
        game.Queries += Handle; // subskrypcja
    }
    protected abstract void Handle(object sender, Query q);
    public void Dispose()
    {
        game.Queries -= Handle; // anulowanie subskrypcji
    }
}

public class DoubleAttackModifier : CreatureModifier
{
    public DoubleAttackModifier(Game game, Creature creature)
        : base(game, creature) {}
    protected override void Handle(object sender, Query q)
    {
        if (q.CreatureName == creature.Name &&
            q.WhatToQuery == Query.Argument.Attack)
            q.Value *= 2;
    }
}

var game = new Game();
var goblin = new Creature(game, "Silny Goblin", 2, 2);
WriteLine(goblin); // Nazwa: Silny Goblin, atak: 2, obrona: 2
using (new DoubleAttackModifier(game, goblin))
{
    WriteLine(goblin); // Nazwa: Silny Goblin, atak: 4, obrona: 2
    using (new IncreaseDefenseModifier(game, goblin))
    {
        WriteLine(goblin); // Nazwa: Silny Goblin, atak: 4, obrona: 4
    }
}
WriteLine(goblin); // Nazwa: Silny Goblin, atak: 2, obrona: 2
 
