#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.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Xsl;
using dataMagus.Common;
using dataMagus.Common.Physical;
using dataMagus.Common.Physical.Relational;
using dataMagus.Common.PlugIn.Generator;
#endregion

namespace dataMagus.PlugIns.Generators.SqlServer2000
{
	/// <summary>
	/// Implementation of the SQLServer2000 code generator.
	/// </summary>
    public class SqlServer2000Generator : IRelationalGenerator
    {
        #region Members
        /// <summary>
        /// Name of the generator.
        /// </summary>
        private string _name = "Sql Server 2000";
        
        /// <summary>
        /// Clone of the schema to be generated.
        /// </summary>
        private PhysicalRelationalSchema _schema;
        #endregion

        #region Properties
        /// <summary>
        /// Extended data from the generator.
        /// </summary>
        public IExtendedData ExtendedData
        {
            get { return GeneratorData.Instance; }
        }

        /// <summary>
        /// Clone of the schema to be generated.
        /// </summary>
        public ISchema Schema
        {
            set
            {
                if (value is PhysicalRelationalSchema)
                {
                    this._schema = (PhysicalRelationalSchema)value;
                }
                else
                {
                    throw new Exception("Schema must be type of PhysicalRelationalSchema");
                }
            }
        }

        /// <summary>
        /// Name of the generator.
        /// </summary>
        public string Name
        {
            get { return this._name; }
        }
        #endregion

        #region Methodes
        /// <summary>
        /// Update a datatype on the schema.
        /// </summary>
        /// <param name="newDatatype">New datatype.</param>
        /// <param name="oldDatatype">Old datatype.</param>
        /// <param name="action">Action happend.</param>
        public void UpdateDataType(DataType newDatatype, DataType oldDatatype, PhysicalItemContainer.DataTypeAction action)
        {
            GeneratorData.Instance.UpdateDataType(newDatatype, oldDatatype, action);
        }
        
        /// <summary>
        /// Get the generator control for the extended table data.
        /// </summary>
        /// <param name="element">Element to store the extended data for.</param>
        /// <returns>Always null.</returns>
        public GeneratorControl GetExtendedTableDataControl(PhysicalRelationalTable element)
        {
            return null;
        }

        /// <summary>
        /// Get the generator control for the extended column data.
        /// </summary>
        /// <param name="element">Element to store the extended data for.</param>
        /// <returns>Instance of a generator control.</returns>
        public GeneratorControl GetExtendedColumnDataControl(PhysicalRelationalColumn element)
        {
            return new ExtendedColumnControl(element);
        }

        /// <summary>
        /// Get the generator control for the extended relationship data.
        /// </summary>
        /// <param name="element">Element to store the extended data for.</param>
        /// <returns>Instance of a generator control.</returns>
        public GeneratorControl GetExtendedRelationshipDataControl(PhysicalRelationalRelationship element)
        {
            return new ExtendedRelationshipControl(element);
        }

        /// <summary>
        /// Get the generator control for the extended index data.
        /// </summary>
        /// <param name="element">Element to store the extended data for.</param>
        /// <returns>Always null.</returns>
        public GeneratorControl GetExtendedIndexDataControl(PhysicalRelationalIndex element)
        {
            return null;
        }

        /// <summary>
        /// Get the generator control for the datatype mapping.
        /// </summary>
        /// <returns>Instance of a generator control.</returns>
        public GeneratorControl GetGeneratorDataTypeMappingsControl()
        {
            return new DataTypeMappingControl();
        }

        /// <summary>
        /// Generate source code into a stream.
        /// </summary>
        /// <param name="stream">Stream to generate in.</param>
        public void Generate(Stream stream)
        {
            // Check schema
            if (null == this._schema)
            {
                throw new Exception("Schema must not be null.");
            }

            // Clean extended data if necessary
            this.CleanExtendedData(this._schema);

            Stream xsltStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("dataMagus.PlugIns.Generators.SqlServer2000.SqlServer2000.xslt");
            XmlReader xsltXmlReader = XmlReader.Create(xsltStream);
            XsltSettings xslSettings = new XsltSettings();
            XsltSettings xsltSettings = new XsltSettings(true, true);
            XslCompiledTransform xslTransform = new XslCompiledTransform();
            xslTransform.Load(xsltXmlReader, xslSettings, null);

            using (MemoryStream ms = new MemoryStream())
            {
                using (XmlWriter writer = new XmlTextWriter(ms, Encoding.UTF8))
                {
                    writer.WriteStartElement("SqlServer2000Generator");
                    this.ExtendedData.WriteXml(writer);
                    this._schema.WriteXml(writer);
                    writer.WriteEndElement();

                    // Important: writer must be flushed, memory stream must be reset to the begin
                    // and must be flushed
                    writer.Flush();
                    ms.Seek(0, SeekOrigin.Begin);
                    ms.Flush();

                    XmlDocument doc = new XmlDocument();
                    doc.Load(ms);
                    xslTransform.Transform(doc, null, stream);
                }
            }
        }

        /// <summary>
        /// Clean all extended generator data.
        /// </summary>
        /// <param name="schema">Schema to clean the data for.</param>
        public void CleanExtendedData(IPhysicalSchema schema)
		{
            if (schema is PhysicalRelationalSchema)
            {
                GeneratorData.Instance.CleanExtendedData((PhysicalRelationalSchema)schema);
            }
		}

        /// <summary>
        /// Get the generator control for the options tab on the generator dialog.
        /// </summary>
        /// <returns>Instance of a generator control.</returns>
		public GeneratorControl GetGeneratorOptionDataControl()
        {
            return new OptionsControl();
        }

        /// <summary>
        /// Get the generator control for the extended schema data.
        /// </summary>
        /// <param name="schema">Schema to store the extended data for.</param>
        /// <returns>Always null.</returns>
        public GeneratorControl GetExtendedSchemaDataControl(IPhysicalSchema schema)
        {
            return null;
        }
        #endregion
    }
}
