#region Copyright and GPL
/*************************************************************************
 * dataMagus - The open source database learning software
 * Copyright (C) 2007 by all authors
 * Authors: Monika Schwitter (monsy@gmx.ch)
 *          Jürg Zgraggen (j.zgraggen@ejaz.net)
 *          HSLU (Hochschule Luzern - Technik+Architektur)
 * 
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 * 
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *************************************************************************/
#endregion
#region Using
using System;
using System.ComponentModel;
using dataMagus.Common.Logical;
using System.Collections.Generic;
using System.Collections;
#endregion

namespace dataMagus.Common.Physical.Relational
{
	/// <summary>
	/// This class represents a physical relational index.
	/// </summary>
    [Serializable]
	public class PhysicalRelationalIndex : PhysicalElement
	{
		#region Enumerations
		/// <summary>
		/// Different types of indexes.
		/// </summary>
        public enum IndexType
        {
        	/// <summary>
        	/// Unique
        	/// </summary>
            Unique,
            
            /// <summary>
            /// Standard
            /// </summary>
            Standard
        }
		#endregion
		
		#region Members
		/// <summary>
		/// Indicator if the index has been generated automatically.
		/// </summary>
        private bool _generated = false;
        
        /// <summary>
        /// Type of the index.
        /// </summary>
        private IndexType _type = IndexType.Unique;
        
        /// <summary>
        /// Holds all columns which belong to the index constraint.
        /// </summary>
        private List<PhysicalRelationalColumn> _columns = new List<PhysicalRelationalColumn>();
		#endregion
		
		#region Constructors / Destructors
		/// <summary>
		/// Constructor.
		/// </summary>
        /// <param name="schema">Physical relational schema.</param>
        /// <param name="id">Unique id of the object.</param>
        /// <param name="origin">Origin element the index is based on.</param>
        /// <param name="name">Name of the index.</param>
		/// <param name="type">Type of the index.</param>
        public PhysicalRelationalIndex(PhysicalRelationalSchema schema,
            string id, IElement origin, string name, IndexType type)
            : base(schema, id, origin, name)
        {
            this._type = type;
        }

		/// <summary>
		/// Constructor.
		/// </summary>
        /// <param name="schema">Physical relational schema.</param>
        /// <param name="id">Unique id of the object.</param>
        /// <param name="origin">Origin element the index is based on.</param>
        /// <param name="name">Name of the index.</param>
		/// <param name="type">Type of the index.</param>
		/// <param name="generated">Indicator if the index has been generated automatically.</param>
        public PhysicalRelationalIndex(PhysicalRelationalSchema schema,
            string id, IElement origin, string name, IndexType type, bool generated)
            : base(schema, id, origin, name)
        {
            this._generated = generated;
            this._type = type;
        }
		#endregion
		
		#region Properties
        /// <summary>
        /// Type of the index.
        /// </summary>
        public IndexType Type
        {
            get { return this._type; }
        }

        /// <summary>
        /// Count all columns inside the index.
        /// </summary>
		[Browsable(false)]
        public int CountColumns
        {
            get { return this._columns.Count; }
        }

		/// <summary>
		/// Indicator if the index has been generated automatically.
		/// </summary>
        public int Generated
        {
            get { return this._columns.Count; }
        }
		#endregion
		
		#region Events
		/// <summary>
		/// Begin initialization mode.
		/// </summary>
		/// <remarks>Prevents event handling.</remarks>
        public override void BeginInit()
        {
            base.BeginInit();
            foreach (PhysicalRelationalColumn column in this._columns)
            {
                column.BeginInit();
            }
        }

        /// <summary>
		/// End initialization mode.
		/// </summary>
		/// <remarks>Event handling will continue.</remarks>
		/// <param name="forceEvent">Indicates if an Undefined event has to be fired to inform other listeners.</param>
        public override void EndInit(bool forceEvent)
        {
            foreach (PhysicalRelationalColumn column in this._columns)
            {
                column.EndInit(forceEvent);
            }
            base.EndInit(forceEvent);
        }

        /// <summary>
        /// Add a new column to the index.
        /// </summary>
        /// <param name="column">Column to add.</param>
        public void AddColumn(PhysicalRelationalColumn column)
        {
            if (!this._columns.Contains(column))
            {
                if (this.InitMode)
                {
                    column.BeginInit();
                }
                this._columns.Add(column);
                this.FireElementChangedEvent(this, new ElementEventArgs(this, ElementChangedAction.AddedElement, column));
            }
        }

        /// <summary>
        /// Remove a column from the index.
        /// </summary>
        /// <param name="column">Column to remove.</param>
        public void RemoveColumn(PhysicalRelationalColumn column)
        {
            this._columns.Remove(column);
            this.FireElementChangedEvent(this, new ElementEventArgs(this, ElementChangedAction.RemovedElement, column));
        }

        /// <summary>
        /// Checks if a column has already been added.
        /// </summary>
        /// <param name="column">Column to check.</param>
        /// <returns>true if the column is contained, else false.</returns>
        public bool ContainsColumn(PhysicalRelationalColumn column)
        {
            return this._columns.Contains(column);
        }

        /// <summary>
        /// Get all columns.
        /// </summary>
        /// <returns>Enumerator to parse.</returns>
        public IEnumerator GetColumns()
        {
            return this._columns.GetEnumerator();
        }
    	#endregion
		
		#region Methodes
        /// <summary>
        /// Writes a the instace of this class to a writer.
        /// </summary>
        /// <param name="writer">Writer object to write into.</param>
        public override void WriteXml(System.Xml.XmlWriter writer)
        {
            // write first the element name
            writer.WriteStartElement("Index");
            writer.WriteAttributeString("type", this._type.ToString());

            // write base items
            base.WriteXml(writer);

            // write my items
            writer.WriteStartElement("Columns");
            foreach (PhysicalRelationalColumn column in this._columns)
            {
                column.WriteXml(writer);
            }
            writer.WriteEndElement();

            writer.WriteEndElement();
        }
		#endregion		
	}
}
