#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.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Xml.Serialization;
using dataMagus.Common.Logical;
using dataMagus.Common.Physical;
#endregion

[assembly:InternalsVisibleTo("dataMagus.Data")]
[assembly:InternalsVisibleTo("dataMagus.Forms")]
namespace dataMagus.Common
{
	/// <summary>
	/// This singelton class containing all needed data in the application. It's
	/// the central storage to be serialized for a persistance storage.
	/// </summary>
	internal sealed class DataContainer : IXmlSerializable
	{
		#region Members
		/// <summary>
		/// Singelton instance object.
		/// </summary>
		private static DataContainer _instance = null;
		
        /// <summary>
        /// Lock object for thread safe access.
        /// </summary>
        private static readonly object _padlock = new object();
        
        /// <summary>
        /// Instance of the logical schema.
        /// </summary>
        private LogicalSchema _logicalSchema = new LogicalSchema();
        
        /// <summary>
        /// Holding all physical data items.
        /// </summary>
        private PhysicalItemContainer _phyicalItemContainer = new PhysicalItemContainer();
		#endregion
		
		#region Constructors / Destructors
		/// <summary>
		/// Default constructor.
		/// </summary>
		private DataContainer()
		{
		}
		#endregion
		
		#region Properties
		/// <summary>
		/// Singelton instance object.
		/// </summary>
		public static DataContainer Instance 
		{
			get
			{
				if (null == DataContainer._instance)
				{
					lock (DataContainer._padlock)
					{
						if (null == DataContainer._instance)
						{
							DataContainer._instance = new DataContainer();
						}
					}
				}
				return DataContainer._instance;
			}			
		}
		
        /// <summary>
        /// Holding all physical data items.
        /// </summary>
		public PhysicalItemContainer PhysicalData
		{
            get { return this._phyicalItemContainer; }
		}
		
        /// <summary>
        /// Instance of the logical schema.
        /// </summary>
		public LogicalSchema LogicalSchema
		{
            get { return this._logicalSchema; }
		}
		#endregion
		
		#region Methodes
		/// <summary>
		/// Exchanges a logical schema and physical data container. This is used 
		/// when a complete schema gets loaded.
		/// </summary>
		/// <param name="schema">Logical schema to exchange.</param>
		/// <param name="physicalData">Physical data to exchange.</param>
        internal void Exchange(LogicalSchema schema, PhysicalItemContainer physicalData)
        {
        	if (this._logicalSchema == schema)
        	{
        		// schema is the same... just send rebuild
				this._logicalSchema.FireSchemaChangedEvent(this, SchemaChangedAction.RebuildedSchema);
        	}
        	else
        	{
        		// exchange the complete schema (remember the old one, exchange, fire event on the old one)
        		ISchema oldSchema = this._logicalSchema;
	            this._logicalSchema = schema;
        		oldSchema.FireSchemaChangedEvent(this, new SchemaEventArgs(schema, SchemaChangedAction.ExchangeSchema));
        	}
            this._phyicalItemContainer = physicalData;
        }
		#endregion

        #region IXmlSerializable Members
        /// <summary>
        /// Gets the xml schema object.
        /// </summary>
        /// <returns>Always null.</returns>
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        /// <summary>
        /// Reads back an instance of this class from a reader.
        /// </summary>
        /// <param name="reader">Reader object to read from.</param>
        public void ReadXml(System.Xml.XmlReader reader)
        {
            while (!reader.EOF)
            {
                reader.Read();
                if (reader.NodeType == System.Xml.XmlNodeType.EndElement && reader.Name == "DataContainer")
                {
                    break;
                }
                if (reader.IsStartElement("LogicalSchema"))
                {
                    this._logicalSchema.ReadXml(reader);
                }
                if (reader.IsStartElement("PhysicalData"))
                {
                    this._phyicalItemContainer.ReadXml(reader);
                }
            }
        }

        /// <summary>
        /// Writes a the instace of this class to a writer.
        /// </summary>
        /// <param name="writer">Writer object to write into.</param>
        public void WriteXml(System.Xml.XmlWriter writer)
        {
            this.LogicalSchema.WriteXml(writer);
            this.PhysicalData.WriteXml(writer);
        }
        #endregion
    }
}
