//Rozdział 13.
//Pełnomocnik

//Pełnomocnik zabezpieczający

public class Car // : ICar
{
    public void Drive()
    {
        WriteLine("Car being driven");
    }
}

public interface ICar
{
    void Drive();
}

public class Driver
{
    public int Age { get; set; }
    public Driver(int age)
    {
        Age = age;
    }
}

public class CarProxy : ICar
{
    private Car car = new Car();
    private Driver driver;
    public CarProxy(Driver driver)
    {
        this.driver = driver;
    }
    public void Drive()
    {
        if (driver.Age >= 16)
            car.Drive();
        else
        {
            WriteLine("Kierowca jest za młody");
        }
    }
}
ICar car = new CarProxy(new Driver(12));
car.Drive(); // Kierowca jest za młody

// Pełnomocnik właściwości
public class Property<T> where T : new()
{
    private T value;
    private readonly string name;
    public T Value
    {
        get => value;
        set
        {
            if (Equals(this.value, value)) return;
            Console.WriteLine($"Przypisanie {value} do właściwości {name}");
            this.value = value;
        }
    }
    public Property() : this(default(T)) {}
    public Property(T value, string name = "")
    {
        this.value = value;
        this.name = name;
    }
}

public static implicit operator T(Property<T> property)
{
    return property.Value; // int n = p_int;
}

public static implicit operator Property<T>(T value)
{
    return new Property<T>(value); // Property<int> p = 123;
}

public class Creature
{
    public Property<int> Agility
        = new Property<int>(10, nameof(Agility))
}

var c = new Creature();
c.Agility = 12; // <nothing happens!>

public class Creature
{
    public readonly Property<int> agility
        = new Property<int>(10, nameof(agility));
    public int Agility
    {
        get => agility.Value;
        set => agility.Value = value;
    }
}

var c = new Creature();
c.Agility = 12; // Przypisanie 12 do Agility

// Pełnomocnik wirtualny

interface IImage
{
    void Draw();
}

class Bitmap : IImage
{
    private readonly string filename;
    public Bitmap(string filename)
    {
        this.filename = filename;
        WriteLine($"Ładowanie obrazu z {filename}");
    }
    public void Draw()
    {
        WriteLine($"Rysowanie obrazu {filename}");
    }
}

var img = new Bitmap("pokemon.png");
// Ładowanie obrazu z pokemon.png
 class LazyBitmap : IImage
{
    private readonly string filename;
    private Bitmap bitmap;
    public LazyBitmap(string filename)
    {
        this.filename = filename;
    }
    public void Draw()
    {
        if (bitmap == null)
            bitmap = new Bitmap(filename);
        bitmap.Draw();
    }
}

public static void DrawImage(IImage img)
{
    WriteLine("Zamierzam narysować obraz");
    img.Draw();
    WriteLine("Zakończyłem rysowanie obrazu");
}

var img = new LazyBitmap("pokemon.png");
DrawImage(img); // tutaj zostanie załadowany obraz
// Zamierzam narysować obraz
// Ładowanie obrazu z pokemon.png
// Rysowanie obrazu pokemon.png
// Zakończyłem rysowanie obrazu

//Pełnomocnik komunikacji
interface IPingable
{
    string Ping(string message);
}

class Pong : IPingable
{
    public string Ping(string message)
    {
        return message + "pong";
    }
}

void UseIt(IPingable pp)
{
    WriteLine(pp.ping("ping"));
}
Pong pp = new Pong();
for (int i = 0; i < 3; ++i)
{
    UseIt(pp);
}

[Route("api/[controller]")]
public class PingPongController : Controller
{
    [HttpGet("{msg}")]
    public string Get(string msg)
    {
        return msg + "pong";
    }
}

class RemotePong : IPingable
{
    string Ping(string message)
    {
        string uri = "http://localhost:9149/api/pingpong/" + message;
        return new WebClient().DownloadString(uri);
    }
}

RemotePong pp; // was Pong
for (int i = 0; i < 3; ++i)
{
    UseIt(pp);
}
 
