using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Xml;
using System.Xml.Serialization;
using ImageBlockz.Core;
using ImageBlockz.Api;

namespace ImageBlockz.Core
{
    /// <summary>
    /// This class implements posibility to store many operations into one sequence and work with them.
    /// </summary>
    public class Sequence : AbstractOperation, IEnumerable<IOperation>
    {
        private List<IOperation> list = new List<IOperation> ();

        /// <summary>
        /// Creates instance of sequence and set <see cref="OperationType"/> to its parent (<see cref="AbstractOperation"/>)
        /// </summary>
        public Sequence()
            : base(OperationType.Filter)
        {
            
        }

        /// <summary>
        /// Set constant OperationName to sequence.
        /// </summary>
        public const string OperationName = "sequence";
        
        //[Obsolete("This is not useful, because of implementation of IEnumerable")]
        /// <summary>
        /// Get list of operations in array.
        /// </summary>
        public IOperation[] Operations
        {
            get
            {
                return list.ToArray();
            }
        }

        /// <summary>
        /// Add <see cref="IOperation"/> into the list.
        /// </summary>
        /// <param name="oper"><see cref="IOperation"/></param>
        public void Add(IOperation oper)
        {
            list.Add(oper);
        }

        /// <summary>
        /// Returns index of <see cref="IOperation"/> in the list.
        /// </summary>
        /// <param name="operation"><see cref="IOperation"/></param>
        /// <returns>Index of operation in the list.</returns>
        public int IndexOf(IOperation operation)
        {
            return list.IndexOf(operation);
        }

        /// <summary>
        /// Insert <see cref="IOperation"/> into the list to exact index.
        /// </summary>
        /// <param name="index">Index in list.</param>
        /// <param name="oper"><see cref="IOperation"/></param>
        public void Insert(int index, IOperation oper)
        {
            list.Insert(index, oper);
        }

        /// <summary>
        /// Remove <see cref="IOperation"/> from the list.
        /// </summary>
        /// <param name="oper"><see cref="IOperation"/></param>
        public void Remove(IOperation oper)
        {
            list.Remove(oper);
        }

        /// <summary>
        /// Remove all <see cref="IOperation"/> from the list.
        /// </summary>
        public void RemoveAll()
        {
            list.Clear();
        }

        /// <summary>
        /// Compute count of items in the list.
        /// </summary>
        /// <returns>Count of Items.</returns>
        public int Counter()
        {
            int count = list.Count();
            return count;
        }

        /// <summary>
        /// Performs all operaction in the sequence.
        /// </summary>
        /// <param name="bmp">Input Bitmap.</param>
        /// <returns>Output Bitmap.</returns>
        public override Bitmap Do(Bitmap bmp)
        {
            foreach (IOperation oper in list)
            {
                bmp = oper.Do(bmp);
            }

            return bmp;
        }

        /// <summary>
        /// Returns <see cref="IOperation"/> from the list on exact index.
        /// </summary>
        /// <param name="index">Index in the list.</param>
        /// <returns><see cref="IOperation"/></returns>
        public IOperation GetOperation(int index)
        {
            return list[index];
        }
        
        /// <summary>
        /// Load all childnodes from XML file to the list.
        /// </summary>
        /// <param name="node">Input node.</param>
        public override void FromXml(XmlNode node)
        {
            XmlNodeList nodes = node.ChildNodes;

            list.Clear();

            OperationFactory factory = OperationFactory.GetDefaultFactory();

            foreach (XmlNode inode in nodes)
            {
                IOperation operation = factory.CreateOperation(inode.Name);

                if (operation != null)
                {
                    operation.FromXml(inode);
                    list.Add(operation);
                }
            }
        }

        /// <summary>
        /// Save all childnodes from the list to XML file.
        /// </summary>
        /// <param name="xmlDoc">Input XML Document.</param>
        /// <returns>Output node.</returns>
        public override XmlNode ToXml(XmlDocument xmlDoc)
        {
            XmlElement operations = xmlDoc.CreateElement("operations");

            foreach (IOperation oper in list)
            {
                operations.AppendChild(oper.ToXml(xmlDoc));
            }

            return operations;
        }

        /// <summary>
        /// Returns formatted name of Sequence.
        /// </summary>
        /// <returns>Formatted name</returns>
        public override string GetFormattedName()
        {
            return "Sequence";
        }

        /// <summary>
        /// Returns blank string for Sequence.
        /// </summary>
        /// <returns>Blank info string.</returns>
        public override string GetInfo()
        {
            return "";
        }

        /// <summary>
        /// Returns enumerated list.
        /// </summary>
        /// <returns></returns>
        public IEnumerator<IOperation> GetEnumerator()
        {
            return list.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return list.GetEnumerator();
        }
    }
}
