Categories
Visual C# ООП Телерик

Подготовка за изпита по ООП

War Machines

Решение

namespace WarMachines.Engine {
  using System;
  using System.Collections.Generic;
  using System.Linq;

  using WarMachines.Interfaces;

  public class Command: ICommand {
    private
    const char SplitCommandSymbol = ' ';

    private string name;
    private IList parameters;

    private Command(string input) {
      this.TranslateInput(input);
    }

    public string Name {
      get {
        return this.name;
      }

      private set {
        if (string.IsNullOrEmpty(value)) {
          throw new ArgumentNullException("Name cannot be null or empty.");
        }

        this.name = value;
      }
    }

    public IList Parameters {
      get {
        return this.parameters;
      }

      private set {
        if (value == null) {
          throw new ArgumentNullException("List of strings cannot be null.");
        }

        this.parameters = value;
      }
    }

    public static Command Parse(string input) {
      return new Command(input);
    }

    private void TranslateInput(string input) {
      var indexOfFirstSeparator = input.IndexOf(SplitCommandSymbol);

      this.Name = input.Substring(0, indexOfFirstSeparator);
      this.Parameters = input.Substring(indexOfFirstSeparator + 1).Split(new [] {
        SplitCommandSymbol
      }, StringSplitOptions.RemoveEmptyEntries);
    }
  }
}
namespace WarMachines.Engine {
  using WarMachines.Interfaces;
  using WarMachines.Machines;

  public class MachineFactory: IMachineFactory {
    public IPilot HirePilot(string name) {
      IPilot pilot = new Pilot(name);
      return pilot;
    }

    public ITank ManufactureTank(string name, double attackPoints, double defensePoints) {
      Tank tank = new Tank(name, attackPoints, defensePoints);
      return tank;
    }

    public IFighter ManufactureFighter(string name, double attackPoints, double defensePoints, bool stealthMode) {
      Fighter fighter = new Fighter(name, attackPoints, defensePoints, stealthMode);
      return fighter;
    }
  }
}
namespace WarMachines.Engine {
  using System;
  using System.Collections.Generic;
  using System.Text;

  using WarMachines.Interfaces;

  public sealed class WarMachineEngine: IWarMachineEngine {
    private
    const string InvalidCommand = "Invalid command name: {0}";
    private
    const string PilotHired = "Pilot {0} hired";
    private
    const string PilotExists = "Pilot {0} is hired already";
    private
    const string TankManufactured = "Tank {0} manufactured - attack: {1}; defense: {2}";
    private
    const string FighterManufactured = "Fighter {0} manufactured - attack: {1}; defense: {2}; stealth: {3}";
    private
    const string MachineExists = "Machine {0} is manufactured already";
    private
    const string MachineHasPilotAlready = "Machine {0} is already occupied";
    private
    const string PilotNotFound = "Pilot {0} could not be found";
    private
    const string MachineNotFound = "Machine {0} could not be found";
    private
    const string MachineEngaged = "Pilot {0} engaged machine {1}";
    private
    const string InvalidMachineOperation = "Machine {0} does not support this operation";
    private
    const string FighterOperationSuccessful = "Fighter {0} toggled stealth mode";
    private
    const string TankOperationSuccessful = "Tank {0} toggled defense mode";
    private
    const string InvalidAttackTarget = "Tank {0} cannot attack stealth fighter {1}";
    private
    const string AttackSuccessful = "Machine {0} was attacked by machine {1} - current health: {2}";

    private static readonly WarMachineEngine SingleInstance = new WarMachineEngine();

    private IMachineFactory factory;
    private IDictionary pilots;
    private IDictionary machines;

    private WarMachineEngine() {
      this.factory = new MachineFactory();
      this.pilots = new Dictionary();
      this.machines = new Dictionary();
    }

    public static WarMachineEngine Instance {
      get {
        return SingleInstance;
      }
    }

    public void Start() {
      var commands = this.ReadCommands();
      var commandResult = this.ProcessCommands(commands);
      this.PrintReports(commandResult);
    }

    private IList ReadCommands() {
      var commands = new List();

      var currentLine = Console.ReadLine();

      while (!string.IsNullOrEmpty(currentLine)) {
        var currentCommand = Command.Parse(currentLine);
        commands.Add(currentCommand);

        currentLine = Console.ReadLine();
      }

      return commands;
    }

    private IList ProcessCommands(IList commands) {
      var reports = new List();

      foreach(var command in commands) {
        string commandResult;

        switch (command.Name) {
        case "HirePilot":
          var pilotName = command.Parameters[0];
          commandResult = this.HirePilot(pilotName);
          reports.Add(commandResult);
          break;

        case "Report":
          var pilotReporting = command.Parameters[0];
          commandResult = this.PilotReport(pilotReporting);
          reports.Add(commandResult);
          break;

        case "ManufactureTank":
          var tankName = command.Parameters[0];
          var tankAttackPoints = double.Parse(command.Parameters[1]);
          var tankDefensePoints = double.Parse(command.Parameters[2]);
          commandResult = this.ManufactureTank(tankName, tankAttackPoints, tankDefensePoints);
          reports.Add(commandResult);
          break;

        case "DefenseMode":
          var defenseModeTankName = command.Parameters[0];
          commandResult = this.ToggleTankDefenseMode(defenseModeTankName);
          reports.Add(commandResult);
          break;

        case "ManufactureFighter":
          var fighterName = command.Parameters[0];
          var fighterAttackPoints = double.Parse(command.Parameters[1]);
          var fighterDefensePoints = double.Parse(command.Parameters[2]);
          var fighterStealthMode = command.Parameters[3] == "StealthON" ? true : false;
          commandResult = this.ManufactureFighter(fighterName, fighterAttackPoints, fighterDefensePoints, fighterStealthMode);
          reports.Add(commandResult);
          break;

        case "StealthMode":
          var stealthModeFighterName = command.Parameters[0];
          commandResult = this.ToggleFighterStealthMode(stealthModeFighterName);
          reports.Add(commandResult);
          break;

        case "Engage":
          var selectedPilotName = command.Parameters[0];
          var selectedMachineName = command.Parameters[1];
          commandResult = this.EngageMachine(selectedPilotName, selectedMachineName);
          reports.Add(commandResult);
          break;

        case "Attack":
          var attackingMachine = command.Parameters[0];
          var defendingMachine = command.Parameters[1];
          commandResult = this.AttackMachines(attackingMachine, defendingMachine);
          reports.Add(commandResult);
          break;

        default:
          reports.Add(string.Format(InvalidCommand, command.Name));
          break;
        }
      }

      return reports;
    }

    private void PrintReports(IList reports) {
      var output = new StringBuilder();

      foreach(var report in reports) {
        output.AppendLine(report);
      }

      Console.Write(output.ToString());
    }

    private string HirePilot(string name) {
      if (this.pilots.ContainsKey(name)) {
        return string.Format(PilotExists, name);
      }

      var pilot = this.factory.HirePilot(name);
      this.pilots.Add(name, pilot);

      return string.Format(PilotHired, name);
    }

    private string ManufactureTank(string name, double attackPoints, double defensePoints) {
      if (this.machines.ContainsKey(name)) {
        return string.Format(MachineExists, name);
      }

      var tank = this.factory.ManufactureTank(name, attackPoints, defensePoints);
      this.machines.Add(name, tank);

      return string.Format(TankManufactured, name, attackPoints, defensePoints);
    }

    private string ManufactureFighter(string name, double attackPoints, double defensePoints, bool stealthMode) {
      if (this.machines.ContainsKey(name)) {
        return string.Format(MachineExists, name);
      }

      var fighter = this.factory.ManufactureFighter(name, attackPoints, defensePoints, stealthMode);
      this.machines.Add(name, fighter);

      return string.Format(FighterManufactured, name, attackPoints, defensePoints, stealthMode == true ? "ON" : "OFF");
    }

    private string EngageMachine(string selectedPilotName, string selectedMachineName) {
      if (!this.pilots.ContainsKey(selectedPilotName)) {
        return string.Format(PilotNotFound, selectedPilotName);
      }

      if (!this.machines.ContainsKey(selectedMachineName)) {
        return string.Format(MachineNotFound, selectedMachineName);
      }

      if (this.machines[selectedMachineName].Pilot != null) {
        return string.Format(MachineHasPilotAlready, selectedMachineName);
      }

      var pilot = this.pilots[selectedPilotName];
      var machine = this.machines[selectedMachineName];

      pilot.AddMachine(machine);
      machine.Pilot = pilot;

      return string.Format(MachineEngaged, selectedPilotName, selectedMachineName);
    }

    private string AttackMachines(string attackingMachineName, string defendingMachineName) {
      if (!this.machines.ContainsKey(attackingMachineName)) {
        return string.Format(MachineNotFound, attackingMachineName);
      }

      if (!this.machines.ContainsKey(defendingMachineName)) {
        return string.Format(MachineNotFound, defendingMachineName);
      }

      var attackingMachine = this.machines[attackingMachineName];
      var defendingMachine = this.machines[defendingMachineName];

      if (attackingMachine is ITank && defendingMachine is IFighter && (defendingMachine as IFighter).StealthMode) {
        return string.Format(InvalidAttackTarget, attackingMachineName, defendingMachineName);
      }

      attackingMachine.Targets.Add(defendingMachineName);

      var attackPoints = attackingMachine.AttackPoints;
      var defensePoints = defendingMachine.DefensePoints;

      var damage = attackPoints - defensePoints;

      if (damage > 0) {
        var newHeathPoints = defendingMachine.HealthPoints - damage;

        if (newHeathPoints < 0) {
          newHeathPoints = 0;
        }
        defendingMachine.HealthPoints = newHeathPoints;
      }
      return string.Format(AttackSuccessful, defendingMachineName, attackingMachineName, defendingMachine.HealthPoints);
    }
    private string PilotReport(string pilotReporting) {
      if (!this.pilots.ContainsKey(pilotReporting)) {
        return string.Format(PilotNotFound, pilotReporting);
      }
      return this.pilots[pilotReporting].Report();
    }
    private string ToggleFighterStealthMode(string stealthModeFighterName) {
      if (!this.machines.ContainsKey(stealthModeFighterName)) {
        return string.Format(MachineNotFound, stealthModeFighterName);
      }
      if (this.machines[stealthModeFighterName] is ITank) {
        return string.Format(InvalidMachineOperation, stealthModeFighterName);
      }
      var machineAsFighter = this.machines[stealthModeFighterName] as IFighter;
      machineAsFighter.ToggleStealthMode();
      return string.Format(FighterOperationSuccessful, stealthModeFighterName);
    }
    private string ToggleTankDefenseMode(string defenseModeTankName) {
      if (!this.machines.ContainsKey(defenseModeTankName)) {
        return string.Format(MachineNotFound, defenseModeTankName);
      }
      if (this.machines[defenseModeTankName] is IFighter) {
        return string.Format(InvalidMachineOperation, defenseModeTankName);
      }
      var machineAsFighter = this.machines[defenseModeTankName] as ITank;
      machineAsFighter.ToggleDefenseMode();
      return string.Format(TankOperationSuccessful, defenseModeTankName);
    }
  }
}
namespace WarMachines.Interfaces {
  using System.Collections.Generic;
  public interface ICommand {
    string Name {
      get;
    }
    IList Parameters {
      get;
    }
  }
}
namespace WarMachines.Interfaces {
  public interface IFighter: IMachine {
    bool StealthMode {
      get;
    }

    void ToggleStealthMode();
  }
}
namespace WarMachines.Interfaces {
  using System.Collections.Generic;

  public interface IMachine {
    string Name {
      get;
      set;
    }

    IPilot Pilot {
      get;
      set;
    }

    double HealthPoints {
      get;
      set;
    }

    double AttackPoints {
      get;
    }

    double DefensePoints {
      get;
    }

    IList Targets {
      get;
    }

    void Attack(string target);

    string ToString();
  }
}
namespace WarMachines.Interfaces {
  public interface IMachineFactory {
    IPilot HirePilot(string name);

    ITank ManufactureTank(string name, double attackPoints, double defensePoints);

    IFighter ManufactureFighter(string name, double attackPoints, double defensePoints, bool stealthMode);
  }
}
namespace WarMachines.Interfaces {
  public interface IPilot {
    string Name {
      get;
    }

    void AddMachine(IMachine machine);

    string Report();
  }
}
namespace WarMachines.Interfaces {
  public interface ITank: IMachine {
    bool DefenseMode {
      get;
    }

    void ToggleDefenseMode();
  }
}
namespace WarMachines.Interfaces {

  public interface IWarMachineEngine {
    void Start();
  }
}
namespace WarMachines.Machines {
  using System;
  using System.Linq;
  using System.Text;
  using WarMachines.Interfaces;

  public class Fighter: Machine, IFighter {
    protected bool stealthMode;

    public Fighter(string name, double attackPoints, double defensePoints, bool stealthMode): base(name, attackPoints, defensePoints) {
      this.HealthPoints = 200;
      this.stealthMode = stealthMode;
    }

    public bool StealthMode {
      get {
        return this.stealthMode;
      }
    }

    public void ToggleStealthMode() {
      this.stealthMode = this.stealthMode ? false : true;
    }

    public override string ToString() {
      StringBuilder output = new StringBuilder();
      output.AppendLine(base.ToString());
      output.AppendFormat(" *Stealth: {0}", this.StealthMode ? "ON" : "OFF");
      return output.ToString();
    }
  }
}
namespace WarMachines.Machines {
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using WarMachines.Interfaces;

  public abstract class Machine: IMachine {
    protected string name;
    protected IPilot pilot;
    protected double healthPoints;
    protected double attackPoints;
    protected double defensePoints;
    protected IList targets;

    public Machine(string name, double attackPoints, double defensePoints) {
      this.Name = name;
      this.attackPoints = attackPoints;
      this.defensePoints = defensePoints;
      this.targets = new List();
    }

    public string Name {
      get {
        return this.name;
      }
      set {
        this.name = value;
      }
    }

    public IPilot Pilot {
      get {
        return this.pilot;
      }
      set {
        this.pilot = value;
      }
    }

    public double HealthPoints {
      get {
        return this.healthPoints;
      }
      set {
        this.healthPoints = value;
      }
    }

    public double AttackPoints {
      get {
        return this.attackPoints;
      }
    }

    public double DefensePoints {
      get {
        return this.defensePoints;
      }
    }

    public IList Targets {
      get {
        return this.targets;
      }
    }

    public void Attack(string target) {
      this.targets.Add(target);
    }

    public override string ToString() {
      StringBuilder output = new StringBuilder();
      output.AppendLine(string.Format("- {0}", this.name));
      output.AppendLine(string.Format(" *Type: {0}", this.GetType().Name));
      output.AppendLine(string.Format(" *Health: {0}", this.HealthPoints));
      output.AppendLine(string.Format(" *Attack: {0}", this.AttackPoints));
      output.AppendLine(string.Format(" *Defense: {0}", this.DefensePoints));
      output.AppendFormat(" *Targets: {0}", this.Targets.Count > 0 ? string.Join(", ", this.Targets) : "None");
      return output.ToString();
    }
  }
}
namespace WarMachines.Machines {
  using System.Collections.Generic;
  using System.Text;
  using WarMachines.Interfaces;
  using System.Linq;

  public class Pilot: IPilot {
    private string name;
    private IList machines;

    public Pilot(string name) {
      this.name = name;
      this.machines = new List();
    }

    public string Name {
      get {
        return this.name;
      }
    }

    public void AddMachine(IMachine machine) {
      this.machines.Add(machine);
    }

    public string Report() {
      StringBuilder output = new StringBuilder();
      if (this.machines.Count == 0) {
        output.AppendFormat("{0} - no machines", this.Name);
      } else {
        output.AppendLine(string.Format("{0} - {1} {2}", this.name, this.machines.Count, this.machines.Count == 1 ? "machine" : "machines"));
        var sortedMachines = this.machines.OrderBy(m => m.HealthPoints).ThenBy(m => m.Name).ToList();
        for (int i = 0; i < sortedMachines.Count - 1; i++) {
          output.AppendLine(sortedMachines[i].ToString());
        }
        output.Append(sortedMachines.Last().ToString());
      }
      return output.ToString();
    }
  }
}
namespace WarMachines.Machines {
  using System.Text;
  using WarMachines.Interfaces;
  public class Tank: Machine, ITank {
    private bool defenseMode = true;
    public Tank(string name, double attackPoints, double defensePoints): base(name, attackPoints, defensePoints) {
      this.HealthPoints = 100;
      this.attackPoints -= 40;
      this.defensePoints += 30;
    }
    public bool DefenseMode {
      get {
        return this.defenseMode;
      }
    }
    public void ToggleDefenseMode() {
      if (this.defenseMode) {
        this.defenseMode = false;
        this.attackPoints += 40;
        this.defensePoints -= 30;
      } else {
        this.defenseMode = true;
        this.attackPoints -= 40;
        this.defensePoints += 30;
      }
    }
    public override string ToString() {
      StringBuilder output = new StringBuilder();
      output.AppendLine(base.ToString());
      output.AppendFormat(" *Defense: {0}", this.DefenseMode ? "ON" : "OFF");
      return output.ToString();
    }
  }
}
namespace WarMachines {
  using WarMachines.Engine;
  public class WarMachinesProgram {
    public static void Main() {
      WarMachineEngine.Instance.Start();
    }
  }
}

Document System

Решение:

  using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Document;

namespace Document {
  public class AudioDocument: MultimediaDocument {
    private int ? sampleRate = null;

    public override void LoadProperty(string key, string value) {

      switch (key) {
      case "samplerate":
        this.sampleRate = int.Parse(value);
        break;
      default:
        base.LoadProperty(key, value);
        break;
      }
    }

    public override void SaveAllProperties(IList > output) {
      base.SaveAllProperties(output);
      output.Add(new KeyValuePair("samplerate", this.SampleRate));
    }

    public int ? SampleRate {
      get {
        return this.sampleRate;
      }
    }
  }
}

namespace Document {
  public abstract class BinaryDocument: Document {
    protected int ? size = null;

    public override void LoadProperty(string key, string value) {
      switch (key) {
      case "size":
        this.size = int.Parse(value);
        break;
      default:
        base.LoadProperty(key, value);
        break;
      }
    }

    public override void SaveAllProperties(IList > output) {
      base.SaveAllProperties(output);
      output.Add(new KeyValuePair("size", this.Size));
    }

    public int ? Size {
      get {
        return this.size;
      }
    }
  }
}

namespace Document {
  public abstract class Document: IDocument {
    protected string name;
    protected string content;

    public string Name {
      get {
        return this.name;
      }
    }

    public string Content {
      get {
        return this.content;
      }
    }

    public virtual void LoadProperty(string key, string value) {
      switch (key) {
      case "name":
        this.name = value;
        break;
      case "content":
        this.content = value;
        break;
      }
    }

    public virtual void SaveAllProperties(IList > output) {
      output.Add(new KeyValuePair("name", this.Name));
      output.Add(new KeyValuePair("content", this.Content));
    }

    public override string ToString() {
      IList > properties = new List > ();
      this.SaveAllProperties(properties);
      var sortedProperties = properties.OrderBy(prop => prop.Key).ToList();

      StringBuilder output = new StringBuilder();
      foreach(var property in sortedProperties) {
        if (property.Value == null || property.Value.ToString() == string.Empty) {
          continue;
        }
        output.AppendFormat("{0}={1};", property.Key, property.Value);
      }
      output.Length -= 1;

      return output.ToString();
    }
  }
}

public interface IDocument {
  string Name {
    get;
  }
  string Content {
    get;
  }
  void LoadProperty(string key, string value);
  void SaveAllProperties(IList > output);
  string ToString();
}

public interface IEditable {
  void ChangeContent(string newContent);
}

public interface IEncryptable {
  bool IsEncrypted {
    get;
  }
  void Encrypt();
  void Decrypt();
}

public class DocumentSystem {
  private static IList documents = new List();

  static void Main() {
    IList allCommands = ReadAllCommands();
    ExecuteCommands(allCommands);
  }

  private static IList ReadAllCommands() {
    List commands = new List();
    while (true) {
      string commandLine = Console.ReadLine();
      if (commandLine == "") {
        // End of commands
        break;
      }
      commands.Add(commandLine);
    }
    return commands;
  }

  private static void ExecuteCommands(IList commands) {
    foreach(var commandLine in commands) {
      int paramsStartIndex = commandLine.IndexOf("[");
      string cmd = commandLine.Substring(0, paramsStartIndex);
      int paramsEndIndex = commandLine.IndexOf("]");
      string parameters = commandLine.Substring(
        paramsStartIndex + 1, paramsEndIndex - paramsStartIndex - 1);
      ExecuteCommand(cmd, parameters);
    }
  }

  private static void ExecuteCommand(string cmd, string parameters) {
    string[] cmdAttributes = parameters.Split(
      new char[] {
        ';'
      }, StringSplitOptions.RemoveEmptyEntries);
    if (cmd == "AddTextDocument") {
      AddTextDocument(cmdAttributes);
    } else if (cmd == "AddPDFDocument") {
      AddPdfDocument(cmdAttributes);
    } else if (cmd == "AddWordDocument") {
      AddWordDocument(cmdAttributes);
    } else if (cmd == "AddExcelDocument") {
      AddExcelDocument(cmdAttributes);
    } else if (cmd == "AddAudioDocument") {
      AddAudioDocument(cmdAttributes);
    } else if (cmd == "AddVideoDocument") {
      AddVideoDocument(cmdAttributes);
    } else if (cmd == "ListDocuments") {
      ListDocuments();
    } else if (cmd == "EncryptDocument") {
      EncryptDocument(parameters);
    } else if (cmd == "DecryptDocument") {
      DecryptDocument(parameters);
    } else if (cmd == "EncryptAllDocuments") {
      EncryptAllDocuments();
    } else if (cmd == "ChangeContent") {
      ChangeContent(cmdAttributes[0], cmdAttributes[1]);
    } else {
      throw new InvalidOperationException("Invalid command: " + cmd);
    }
  }

  private static void AddDocument(IDocument document, string[] attributes) {
    foreach(var attribute in attributes) {
      string[] splittedAttribute = attribute.Split('=');
      string key = splittedAttribute[0];
      string value = splittedAttribute[1];
      document.LoadProperty(key, value);
    }
    if (document.Name == null) {
      Console.WriteLine("Document has no name");
    } else {
      documents.Add(document);
      Console.WriteLine("Document added: {0}", document.Name);
    }
  }

  private static void AddTextDocument(string[] attributes) {
    IDocument document = new TextDocument();
    AddDocument(document, attributes);
  }

  private static void AddPdfDocument(string[] attributes) {
    IDocument document = new PDFDocument();
    AddDocument(document, attributes);
  }

  private static void AddWordDocument(string[] attributes) {
    IDocument document = new WordDocument();
    AddDocument(document, attributes);
  }

  private static void AddExcelDocument(string[] attributes) {
    IDocument document = new ExcelDocument();
    AddDocument(document, attributes);
  }

  private static void AddAudioDocument(string[] attributes) {
    IDocument document = new AudioDocument();
    AddDocument(document, attributes);
  }

  private static void AddVideoDocument(string[] attributes) {
    IDocument document = new VideoDocument();
    AddDocument(document, attributes);
  }

  private static void ListDocuments() {
    if (documents.Count() > 0) {
      foreach(var document in documents) {
        if (document is IEncryptable && ((IEncryptable) document).IsEncrypted) {
          Console.WriteLine("{0}[encrypted]", document.GetType().Name);
        } else {
          Console.WriteLine("{0}[{1}]", document.GetType().Name, document.ToString());
        }
      }
    } else {
      Console.WriteLine("No documents found");
    }
  }

  private static void EncryptDocument(string name) {
    if (documents.Where(doc => doc.Name == name).Count() == 0) {
      Console.WriteLine("Document not found: {0}", name);
    } else {
      foreach(var document in documents) {
        if (document.Name == name) {
          if (document is IEncryptable) {
            ((IEncryptable) document).Encrypt();
            Console.WriteLine("Document encrypted: {0}", document.Name);
          } else {
            Console.WriteLine("Document does not support encryption: {0}", document.Name);
          }
        }
      }
    }
  }

  private static void DecryptDocument(string name) {
    if (documents.Where(doc => doc.Name == name).Count() == 0) {
      Console.WriteLine("Document not found: {0}", name);
    } else {
      foreach(var document in documents) {
        if (document.Name == name) {
          if (document is IEncryptable) {
            ((IEncryptable) document).Decrypt();
            Console.WriteLine("Document decrypted: {0}", document.Name);
          } else {
            Console.WriteLine("Document does not support decryption: {0}", document.Name);
          }
        }
      }
    }
  }

  private static void EncryptAllDocuments() {
    if (documents.Where(doc => doc is IEncryptable).Count() > 0) {
      foreach(var document in documents) {
        if (document is IEncryptable) {
          ((IEncryptable) document).Encrypt();
        }
      }
      Console.WriteLine("All documents encrypted");
    } else {
      Console.WriteLine("No encryptable documents found");
    }
  }

  private static void ChangeContent(string name, string content) {
    if (documents.Where(doc => doc.Name == name).Count() > 0) {
      foreach(var document in documents) {
        if (document.Name == name) {
          if (document is IEditable) {
            ((IEditable) document).ChangeContent(content);
            Console.WriteLine("Document content changed: {0}", document.Name);
          } else {
            Console.WriteLine("Document is not editable: {0}", document.Name);
          }
        }
      }
    } else {
      Console.WriteLine("Document not found: {0}", name);
    }
  }
}

namespace Document {
  public abstract class EncryptableBinaryDocument: BinaryDocument, IEncryptable {
    private bool isEncrypted = false;

    public bool IsEncrypted {
      get {
        return this.isEncrypted;
      }
    }

    public void Encrypt() {
      if (!this.isEncrypted) {
        this.isEncrypted = true;
      }
    }

    public void Decrypt() {
      if (this.isEncrypted) {
        this.isEncrypted = false;
      }
    }
  }
}

namespace Document {
  public abstract class EncryptableOfficeDocument: OfficeDocument, IEncryptable {
    private bool isEncrypted = false;

    public bool IsEncrypted {
      get {
        return this.isEncrypted;
      }
    }

    public void Encrypt() {
      if (!this.isEncrypted) {
        this.isEncrypted = true;
      }
    }

    public void Decrypt() {
      if (this.isEncrypted) {
        this.isEncrypted = false;
      }
    }
  }
}

namespace Document {
  public class ExcelDocument: EncryptableOfficeDocument {
    private int ? numberOfRows;
    private int ? numberOfColumns;

    public override void LoadProperty(string key, string value) {

      switch (key) {
      case "rows":
        this.numberOfRows = int.Parse(value);
        break;
      case "cols":
        this.numberOfColumns = int.Parse(value);
        break;
      default:
        base.LoadProperty(key, value);
        break;
      }
    }

    public override void SaveAllProperties(IList > output) {
      base.SaveAllProperties(output);
      output.Add(new KeyValuePair("rows", this.NumberOfRows));
      output.Add(new KeyValuePair("cols", this.NumberOfColumns));
    }

    public int ? NumberOfRows {
      get {
        return this.numberOfRows;
      }
    }

    public int ? NumberOfColumns {
      get {
        return this.numberOfColumns;
      }
    }
  }
}

namespace Document {
  public abstract class MultimediaDocument: BinaryDocument {
    protected int ? length = null;

    public override void LoadProperty(string key, string value) {

      switch (key) {
      case "length":
        this.length = int.Parse(value);
        break;
      default:
        base.LoadProperty(key, value);
        break;
      }
    }

    public override void SaveAllProperties(IList > output) {
      base.SaveAllProperties(output);
      output.Add(new KeyValuePair("length", this.Length));
    }

    public int ? Length {
      get {
        return this.length;
      }
    }
  }
}

namespace Document {
  public abstract class OfficeDocument: BinaryDocument {
    protected string version = string.Empty;

    public override void LoadProperty(string key, string value) {

      switch (key) {
      case "version":
        this.version = value;
        break;
      default:
        base.LoadProperty(key, value);
        break;
      }
    }

    public override void SaveAllProperties(IList > output) {
      base.SaveAllProperties(output);
      output.Add(new KeyValuePair("version", this.Version));
    }

    public string Version {
      get {
        return this.version;
      }
    }
  }
}

namespace Document {
  public class PDFDocument: EncryptableBinaryDocument {
    private int ? numberOfPages = null;

    public int ? NumberOfPages {
      get {
        return this.numberOfPages;
      }
    }

    public override void SaveAllProperties(IList > output) {
      base.SaveAllProperties(output);
      output.Add(new KeyValuePair("pages", this.NumberOfPages));
    }

    public override void LoadProperty(string key, string value) {

      switch (key) {
      case "pages":
        this.numberOfPages = int.Parse(value);
        break;
      default:
        base.LoadProperty(key, value);
        break;
      }
    }
  }
}

namespace Document {
  public class TextDocument: Document, IEditable {
    private string charset = string.Empty;

    public string Charset {
      get {
        return this.charset;
      }
    }

    public override void LoadProperty(string key, string value) {

      switch (key) {
      case "charset":
        this.charset = value;
        break;
      default:
        base.LoadProperty(key, value);
        break;
      }
    }

    public override void SaveAllProperties(IList > output) {
      base.SaveAllProperties(output);
      output.Add(new KeyValuePair("charset", this.Charset));
    }

    public void ChangeContent(string newContent) {
      this.content = newContent;
    }
  }
}

namespace Document {
  public class VideoDocument: MultimediaDocument {
    private int ? frameRate = null;

    public override void LoadProperty(string key, string value) {

      switch (key) {
      case "framerate":
        this.frameRate = int.Parse(value);
        break;
      default:
        base.LoadProperty(key, value);
        break;
      }
    }

    public override void SaveAllProperties(IList > output) {
      base.SaveAllProperties(output);
      output.Add(new KeyValuePair("framerate", this.FrameRate));
    }

    public int ? FrameRate {
      get {
        return this.frameRate;
      }
    }
  }
}

namespace Document {
  public class WordDocument: EncryptableOfficeDocument, IEditable {
    private int ? numberOfCharacters = null;

    public int ? NumberOfCharacters {
      get {
        return this.numberOfCharacters;
      }
    }

    public override void LoadProperty(string key, string value) {

      switch (key) {
      case "chars":
        this.numberOfCharacters = int.Parse(value);
        break;
      default:
        base.LoadProperty(key, value);
        break;
      }
    }

    public override void SaveAllProperties(IList > output) {
      base.SaveAllProperties(output);
      output.Add(new KeyValuePair("chars", this.NumberOfCharacters));
    }

    public void ChangeContent(string newContent) {
      this.content = newContent;
    }
  }
}