using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;
using System.Threading;
using System.ComponentModel;

using CategoryTheory;
using DiagramUI;
using DataPerformer;
using DataSetService;
using DataTableSelection;
using DataPerformerUI;


namespace Astronomy.UI
{
    internal class AstronomyFactory : IUIFactory
    {
        protected ToolsDiagram tools;

        protected static DataWarehouse.DatabaseInterface data; 

        protected PanelDesktop desktop;


        protected IErrorHandler errorHandler = null;

        protected PaletteButton libraryButton;

        /// <summary>
        /// The start thread
        /// </summary>
        protected ThreadStart start;

        /// <summary>
        /// Number of start step
        /// </summary>
        protected int startStep;

        /// <summary>
        /// Pause in milliseconds
        /// </summary>
        protected int pause;

        /// <summary>
        /// Step of performance
        /// </summary>
        protected double step;

        /// <summary>
        /// Time of start
        /// </summary>
        protected double startTime;

        /// <summary>
        /// Count of steps
        /// </summary>
        protected int stepCount;

        /// <summary>
        /// Number of current step
        /// </summary>
        protected int currentStep;



        internal static DataWarehouse.DatabaseInterface Data
        {
            set
            {
                data = value;
            }
        }


        /// <summary>
        /// Error handler
        /// </summary>
        public IErrorHandler ErrorHandler
        {
            set
            {
                errorHandler = value;
            }
        }


        #region IUIFactory Members

        /// <summary>
        /// Object creation
        /// </summary>
        /// <param name="button">Corresponding button</param>
        /// <returns>The object</returns>
        ICategoryObject IUIFactory.CreateObject(PaletteButton button)
        {
            if (button.Kind == (int)ButtonKinds.Container)
            {
                return load(button.Type);
            }
            if (button.Kind == (int)ButtonKinds.MultiLibraryObject)
            {
                return new MultiLibraryObject();
            }
            // Creation of the series object
            if (button.Kind == (int)ButtonKinds.DrawSeries)
            {
                return new DataPerformerUI.DrawSeries();
            }
            // Creation of data selection object
            if (button.Kind == (int)ButtonKinds.DataSetSelection)
            {
                return new DataSetSelection();
            }
            if (button.Kind == (int)ButtonKinds.BitmapSelection)
            {
                return new ImageNavigation.BitmapSelection();
            }
            if (button.Kind == (int)ButtonKinds.AliasRegression)
            {
                return new Regression.AliasRegression();
            }
            if (button.Kind == (int)ButtonKinds.StatementWrapper)
            {
                return new StatementWrapper();
            }
            if (button.Kind == (int)ButtonKinds.VectorFormulaConsumer)
            {
                return new VectorFormulaConsumer();
            }
            else if (button.Kind == (int)ButtonKinds.DataSetIterator)
            {
                return new DataSetIterator();
            }
            else if (button.Kind == (int)ButtonKinds.IteratorGLM)
            {
                return new IteratorGLM();
            }
            if (button.Kind == (int)ButtonKinds.ObjectTransformer)
            {
                return new DataPerformer.ObjectTransformer();
            }
            else if (button.Kind == (int)ButtonKinds.DataConsumer)
            {
                return new DataConsumer((int)ButtonKinds.DataConsumer);
            }
            else if (button.Kind == (int)ButtonKinds.PositionCollectionData)
            {
                return new Motion6D.PositionCollectionData();
            }
            else if (button.Kind == (int)ButtonKinds.PositionCollectionIndicator)
            {
                return new Motion6D.PositionCollectionIndicator();
            }
            else if (button.Kind == (int)ButtonKinds.ReferenceFrameData)
            {
                return new Motion6D.ReferenceFrameData();
            }
            else if (button.Kind == (int)ButtonKinds.SeriesIterator)
            {
                return new DataPerformer.SeriesIterator();
            }
            else if (button.Kind == (int)ButtonKinds.FormulaFilterIterator)
            {
                return new DataPerformer.FormulaFilterIterator();
            }
            else if (button.Kind == (int)ButtonKinds.SeriesData)
            {
                return new DataTableSelection.DataTableSeries();
            }
            else if (button.Kind == (int)ButtonKinds.Series)
            {
                return new DataPerformer.Series();
            }
            else if (button.Kind == (int)ButtonKinds.RigidReferenceFrame)
            {
                return new Motion6D.RigidReferenceFrame();
            }
            else if (button.Kind == (int)ButtonKinds.RelativeMeasurements)
            {
                return new Motion6D.RelativeMeasurements();
            }
            else if (button.Kind == (int)ButtonKinds.Random)
            {
                return new RandomGenerator();
            }
            else if (button.Kind == (int)ButtonKinds.Recursive)
            {
                return new Recursive();
            }
            else if (button.Kind == (int)ButtonKinds.ODE)
            {
                return new DifferentialEquationSolver();
            }
            if (button.Kind == (int)ButtonKinds.DataPicture)
            {
                return new ImageTransformations.DataPicture();
            }
            if (button.Kind == (int)ButtonKinds.Camera3D)
            {
                return Motion6D.PositionObjectFactory.Factory.NewCamera();
            }
            if (button.Kind == (int)ButtonKinds.Visible3D)
            {
                Motion6D.SerializablePosition p = new Motion6D.SerializablePosition();
                object o = Motion6D.PositionObjectFactory.Factory.CreateObject(button.Type);
                p.Parameters = o;
                return p;
            }
            return null;
        }

        ICategoryArrow IUIFactory.CreateArrow(PaletteButton button)
        {
            if (button.Kind == (int)ButtonKinds.MeasureLink)
            {
                return new DataLink();
            }
            if (button.Kind == (int)ButtonKinds.DataSetArrow)
            {
                return new DataSetArrow();
            }
            if (button.Kind == (int)ButtonKinds.ObjectTransformerLink)
            {
                return new ObjectTransformerLink();
            }
            else if (button.Kind == (int)ButtonKinds.RelativeMeasurementsLink)
            {
                return new Motion6D.RelativeMeasurementsLink();
            }
            else if (button.Kind == (int)ButtonKinds.ReferenceFrameArrow)
            {
                return new Motion6D.ReferenceFrameArrow();
            }
            else if (button.Kind == (int)ButtonKinds.UnaryLink)
            {
                return new UnaryLink();
            }
            else if (button.Kind == (int)ButtonKinds.PositionIndicatorLink)
            {
                return new Motion6D.PositionIndicatorLink();
            }
            else if (button.Kind == (int)ButtonKinds.IteratorConsumerLink)
            {
                return new DataPerformer.IteratorConsumerLink();
            }
            if (button.Kind == (int)ButtonKinds.VisibleLink)
            {
                return new Motion6D.CameraLink();
            }
            if (button.Kind == (int)ButtonKinds.AliasRegressionLink)
            {
                return new Regression.SelectionLink();
            }
            if (button.Kind == (int)ButtonKinds.BitmapNavigationLink)
            {
                return new ImageNavigation.BitmapMeasurementsLink();
            }
            return null;
        }

        /// <summary>
        /// Creates property editor from desktop component
        /// </summary>
        /// <param name="comp">The component</param>
        /// <returns>The property editor</returns>
        System.Windows.Forms.Form IUIFactory.CreateForm(INamedComponent comp)
        {
            // Checks whether component is an arrow
            if (comp is IArrowLabel)
            {
                IArrowLabel lab = comp as IArrowLabel;
                ICategoryArrow arrow = lab.Arrow;
            }
            // The component is an object
            if (comp is IObjectLabel)
            {
                IObjectLabel lab = comp as IObjectLabel;
                // The object of component
                ICategoryObject obj = lab.Object;
                Form form = ToolsDiagram.CreateEditorForm(obj);
                if (form != null)
                {
                    return form;
                }

                // Creation of iterator property editor
                if (obj is IteratorGLM)
                {
                    return new FormIterateGLM(lab);
                }
                // Creation of VectorFormulaConsumer property editor
                if (obj is VectorFormulaConsumer)
                {
                    return new FormVectorConsumer(lab);
                }
                if (obj is StatementWrapper)
                {
                    return new DataPerformerUI.FormStatementSelection(lab);
                }
                if (obj is DataPerformer.ObjectTransformer)
                {
                    return new FormObjectTransformer(lab);
                }
                if (obj is ImageNavigation.BitmapSelection)
                {
                    return new ImageNavigation.FormBitmapSelection(lab);
                }
                if (obj is DataPerformer.SeriesIterator)
                {
                    return new FormSeriesIterator(lab);
                }
                if (obj is DataPerformerUI.DrawSeries)
                {
                    return new DataPerformerUI.FormPointCollection(lab);
                }
                if (obj is DataTableSelection.DataTableSeries)
                {
                    return new FormSeriesTable(lab);
                }
                if (obj is DataPerformer.Series)
                {
                    return new FormSeries(lab);
                }
                if (obj is DataConsumer)
                {
                	DataConsumer consumer = obj as DataConsumer;
					if (consumer.ConsumerType == (int)ButtonKinds.DataConsumer)
					{
						return new FormGraph(consumer, lab);
					}
				}
                if (obj is Motion6D.Camera)
                {
                    Motion6D.Camera c = obj as Motion6D.Camera;
                    return Motion6D.PositionObjectFactory.Factory.CreateForm(c) as Form;
                }
                if (obj is Motion6D.PositionCollectionIndicator)
                {
                    return new MotionUI.FormPositionsIndicatror(lab);
                }
                if (obj is Motion6D.PositionCollectionData)
                {
                    return new MotionUI.FormPointsCollection(lab);
                }
                if (obj is Motion6D.ReferenceFrameData)
                {
                    return new MotionUI.FormFrameData(lab);
                }
                if (obj is FormulaFilterIterator)
                {
                    return new DataPerformerUI.FormIteratorFilter(lab);
                }
                if (obj is DifferentialEquationSolver)
                {
                    return new DataPerformerUI.FormDiffEquation(lab);
                }
                if (obj is Recursive)
                {
                    return new DataPerformerUI.FormRecursive(lab);
                }
                if (obj is ImageTransformations.DataPicture)
                {
                    return new ImageTransformations.FormDataPicture(lab);
                }
                if (obj is Motion6D.SerializablePosition)
                {
                    Motion6D.IPosition p = obj as Motion6D.IPosition;
                    object o = p.Parameters;
                    if (o != null & Motion6D.PositionObjectFactory.Factory != null)
                    {
                        if (o is Motion6D.IVisible)
                        {
                            Motion6D.IVisible v = o as Motion6D.IVisible;
                            object ob = Motion6D.PositionObjectFactory.Factory.CreateForm(p, v);
                            if (ob != null)
                            {
                                if (ob is Form)
                                {
                                    Form f = ob as Form;
                                    return f;
                                }
                            }
                        }
                    }
                }
                if (obj is Motion6D.RigidReferenceFrame)
                {
                    return new MotionUI.FormRigidFrame(lab);
                }
                if (obj is Regression.AliasRegression)
                {
                    return new DataPerformerUI.FormAliasRegression(lab);
                }
            }
            return new DefaultForm(comp);
        }

        void IUIFactory.ShowError(Exception e)
        {
            if (errorHandler != null)
            {
                errorHandler.ShowError(e);
            }
        }

        ArrowLabel IUIFactory.CreateArrowLabel(PaletteButton button, ICategoryArrow arrow, IObjectLabel source, IObjectLabel target)
        {
            return new ArrowLabel(button, arrow, source, target);
        }

        ObjectLabel IUIFactory.CreateObjectLabel(PaletteButton button)
        {
            if (button.Kind == (int)ButtonKinds.Container)
            {
                return new ContainerObjectLabel(button);
            }
            return new ObjectLabel(button);
        }

        PaletteButton IUIFactory.GetObjectButton(ICategory category)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        PaletteButton IUIFactory.GetArrowButton(ICategory category)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        ToolsDiagram IUIFactory.Tools
        {
            set { tools = value; }
        }

        PaletteButton IUIFactory.GetObjectButton(ICategoryObject obj)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        PaletteButton IUIFactory.GetArrowButton(ICategoryArrow arrow)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        void IUIFactory.CheckOrder(PanelDesktop desktop)
        {
            foreach (Control c in desktop.Controls)
            {
                if (!(c is ArrowLabel))
                {
                    continue;
                }
                ArrowLabel l = c as ArrowLabel;
                ICategoryArrow a = l.Arrow;
                if (!(a is DataLink))
                {
                    continue;
                }
                if (l.Source.Root.Ord < l.Target.Root.Ord)
                {
                    PureDesktop.ThrowException(a, new Exception(DataLink.SetProviderBefore));
                }
            }
        }

        ObjectLabel IUIFactory.CreateLabel(ICategoryObject obj)
        {
            return new ObjectLabel(libraryButton);
        }

        ArrowLabel IUIFactory.CreateLabel(ICategoryArrow arr)
        {
            return null;
        }



        #endregion


        #region Specific Members

        internal PanelDesktop Desktop
        {
            get
            {
                return desktop;
            }
            set
            {
                desktop = value;
            }
        }

        internal void Start(double startTime, int startStep, int pause, double step, int stepCount, PanelDesktop desktop)
        {
            this.startTime = startTime;
            this.startStep = startStep;
            this.pause = pause;
            this.step = step;
            this.stepCount = stepCount;
            this.desktop = desktop;
            startWorker();
        }

        private void work(object sender, DoWorkEventArgs e)
        {
            run();
        }

        public void startWorker()
        {
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += work;
            worker.RunWorkerAsync();
        }


        void run()
        {
            try
            {
                DataPerformerStrategy.Object.PrepareAll(desktop);
                //prepareCameras();
                currentStep = startStep;
                DataPerformerStrategy.Object.StartAll(desktop);
                DataPerformerStrategy.Object.Time = startTime + currentStep * step;
                /*if (progressIndicator != null)
                {
                    progressIndicator.Init(stepCount);
                }*/
                //ArrayList lc = DataConsumer.GetDataConsumers(desktop);
                //			DifferentialEquationProcessor processor = DifferentialEquationProcessor.Object;
                //processor.Set(lc);
                for (int i = 1; i < stepCount; i++)
                {
                    currentStep = startStep + i;
                    //					UpdateFrames();
                    //					UpdateObjects();
                    Redraw();
                    Thread.Sleep(pause);
                    //processor.Step(startTime + currentStep * step - step, startTime + currentStep * step);
                    DataPerformerStrategy.Object.Time = startTime + currentStep * step;
                }
            }
            catch (Exception e)
            {
                //Form f = progressIndicator as Form;
                DefaultForm.ShowError(null, e);
            }

        }

        internal void Redraw()
        {
            foreach (Control c in desktop.Controls)
            {
                if (!(c is ObjectLabel))
                {
                    continue;
                }
                ObjectLabel label = c as ObjectLabel;
                Form f = label.LabelForm;

                if (f == null)
                {
                    continue;
                }
                if (f.IsDisposed)
                {
                    continue;
                }
                if (!(f is IRedraw))
                {
                    continue;
                }
                IRedraw r = f as IRedraw;
                r.Redraw();
            }
        }

        internal PaletteButton LibraryButton
        {
            set
            {
                libraryButton = value;
            }
        }

        ObjectContainer loadContainer(Stream stream)
        {
            BinaryFormatter binary = new BinaryFormatter();
            ObjectContainer ob = binary.Deserialize(stream) as ObjectContainer;
            stream.Close();
            return ob;
        }

        MultiLibraryObject loadMultilibrary(Stream stream)
        {
            BinaryFormatter binary = new BinaryFormatter();
            SerializationBinder[] binders = null;
            PureDesktopPeer d = new PureDesktopPeer();
            d.Load(stream, binders);
            stream.Close();
            PureObjectLabel.Wrappers = true;
            IObjectLabel l = d.Objects[0] as IObjectLabel;
            ICategoryObject ob = l.Object;
            PureObjectLabel.Wrappers = false;
            return ob as MultiLibraryObject;
       }

        ICategoryObject load(string str)
        {
            Stream stream = null;
            bool cont = true;
            string fn = ResourceService.Resources.CurrentDirectory + "Containers\\" + str;
            if (File.Exists(fn))
            {
                stream = File.OpenRead(fn);
                int n = fn.LastIndexOf('.');
                if (fn.Substring(n + 1).ToLower().Equals("cfa"))
                {
                    cont = false;
                }
            }
            else
            {
                string ext = null;
                byte[] buffer = data.GetData(str, ref ext);
                ext = ext.Trim();
                if (!ext.ToLower().Equals("cont"))
                {
                    cont = false;
                }
                stream = new MemoryStream(buffer);
            }
            if (cont)
            {
                return loadContainer(stream);
            }
            return loadMultilibrary(stream);
        }

        #endregion
    }
}
