//Rozdział 18.
//Mediator

// Chat room

public class Person
{
    public string Name;
    public ChatRoom Room;
    private List<string> chatLog = new List<string>();

    public Person(string name) => Name = name;
    public void Receive(string sender, string message)
    {
        string s = $"{sender}: '{message}'";
        WriteLine($"[{Name}'s chat session] {s}");
        chatLog.Add(s);
    }

    public void Say(string message) => Room.Broadcast(Name, message);

    public void PrivateMessage(string who, string message)
    {
        Room.Message(Name, who, message);
    }
}

public class ChatRoom
{
    private List<Person> people = new List<Person>();

    public void Broadcast(string source, string message) { ... }
    public void Join(Person p) { ... }
    public void Message(string source, string destination, string message) { ... }
}

public void Join(Person p)
{
    string joinMsg = $"{p.Name} dołącza do czatu";
    Broadcast("room", joinMsg);
    p.Room = this;
    people.Add(p);
}

public void Broadcast(string source, string message)
{
    foreach (var p in people)
        if (p.Name != source)
            p.Receive(source, message);
}
 public void Message(string source, string destination, string
message)
{
    people.FirstOrDefault(p => p.Name == destination)?.Receive(source, message);
}

public void Say(string message) => Room.Broadcast(Name, message);
public void PrivateMessage(string who, string message)
{
    Room.Message(Name, who, message);
}

public void Receive(string sender, string message)
{
    string s = $"{sender}: '{message}'";
    WriteLine($"[sesja czatu użytkownika {Name}] {s}");
    chatLog.Add(s);
}

var room = new ChatRoom();
var jan = new Person("Jan");
var janina = new Person("Janina");
room.Join(jan);
room.Join(janina);
jan.Say("cześć wszystkim");
janina.Say("cześć, witaj janie");
var szymon = new Person("Szymon");
room.Join(szymon);
szymon.Say("witajcie wszyscy!");
janina.PrivateMessage("Szymon", "cieszę się, że do nas dołączyłeś szymonie!");
[sesja czatu użytkownika jan] room: "janina dołącza do czatu"
[sesja czatu użytkownika janina] jan: "cześć wszystkim"
[sesja czatu użytkownika jan] janina: "cześć, witaj janie"
[sesja czatu użytkownika jan] room: "szymon dołącza do czatu"
[sesja czatu użytkownika janina] room: "szymon dołącza do czatu"
[sesja czatu użytkownika jan] szymon: "witajcie wszyscy!"
[sesja czatu użytkownika janina] simon: "witajcie wszyscy!"
[sesja czatu użytkownika szymon] janina: "cieszę się, że do nas dołączyłeś szymonie"

//Mediator ze zdarzeniami
abstract class GameEventArgs : EventArgs
{
    public abstract void Print();
}

class PlayerScoredEventArgs : GameEventArgs
{
    public string PlayerName;
    public int GoalsScoredSoFar;

    public PlayerScoredEventArgs(string playerName, int goalsScoredSoFar)
    {
        PlayerName = playerName;
        GoalsScoredSoFar = goalsScoredSoFar;
    }
    public override void Print()
    {
        WriteLine($"{PlayerName} zdobył gola!" +
                  $"(jego {GoalsScoredSoFar} gol)");
    }
}

class Game
{
    public event EventHandler<GameEventArgs> Events;
    public void Fire(GameEventArgs args)
    {
        Events?.Invoke(this, args);
    }
}

class Player
{
    private string name;
    private int goalsScored = 0;
    private Game game;

    public Player(Game game, string name)
    {
        this.name = name;
        this.game = game;
    }

    public void Score()
    {
        goalsScored++;
        var args = new PlayerScoredEventArgs(name, goalsScored);
        game.Fire(args);
    }
}

class Coach
{
    private Game game;
    public Coach(Game game)
    {
        this.game = game;
        //świętujemy, jeśli gracz strzelił mniej niż 3 bramki
        game.Events += (sender, args) =>
        {
            if (args is PlayerScoredEventArgs scored
                && scored.GoalsScoredSoFar < 3)
            {
                WriteLine($"trener mówi: dobra robota, {scored.PlayerName}");
            }
        };
    }
}

var game = new Game();
var player = new Player(game, "Staś");
var coach = new Coach(game);
player.Score(); // trener mówi: dobra robota, Staś
player.Score(); //trener mówi: dobra robota, Staś
player.Score(); //
 
