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

namespace TestLibrary
{
    // Create an enumeration that contains a list of colors.
    public enum BallColor
    {
        Red,
        Yellow,
        Green,
        Blue,
        Purple
    }

    // Create an enumeration that defines the ball sizes.
    public enum BallSize
    {
        Small,
        Medium,
        Large
    }

    // Define a structure to hold the ball information.
    public struct BallData
    {
        // It's possible to define Color and Size as fields
        // because their content is strictly controlled by the
        // enumeration.
        public BallColor Color;
        public BallSize Size;

        // Use a private field and a public property for the Name.
        private String _Name;
        public String Name
        {
            get
            {
                return _Name;
            }
            set
            {
                // Check the name length for potential problems.
                if (value.Length <= 10)

                    // When the name is the right length, use it.
                    _Name = value;
                else

                    // Otherwise, tell the developer using the class
                    // that there is an exception.
                    throw new
                        ArgumentOutOfRangeException(
                            "Provide a string that is ten characters long.");
            }
        }
    }

    public class TestClass
    {
        // Define the class constructor to initialize variables
        // and perform other useful tasks.
        public TestClass()
        {
            // Allow additions and deletions.
            _AllowAdditions = true;
            _AllowDeletions = true;

            // Create an empty ball list.
            _BallList = new List<BallData>();
        }

        // Make it possible to control additions and deletions.
        private Boolean _AllowAdditions;
        public Boolean AllowAdditions
        {
            get { return _AllowAdditions; }
            set { _AllowAdditions = value; }
        }
        private Boolean _AllowDeletions;
        public Boolean AllowDeletions
        {
            get { return _AllowDeletions; }
            set { _AllowDeletions = value; }
        }

        // Define the list of balls for this application.
        private List<BallData> _BallList;
        public List<BallData> BallList
        {
            get { return _BallList; }
        }

        // The person using the class may want to know how
        // many balls are in the list.
        public Int32 BallCount
        {
            get { return _BallList.Count; }
        }

        // Tell the user when balls are added.
        public delegate void BallAdded(BallData Ball);
        public event BallAdded OnBallAdded;

        // Tell the user when balls are deleted.
        public delegate void BallDeleted(BallData Ball);
        public event BallDeleted OnBallDeleted;

        // Indicate there are no more balls in the list.
        public delegate void EndOfBalls();
        public event EndOfBalls OnEndOfBalls;

        // Create methods for adding and removing balls.
        public List<BallData> AddBall(BallData NewBall)
        {
            // Verify that we can add the ball.
            if (_AllowAdditions)
            {

                // Add the new ball.
                _BallList.Add(NewBall);

                // Raise an event to indicate the addition.
                if (OnBallAdded != null)
                    OnBallAdded(NewBall);

                // Return the updated list.
                return _BallList;
            }
            else
            {
                // Tell the developer there is a problem.
                throw new InvalidOperationException("Additions not allowed.");
            }
        }

        public List<BallData> DeleteBall(BallData OldBall)
        {
            // Verify that there is a ball to delete.
            if (_BallList.Count == 0)
                throw new InvalidOperationException("There are no balls to delete!");

            // Verify that deletions are allowed.
            if (_AllowDeletions)
            {
                // Remove the existing ball.
                _BallList.Remove(OldBall);

                // Raise an event to indicate the deletion.
                if (OnBallDeleted != null)
                    OnBallDeleted(OldBall);

                // Raise an event if this is the last ball.
                if (_BallList.Count == 0)
                    if (OnEndOfBalls != null)
                        OnEndOfBalls();

                // Return the updated list.
                return _BallList;
            }
            else
            {
                // Tell the developer there is a problem.
                throw new InvalidOperationException("Deletions not allowed.");
            }
        }

        // Define a method for obtaining a list of ball names.
        public List<String> GetNames()
        {
            // Create an empty list to hold the name.
            List<String> Names = new List<String>();

            // Obtain a list of names from the internal list.
            foreach (BallData Item in _BallList)
                Names.Add(Item.Name);

            // Return the resulting list.
            return Names;
        }

        // Define a method for returning a specific ball.
        public BallData GetBall(String Name)
        {
            // Check each item in the list for the name.
            foreach (BallData Item in _BallList)

                // If the name matches, return the item to the
                // caller and exit the loop.
                if (Item.Name == Name)
                {
                    return Item;
                }

            // Otherwise, throw an exception to indicate that the
            // ball wasn't found.
            throw new KeyNotFoundException("The ball name doesn't exist.");
        }
    }
}
