using System;
 
namespace DoFactory.GangOfFour.Chain.RealWorld
{
	/// 
	/// MainApp startup class for Real-World 
	/// Chain of Responsibility Design Pattern.
	/// 
  class MainApp
  {
	/// 
	/// Entry point into console application.
	/// 
    static void Main()
    {
      // Setup Chain of Responsibility
      Approver larry = new Director();
      Approver sam = new VicePresident();
      Approver tammy = new President();
 
      larry.SetSuccessor(sam);
      sam.SetSuccessor(tammy);
 
      // Generate and process purchase requests
      Purchase p = new Purchase(2034, 350.00, "Assets");
      larry.ProcessRequest(p);
 
      p = new Purchase(2035, 32590.10, "Project X");
      larry.ProcessRequest(p);
 
      p = new Purchase(2036, 122100.00, "Project Y");
      larry.ProcessRequest(p);
 
      // Wait for user
      Console.ReadKey();
    }
  }
 
	/// 
	/// The 'Handler' abstract class
	/// 
  abstract class Approver
  {
    protected Approver successor;
 
    public void SetSuccessor(Approver successor)
    {
      this.successor = successor;
    }
 
    public abstract void ProcessRequest(Purchase purchase);
  }
 
	/// 
	/// The 'ConcreteHandler' class
	/// 
  class Director : Approver
  {
    public override void ProcessRequest(Purchase purchase)
    {
      if (purchase.Amount < 10000.0)
      {
        Console.WriteLine("{0} approved request# {1}",
          this.GetType().Name, purchase.Number);
      }
      else if (successor != null)
      {
        successor.ProcessRequest(purchase);
      }
    }
  }
 
	/// 
	/// The 'ConcreteHandler' class
	/// 
  class VicePresident : Approver
  {
    public override void ProcessRequest(Purchase purchase)
    {
      if (purchase.Amount < 25000.0)
      {
        Console.WriteLine("{0} approved request# {1}",
          this.GetType().Name, purchase.Number);
      }
      else if (successor != null)
      {
        successor.ProcessRequest(purchase);
      }
    }
  }
 
	/// 
	/// The 'ConcreteHandler' class
	/// 
  class President : Approver
  {
    public override void ProcessRequest(Purchase purchase)
    {
      if (purchase.Amount < 100000.0)
      {
        Console.WriteLine("{0} approved request# {1}",
          this.GetType().Name, purchase.Number);
      }
      else
      {
        Console.WriteLine(
          "Request# {0} requires an executive meeting!",
          purchase.Number);
      }
    }
  }
 
	/// 
	/// Class holding request details
	/// 
  class Purchase
  {
    private int _number;
    private double _amount;
    private string _purpose;
 
    // Constructor
    public Purchase(int number, double amount, string purpose)
    {
      this._number = number;
      this._amount = amount;
      this._purpose = purpose;
    }
 
    // Gets or sets purchase number
    public int Number
    {
      get { return _number; }
      set { _number = value; }
    }
 
    // Gets or sets purchase amount
    public double Amount
    {
      get { return _amount; }
      set { _amount = value; }
    }

    // Gets or sets purchase purpose
    public string Purpose
    {
      get { return _purpose; }
      set { _purpose = value; }
    }
  }
}