#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.IO;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.Runtime.CompilerServices;
using System.Xml.Serialization;
using System.Xml;
using dataMagus.Common;
using dataMagus.Common.Physical;
using dataMagus.Common.Logical;
#endregion

[assembly: InternalsVisibleTo("dataMagus")]
namespace dataMagus.Data
{
	/// <summary>
	/// This class serializes the data container.
	/// </summary>
    public class DataContainerSerializer
    {
    	/// <summary>
		/// This class holds and serializes the data for internal use.
    	/// </summary>
        public class DataContainerInternal : IXmlSerializable
        {
			#region Members
			/// <summary>
			/// Logical schema (containing all logical needed data).
			/// </summary>
            private LogicalSchema _logicalSchema = new LogicalSchema();
            
            /// <summary>
            /// Physical data extensions to restore the changed data.
            /// </summary>
            private PhysicalItemContainer _physicalData = new PhysicalItemContainer();
			#endregion
	
	        #region Constructors / Destructors
            /// <summary>
            /// Constructor
            /// </summary>
            /// <param name="schema">Logical schema to serialize.</param>
            /// <param name="physicalData">Physical data extensions to serialize.</param>
            public DataContainerInternal(LogicalSchema schema, PhysicalItemContainer physicalData)
            {
                this._logicalSchema = schema;
                this._physicalData = physicalData;
            }

            /// <summary>
            /// Default constructor.
            /// </summary>
            public DataContainerInternal()
            {
            }
	        #endregion

	        #region Properties
			/// <summary>
			/// Logical schema (containing all logical needed data).
			/// </summary>
            public LogicalSchema LogicalSchema
            {
                get { return this._logicalSchema; }
            }

            /// <summary>
            /// Physical data extensions to restore the changed data.
            /// </summary>
            public PhysicalItemContainer PhysicalData
            {
                get { return this._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(XmlReader reader)
            {
                while (!reader.EOF)
                {
                    reader.Read();
                    if (reader.NodeType == System.Xml.XmlNodeType.EndElement && reader.Name == "DataContainerInternal")
                    {
                        break;
                    }
                    if (reader.IsStartElement("LogicalSchema"))
                    {
                        this._logicalSchema.ReadXml(reader);
                    }
                    if (reader.IsStartElement("PhysicalData"))
                    {
                        this._physicalData.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(XmlWriter writer)
            {
                this._logicalSchema.WriteXml(writer);
                this._physicalData.WriteXml(writer);
            }
            #endregion
        }

		#region Methodes
		/// <summary>
		/// Save the given data container persitant into the defined file.
		/// </summary>
		/// <param name="dc">Data container to be saved.</param>
		/// <param name="path">File to save the data in.</param>
        internal void Save(DataContainer dc, string path)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(DataContainerInternal));
            using (FileStream file = new FileStream(path, FileMode.Create))
            {
                try
                {
                    DataContainerInternal dci = new DataContainerInternal(dc.LogicalSchema, dc.PhysicalData);
                    serializer.Serialize(file, dci);
                    file.Flush();
                }
                catch (Exception ex)
                {
                    throw new Exception(global::dataMagus.Data.OtherResources.ExceptionSchemaCorrupt, ex.InnerException);
                }
            }
        }

        /// <summary>
        /// Loads the data form a given file.
        /// </summary>
        /// <param name="path">File to load from.</param>
        internal void Load(string path)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(DataContainerInternal));
            using (Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
            {
                try
                {
                    DataContainerInternal container = (DataContainerInternal)serializer.Deserialize(stream);
                    DataContainer.Instance.Exchange(container.LogicalSchema, container.PhysicalData);
                }
                catch (Exception ex)
                {
                    throw new Exception(global::dataMagus.Data.OtherResources.ExceptionFileCorrupt, ex.InnerException);
                }
            }
        }
		#endregion        
    }
}
