Inheritance: IDisposable
        private Controller()
        {
            itemTextBuilder    = new ItemTextBuilder();
            TrackingController = new TrackingController();
            SelectionCommand   = Canguro.Commands.View.Selection.Instance;
            commands.Add("select", SelectionCommand);
            loadCommands();

            services     = null;
            modelCmd     = null;
            lastViewCmd  = null;
            viewCmd      = SelectionCommand;
            executeQueue = new Queue <string>();
            Idle        += new EventHandler(flushExecuteQueue);
        }
        private Controller()
        {
            itemTextBuilder = new ItemTextBuilder();
            TrackingController = new TrackingController();
            SelectionCommand = Canguro.Commands.View.Selection.Instance;
            commands.Add("select", SelectionCommand);
            loadCommands();

            services = null;
            modelCmd = null;
            lastViewCmd = null;
            viewCmd = SelectionCommand;
            executeQueue = new Queue<string>();
            Idle += new EventHandler(flushExecuteQueue);
        }
        /// <summary>
        /// Method called when a model command ends or is cancelled
        /// </summary>
        private void endModelCommand()
        {
            if (modelCmd != null)
            {
                modelCmd.Cancel = true;
            }

            mainFrm.ReportProgress("", 0, "", 0, DateTime.Now.AddMilliseconds(1));

            if (!mainFrm.SmallPanel.IsDisposed && !mainFrm.SmallPanel.Disposing)
            {
                mainFrm.SmallPanel.Stop();
            }

            mainFrm.HideCommandToolbox();

            Model.Model.Instance.Undo.Commit();

            modelCmd = null;
            if (services != null)
            {
                services.Dispose();
                services = null;
            }
            TrackingController.TrackingService = null;
            TrackingController.ResetStatus(Canguro.View.GraphicViewManager.Instance.ActiveView);
            TrackingController.SnapController.IsActive     = false;
            TrackingController.SnapController.PrimaryPoint = Snap.PointMagnet.ZeroMagnet;

            // Reset selection
            SelectionCommand.Start(null);
            viewCmd = SelectionCommand;
            mainFrm.ScenePanel.Cursor = viewCmd.Cursor;

            if (EndModelCommand != null)
            {
                EndModelCommand(this, EventArgs.Empty);
            }
        }
        /// <summary>
        /// Este método es llamado como resultado de una acción del usuario, no de algún otro comando.
        /// Por esto sus mensajes de error se mandan al usuario como avisos y se resuelven aquí mismo
        /// en lugar de aventar excepciones.
        /// </summary>
        /// <param name="command">El nombre del comando a ejecutar</param>
        /// <returns>True if the command executed successfully. False otherwise.</returns>
        public bool Execute(string command)
        {
            // Clean command
            command = command.Trim().ToLowerInvariant();

            // Check cancel first
            if (command.Equals("cancel"))
            {
                // Cancel View Command, Model Command and Selection if applicable
                // (in that order, only one action per cancel)
                if ((viewCmd != SelectionCommand || Canguro.View.GraphicViewManager.Instance.ActiveView.ModelRenderer.RenderOptions.ShowAnimated) && EndViewCommand != null)
                {
                    EndViewCommand(this, new EndViewCommandArgs(viewCmd));
                }
                else
                {
                    if (modelCmd != null)
                    {
                        if (!modelCmd.AllowCancel())
                        {
                            return(false);
                        }

                        endModelCommand();
                    }
                    else
                    {
                        // If there was no ModelCommand, clear and reset selection
                        Canguro.Model.Model.Instance.UnSelectAll();
                        SelectionCommand.Reset();
                    }
                }

                IdleReset();

                viewCmd = SelectionCommand;
                if (StartViewCommand != null)
                {
                    StartViewCommand(this, EventArgs.Empty);
                }
                mainFrm.ScenePanel.Cursor = SelectionCommand.DefaultCursor;

                return(true);
            }

            // Check if command exists
            if (!commands.ContainsKey(command))
            {
                System.Windows.Forms.MessageBox.Show(Culture.Get("CommandNotFound") + ": '" + command + "'", Culture.Get("ActionNotPossibleTitle"), System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                return(false);
            }

            // Execute Command
            // Prioritize View Commands
            Command cmd = commands[command];

            if (cmd is ViewCommand)
            {
                // If a series of viewCommands has ended (entered SelectionCommand)
                // then send the EndViewCommand signal
                // If Selection was doing anything and the viewCmd changes to zoom, pan, rotate, etc.
                // (exits selection mode), reset SelectionCommand
                if ((cmd == SelectionCommand) && (viewCmd != SelectionCommand) && (EndViewCommand != null))
                {
                    EndViewCommand(this, new EndViewCommandArgs(viewCmd));
                }
                else if ((cmd != SelectionCommand) && (viewCmd == SelectionCommand))
                {
                    // Tal vez en lugar de un Reset sea mejor un Cancel, para no perder el tracking
                    SelectionCommand.Reset();
                }

                // Instantiate and run new ViewCommand
                ViewCommand lastViewCmd = viewCmd;
                viewCmd = (ViewCommand)cmd;
                if (StartViewCommand != null)
                {
                    StartViewCommand(this, EventArgs.Empty);
                }

                if (viewCmd.SavePrevious)
                {
                    GraphicViewManager.Instance.SavePreviousActiveView();
                    //System.Console.WriteLine("SavePrevious");
                }

                if (viewCmd.IsInteractive)
                {
                    mainFrm.ScenePanel.Cursor = viewCmd.Cursor;
                }
                else
                {
                    viewCmd.Run(GraphicViewManager.Instance.ActiveView);
                    GraphicViewManager.Instance.updateView(false);
                    if (EndViewCommand != null)
                    {
                        EndViewCommand(this, new EndViewCommandArgs(viewCmd));
                    }

                    if (lastViewCmd == SelectionCommand)
                    {
                        viewCmd = SelectionCommand;
                    }
                    else
                    {
                        //if (lastViewCmd.SavePrevious && viewCmd != Commands.View.ZoomPrevious.Instance)
                        //{
                        //    GraphicViewManager.Instance.SavePreviousActiveView();
                        //    System.Console.WriteLine("SavePrevious");
                        //}

                        //viewCmd = lastViewCmd;

                        Execute("select");
                    }

                    if (StartViewCommand != null)
                    {
                        StartViewCommand(this, EventArgs.Empty);
                    }
                }
            }
            else if (cmd is ModelCommand)
            {
                if (modelCmd == null)
                {
                    // Por el momento funcionan en el mismo hilo, por lo que al terminar la
                    // llamada a Run se puede asignar modelCmd = null y services = null
                    modelCmd        = (ModelCommand)cmd;
                    modelCmd.Cancel = false;
                    try
                    {
                        if (StartModelCommand != null)
                        {
                            StartModelCommand(this, EventArgs.Empty);
                        }
                        modelCmd.Run(services = new CommandServices(this));
                    }
                    catch (CancelCommandException) { Model.Model.Instance.Undo.Rollback(); }
                    catch (Exception ex) { System.Diagnostics.Debug.WriteLine("Controller.Execute: {0}", ex.Message); }
                    finally
                    {
                        endModelCommand();
                    }
                }
                else
                {
                    System.Windows.Forms.MessageBox.Show(Culture.Get("ModelCmdAlreadyExecuting"), Culture.Get("ActionNotPossibleTitle"), System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                    return(false);
                }
            }

            return(true);
        }
        /// <summary>
        /// Method called when a model command ends or is cancelled
        /// </summary>
        private void endModelCommand()
        {
            if (modelCmd != null)
                modelCmd.Cancel = true;

            mainFrm.ReportProgress("", 0, "", 0, DateTime.Now.AddMilliseconds(1));

            if (!mainFrm.SmallPanel.IsDisposed && !mainFrm.SmallPanel.Disposing)
                mainFrm.SmallPanel.Stop();

            mainFrm.HideCommandToolbox();

            Model.Model.Instance.Undo.Commit();

            modelCmd = null;
            if (services != null)
            {
                services.Dispose();
                services = null;
            }
            TrackingController.TrackingService = null;
            TrackingController.ResetStatus(Canguro.View.GraphicViewManager.Instance.ActiveView);
            TrackingController.SnapController.IsActive = false;
            TrackingController.SnapController.PrimaryPoint = Snap.PointMagnet.ZeroMagnet;

            // Reset selection
            SelectionCommand.Start(null);
            viewCmd = SelectionCommand;
            mainFrm.ScenePanel.Cursor = viewCmd.Cursor;

            if (EndModelCommand != null)
                EndModelCommand(this, EventArgs.Empty);
        }
        /// <summary>
        /// Este método es llamado como resultado de una acción del usuario, no de algún otro comando.
        /// Por esto sus mensajes de error se mandan al usuario como avisos y se resuelven aquí mismo
        /// en lugar de aventar excepciones.
        /// </summary>
        /// <param name="command">El nombre del comando a ejecutar</param>
        /// <returns>True if the command executed successfully. False otherwise.</returns>
        public bool Execute(string command)
        {
            // Clean command
            command = command.Trim().ToLowerInvariant();

            // Check cancel first
            if (command.Equals("cancel"))
            {
                // Cancel View Command, Model Command and Selection if applicable
                // (in that order, only one action per cancel)
                if ((viewCmd != SelectionCommand || Canguro.View.GraphicViewManager.Instance.ActiveView.ModelRenderer.RenderOptions.ShowAnimated) && EndViewCommand != null)
                    EndViewCommand(this, new EndViewCommandArgs(viewCmd));
                else
                {
                    if (modelCmd != null)
                    {
                        if (!modelCmd.AllowCancel())
                            return false;

                        endModelCommand();
                    }
                    else
                    {
                        // If there was no ModelCommand, clear and reset selection
                        Canguro.Model.Model.Instance.UnSelectAll();
                        SelectionCommand.Reset();
                    }
                }

                IdleReset();

                viewCmd = SelectionCommand;
                if (StartViewCommand != null)
                    StartViewCommand(this, EventArgs.Empty);
                mainFrm.ScenePanel.Cursor = SelectionCommand.DefaultCursor;

                return true;
            }

            // Check if command exists
            if (!commands.ContainsKey(command))
            {
                System.Windows.Forms.MessageBox.Show(Culture.Get("CommandNotFound") + ": '" + command + "'", Culture.Get("ActionNotPossibleTitle"), System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                return false;
            }

            // Execute Command
            // Prioritize View Commands
            Command cmd = commands[command];
            if (cmd is ViewCommand)
            {
                // If a series of viewCommands has ended (entered SelectionCommand)
                // then send the EndViewCommand signal
                // If Selection was doing anything and the viewCmd changes to zoom, pan, rotate, etc.
                // (exits selection mode), reset SelectionCommand
                if ((cmd == SelectionCommand) && (viewCmd != SelectionCommand) && (EndViewCommand != null))
                    EndViewCommand(this, new EndViewCommandArgs(viewCmd));
                else if ((cmd != SelectionCommand) && (viewCmd == SelectionCommand))
                    // Tal vez en lugar de un Reset sea mejor un Cancel, para no perder el tracking
                    SelectionCommand.Reset();

                // Instantiate and run new ViewCommand
                ViewCommand lastViewCmd = viewCmd;
                viewCmd = (ViewCommand)cmd;
                if (StartViewCommand != null)
                    StartViewCommand(this, EventArgs.Empty);

                if (viewCmd.SavePrevious)
                {
                    GraphicViewManager.Instance.SavePreviousActiveView();
                    //System.Console.WriteLine("SavePrevious");
                }

                if (viewCmd.IsInteractive)
                    mainFrm.ScenePanel.Cursor = viewCmd.Cursor;
                else
                {
                    viewCmd.Run(GraphicViewManager.Instance.ActiveView);
                    GraphicViewManager.Instance.updateView(false);
                    if (EndViewCommand != null)
                        EndViewCommand(this, new EndViewCommandArgs(viewCmd));

                    if (lastViewCmd == SelectionCommand)
                        viewCmd = SelectionCommand;
                    else
                    {
                        //if (lastViewCmd.SavePrevious && viewCmd != Commands.View.ZoomPrevious.Instance)
                        //{
                        //    GraphicViewManager.Instance.SavePreviousActiveView();
                        //    System.Console.WriteLine("SavePrevious");
                        //}

                        //viewCmd = lastViewCmd;

                        Execute("select");
                    }

                    if (StartViewCommand != null)
                        StartViewCommand(this, EventArgs.Empty);
                }
            }
            else if (cmd is ModelCommand)
            {
                if (modelCmd == null)
                {
                    // Por el momento funcionan en el mismo hilo, por lo que al terminar la
                    // llamada a Run se puede asignar modelCmd = null y services = null
                    modelCmd = (ModelCommand)cmd;
                    modelCmd.Cancel = false;
                    try
                    {
                        if (StartModelCommand != null)
                            StartModelCommand(this, EventArgs.Empty);
                        modelCmd.Run(services = new CommandServices(this));
                    }
                    catch (CancelCommandException) { Model.Model.Instance.Undo.Rollback(); }
                    catch (Exception ex) { System.Diagnostics.Debug.WriteLine("Controller.Execute: {0}", ex.Message); }
                    finally
                    {
                        endModelCommand();
                    }
                }
                else
                {
                    System.Windows.Forms.MessageBox.Show(Culture.Get("ModelCmdAlreadyExecuting"), Culture.Get("ActionNotPossibleTitle"), System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                    return false;
                }
            }

            return true;
        }