using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices;
using System.IO;
using SolidEdgeFramework;
using Microsoft.Win32;

namespace SolidEdgeMovieRecorder
{
    public partial class SEMovieRecorderForm : Form, ISEAnimationEvents, ISEApplicationEvents
    {
#region MemberData

        private Dictionary<IConnectionPoint, int> m_ConnectionPoints = new Dictionary<IConnectionPoint, int>();
        private Dictionary<IConnectionPoint, int> m_AnimationConnectionPoints = new Dictionary<IConnectionPoint, int>();
        private SolidEdgeFramework.Application m_Application = null;
        private SolidEdgeAssembly.AssemblyDocument m_Document = null;
        private SolidEdgeFramework.View m_View = null;
        private bool m_MovieInProgress = false;
        private int m_CurrentFrame = 0;
        private string m_Title = "";
        private string m_SubTitle = "";
        private string m_Description = "";
        private string m_Copyright = "";
        private string m_Author = "";
        private string m_AuthorURL = "";

#endregion

#region Constants

        private const int Format_AVIIndex = 0;
        private const int Format_WMVIndex = 1;

        private const int Resolution_NTSCIndex = 0;
        private const int Resolution_PALIndex = 1;
        private const int Resolution_HDIndex = 2;
        private const int Resolution_FullHDIndex = 3;
        private const int Resolution_CurrentViewIndex = 4;
        private const int Resolution_CustomIndex = 5;

#endregion

        public SEMovieRecorderForm()
        {
            InitializeComponent();
        }

        /*
        Function
            CleanupViewData

        Abstract
            Cleans up all member data.
        */

        private void CleanupAllData()
        {
            // clean up the view / recorder data
            CleanupViewData();

            // release our other objects
            m_Document = null;
            m_Application = null;
        }

        /*
        Function
            CleanupViewData

        Abstract
            Cleans up the view and movie recorder data.
        */

        private void CleanupViewData()
        {
            try
            {
                // unhook from the animation event set
                UnhookAnimationEvents();

                // stop recording any movie currently in progress
                StopRecordingMovie();

                // destroy the movie recorder
                m_View.DestroyMovieRecorder();
            }
            catch
            {
            }

            // release the view
            m_View = null;

            DisableControlsForUnableToRecord();
        }

        /*
        Function
            SEMovieRecorderForm_Load

        Abstract
            Performs initialization when the form loads.
        */

        private void SEMovieRecorderForm_Load(object sender, EventArgs e)
        {
            // register a message filter to reduce message timing issues
            OleMessageFilter.Register(); 
            
            // try to get the currently running instance of Solid Edge
            try
            {
                m_Application = (SolidEdgeFramework.Application)Marshal.GetActiveObject("SolidEdge.Application");
            }
            catch
            {
                MessageBox.Show("Could not get the Solid Edge application object.", "Solid Edge Movie Recorder");

                // Solid Edge isn't running, shut down
                Close();
            }

            if (null != m_Application)
            {
                // hook up the application event set
                HookEvents(m_Application, typeof(ISEApplicationEvents).GUID);

                // try to get the active assembly document
                try
                {
                    m_Document = (SolidEdgeAssembly.AssemblyDocument)m_Application.ActiveDocument;
                }
                catch
                {
                    m_Document = null;                	
                }

                // if we have the active assembly document, set up the view and movie recorder
                if (null != m_Document)
                {
                    SetView();
                }
            }

            // initialize the movie settings controls
            InitializeMovieControls();

            if (null == m_Document)
            {
                DisableControlsForUnableToRecord();
            }
        }

        /*
        Function
            SEMovieRecorderForm_Shown

        Abstract
            Additional initialization when the form has been displayed.
        */

        private void SEMovieRecorderForm_Shown(object sender, EventArgs e)
        {
            // select the default file name we assigned so it can be changed immediately
            TextBoxSelectString(FileNameTextBox, "animation");
        }

        /*
        Function
            SEMovieRecorderForm_FormClosing

        Abstract
            Peforms clean up when the form is closing.
        */

        private void SEMovieRecorderForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            // unhook from events we are listening to
            UnhookEvents();

            // clean up the moview data
            CleanupAllData();

            // unregister the message filter
            OleMessageFilter.Unregister();
        }

        /*
        Function
            InitializeMovieControls

        Abstract
            Initializes the movie settings controls.
        */

        private void InitializeMovieControls()
        {
            // set the frame rate text
            SetFrameRateLabelText();

            // set the quality text
            SetQualityLabelText();

            // default to the WMV movie format
            FormatComboBox.SelectedIndex = Format_WMVIndex;

            // default to the Full HD resolution
            ResolutionComboBox.SelectedIndex = Resolution_FullHDIndex;

            // default to play the movie when done recording
            PlayCheckBox.Checked = true;

            // default to record animation timeline events
            AnimationTimelineCheckBox.Checked = true;

            // default to not record Drag Component motion events
            DragComponentCheckBox.Checked = false;

            // disable the Stop Recording button since there is no movie in progress
            StopRecordingButton.Enabled = false;

            // set the Start/Stop recording tooltips
            ControlToolTips.SetToolTip(StartRecordingButton, "Start Recording");
            ControlToolTips.SetToolTip(StopRecordingButton, "Stop Recording");

            // set the default movie file name
            FileNameTextBox.Text = DefaultMovieName();

            // enable the resolution fields if possible
            EnableOrDisableResolutionFields(true);

            // default the movie author to the current user
            m_Author = System.Environment.UserName;

            // initialize the bit rate
            if (null != m_View)
            {
                try
                {
                    BitRateTextBox.Text = m_View.MovieBitRate.ToString();
                }
                catch
                {

                }
            }
        }

#region Utilities

        /*
        Function
            TextBoxSelectString

        Abstract
            Selects the string in the text box if it is found.
        */

        private void TextBoxSelectString(TextBox BoxToSearch, string TextToSelect)
        {
            try
            {
                if (!string.IsNullOrWhiteSpace(TextToSelect))
                {
                    int index = BoxToSearch.Text.IndexOf(TextToSelect);

                    // if the string was found, set focus to the text box and select the string
                    if (-1 != index)
                    {
                        BoxToSearch.Focus();

                        BoxToSearch.Select(index, TextToSelect.Length);
                    }
                }
            }
            catch
            {
            	
            }
        }

        /*
        Function
            DefaultMovieName

        Abstract
            Returns the default name to use for the movie file.
            The default is a file called animation.wmv in the temp folder.
        */

        private string DefaultMovieName()
        {
            string TempPath = System.IO.Path.GetTempPath();

            return TempPath + "animation.wmv";
        }

        /*
        Function
            InitializeViewAndRecorder

        Abstract
            Sets the input view as the view to use for recording and initializes the movie
            recorder for recording.
        */

        private void InitializeViewAndRecorder(SolidEdgeFramework.View CurrentView)
        {
            if (null != CurrentView)
            {
                try
                {
                    // only use the view if it is able to display
                    if (CurrentView.DisplayEnabled)
                    {
                        m_View = CurrentView;

                        if (null != m_View)
                        {
                            // hook up the animation event set
                            HookAnimationEvents(typeof(ISEAnimationEvents).GUID);
                        }

                        // intialize the movie recorder
                        UpdateMovieFormat();
                    }
                }
                catch
                {
                }
            }
        }

        /*
        Function
            PopulateCodecList

        Abstract
            Populates the compression codec combo box with the codecs available on the user's
            machine for the given movie format.

        History
            Greg Luckett    11/6/2014  creation
        */

        private void PopulateCodecList()
        {
            if (null != m_View)
            {
                try
                {
                    string[] Codecs = { "" };
                    Array ArrayOfCodecs;

                    // reset the current codec list
                    CodecComboBox.Items.Clear();

                    // get the list of available movie codecs and populate the combo box
                    // with them
                    ArrayOfCodecs = Codecs.ToArray();

                    m_View.GetAvailableMovieCodecs(out ArrayOfCodecs);

                    foreach (string codec in ArrayOfCodecs)
                    {
                        CodecComboBox.Items.Add(codec);
                    }

                    // default to the first codec in the list
                    CodecComboBox.SelectedIndex = 0;
                }
                catch
                {

                }
            }
        }

        /*
        Function
            UpdateMovieFormat

        Abstract
            Creates the movie recorder for the currently selected movie format.
        */

        private void UpdateMovieFormat()
        {
            seMovieFormatConstants MovieFormat;
            String MovieFile;

            if (null != m_View)
            {
                try
                {
                    // stop recording the current movie in progress
                    StopRecordingMovie();

                    // destroy the current movie recorder
                    m_View.DestroyMovieRecorder();
                }
                catch
                {

                }
            }

            try
            {
                MovieFile = FileNameTextBox.Text;

                if (String.IsNullOrWhiteSpace(MovieFile))
                {
                    MovieFile = DefaultMovieName();
                }

                // make sure the file name is initialized with the appropriate extension
                if (Format_AVIIndex == FormatComboBox.SelectedIndex)
                {
                    MovieFormat = seMovieFormatConstants.seMovieFormatAVI;
                    FileNameTextBox.Text = MovieFile.Replace(".wmv", ".avi");
                }
                else
                {
                    MovieFormat = seMovieFormatConstants.seMovieFormatWMV;
                    FileNameTextBox.Text = MovieFile.Replace(".avi", ".wmv");
                }

                EnableOrDisableControlsBasedOnMovieFormat();

                // create the recorder for the current movie format
                m_View.CreateMovieRecorder(MovieFormat);
            }
            catch
            {

            }

            // fill the codec list
            PopulateCodecList();
        }

        /*
        Function
            CustomResolutionSelected

        Abstract
            Returns whether or not the user has selected a custom movie resolution.
        */

        private bool CustomResolutionSelected()
        {
            return (Resolution_CustomIndex == ResolutionComboBox.SelectedIndex) ? true : false;
        }

        /*
        Function
            SetMovieCodec

        Abstract
            Sets the compression codec for the movie.
        */

        private void SetMovieCodec()
        {
            if (null != m_View)
            {
                try
                {
                    string Codec = CodecComboBox.SelectedItem.ToString();

                    if (!String.IsNullOrWhiteSpace(Codec))
                    {
                        m_View.MovieCodec = Codec;
                    }
                }
                catch
                {

                }
            }
        }

        /*
        Function
            SetMovieBitRate

        Abstract
            Sets the movie bit rate for the movie.
        */

        private void SetMovieBitRate()
        {
            if (null != m_View)
            {
                try
                {
                    string BitRateText = BitRateTextBox.Text;

                    if (!String.IsNullOrWhiteSpace(BitRateText))
                    {
                        m_View.MovieBitRate = Convert.ToUInt32(BitRateText);
                    }
                }
                catch
                {

                }
            }
        }

        /*
        Function
            SetMovieTitle

        Abstract
            Sets the title for the movie.
        */

        private void SetMovieTitle()
        {
            if (null != m_View)
            {
                try
                {
                    if (!String.IsNullOrWhiteSpace(m_Title))
                    {
                        m_View.MovieTitle = m_Title;
                    }
                }
                catch
                {

                }
            }
        }

        /*
        Function
            SetMovieSubTitle

        Abstract
            Sets the sub title (not subtitle) for the movie.
        */

        private void SetMovieSubTitle()
        {
            if (null != m_View)
            {
                try
                {
                    if (!String.IsNullOrWhiteSpace(m_SubTitle))
                    {
                        m_View.MovieSubTitle = m_Title;
                    }
                }
                catch
                {

                }
            }
        }

        /*
        Function
            SetMovieDescription

        Abstract
            Sets the description for the movie.
        */

        private void SetMovieDescription()
        {
            if (null != m_View)
            {
                try
                {
                    if (!String.IsNullOrWhiteSpace(m_Description))
                    {
                        m_View.MovieDescription = m_Description;
                    }
                }
                catch
                {

                }
            }
        }

        /*
        Function
            SetMovieCopyright

        Abstract
            Sets the copyright for the movie.
        */

        private void SetMovieCopyright()
        {
            if (null != m_View)
            {
                try
                {
                    if (!String.IsNullOrWhiteSpace(m_Copyright))
                    {
                        m_View.MovieCopyright = m_Copyright;
                    }
                }
                catch
                {

                }
            }
        }

        /*
        Function
            SetMovieAuthor

        Abstract
            Sets the author for the movie.
        */

        private void SetMovieAuthor()
        {
            if (null != m_View)
            {
                try
                {
                    if (!String.IsNullOrWhiteSpace(m_Author))
                    {
                        m_View.MovieAuthor = m_Author;
                    }
                }
                catch
                {

                }
            }
        }

        /*
        Function
            SetMovieAuthorURL

        Abstract
            Sets the author's website URL for the movie.
        */

        private void SetMovieAuthorURL()
        {
            if (null != m_View)
            {
                try
                {
                    if (!String.IsNullOrWhiteSpace(m_AuthorURL))
                    {
                        m_View.MovieAuthorURL = m_AuthorURL;
                    }
                }
                catch
                {

                }
            }
        }

        /*
        Function
            ResetDefaultBitRate

        Abstract
            Resets the default bit rate for the movie. When setting the bit rate to 0,
            the new default bit rate will be calculated based on the frame rate and resolution.
        */

        private void ResetDefaultBitRate()
        {
            if (null != m_View)
            {
                // reset the bit rate to 0, which forces the new default to be computed
                m_View.MovieBitRate = 0;

                // update the value with the new default
                BitRateTextBox.Text = m_View.MovieBitRate.ToString();
            }
        }

        /*
        Function
            AddFrameToMovie

        Abstract
            Adds a frame to the current movie in progress. The input frame number is
            the current frame given to us by the animation editor. All frames are
            marked as keyframes in this example.
        */

        private void AddFrameToMovie(int TimelineFrame)
        {
            // only add a frame if there is a movie in progress and the timeline frame is greater than the last frame we added
            if (m_MovieInProgress && (0 < TimelineFrame) && (TimelineFrame > m_CurrentFrame) && (null != m_View))
            {
                try
                {
                    int FrameCount = 0;
                    bool KeyFrame = true;

                    // add the frame to the movie
                    m_View.AddFrameToMovie(KeyFrame, out FrameCount);

                    // update the last frame added with the new frame
                    m_CurrentFrame = FrameCount;
                }
                catch
                {

                }
            }
        }

        /*
        Function
            AddFrameToDragComponentMovie

        Abstract
            Adds a frame to the current movie in progress for a Drag Component motion event. There is no
            frame number information received since there is no frame concept with Drag Component. All frames are
            marked as keyframes in this example.
        */

        private void AddFrameToDragComponentMovie()
        {
            // only add a frame if there is a movie in progress
            if (m_MovieInProgress && (null != m_View))
            {
                try
                {
                    int FrameCount = 0;
                    bool KeyFrame = true;

                    // add the frame to the movie
                    m_View.AddFrameToMovie(KeyFrame, out FrameCount);
                    
                    m_CurrentFrame = FrameCount;
                }
                catch
                {

                }
            }
        }

        /*
        Function
            UpdateCustomMovieResolution

        Abstract
            If the user has chosen to use a custom movie resolution, updates the movie resolution and default bit rate when the user modifies the width
            or height of the movie.
        */

        private void UpdateCustomMovieResolution()
        {
            // don't do anything if not using a custom resolution
            if (Resolution_CustomIndex == ResolutionComboBox.SelectedIndex)
            {
                if (null != m_View)
                {
                    try
                    {
                        // don't change anything if the width or height is null or empty
                        if (!string.IsNullOrWhiteSpace(WidthTextBox.Text) && !string.IsNullOrWhiteSpace(HeightTextBox.Text))
                        {
                            try
                            {
                                int nWidth = Convert.ToInt32(WidthTextBox.Text);
                                int nHeight = Convert.ToInt32(HeightTextBox.Text);

                                // update the resolution
                                m_View.SetCustomMovieResolution(nWidth, nHeight);

                                // reset the movie bit rate
                                ResetDefaultBitRate();
                            }
                            catch
                            {

                            }
                        }
                    }
                    catch
                    {
                    }
                }
            }
        }

        /*
        Function
            StartRecordingMovie

        Abstract
            Starts the movie recording process if there is not a movie already in progress. Once the recording process
            has been started, frames will be added to the movie when animation events are received (based on the settings the
            user has selected on the form).
        */

        private void StartRecordingMovie()
        {
            // only start recording if there is not already a movie in progress
            if (!m_MovieInProgress && (null != m_View))
            {
                try
                {
                    string FileName = DefaultMovieName();

                    // disable all the movie settings controls because
                    // the settings can not be modified once recording has
                    // started
                    EnableOrDisableRecordingControls(false);

                    // enable the Stop Recording button
                    StopRecordingButton.Enabled = true;

                    // set the various movie settings
                    SetMovieResolution();
                    SetMovieCodec();
                    SetMovieBitRate();
                    SetMovieTitle();
                    SetMovieSubTitle();
                    SetMovieDescription();
                    SetMovieCopyright();
                    SetMovieAuthor();
                    SetMovieAuthorURL();

                    if (!String.IsNullOrWhiteSpace(FileNameTextBox.Text))
                    {
                        FileName = FileNameTextBox.Text;
                    }

                    // start recording the movie
                    m_View.BeginMovieRecording(FileName);

                    m_MovieInProgress = true;
                    m_CurrentFrame = 0;
                }
                catch
                {
                    EnableOrDisableRecordingControls(true);
                    EnableOrDisableControlsBasedOnMovieFormat();

                    StopRecordingButton.Enabled = false;

                    m_MovieInProgress = false;
                }
            }
        }

        /*
        Function
            StopRecordingMovie

        Abstract
            Stops the movie recording process if there is a movie being recorded. This finalizes the
            movie file on disk.
        */

        private void StopRecordingMovie()
        {
            // don't do anything if there is not a movie in progress
            if (m_MovieInProgress && (null != m_View))
            {
                try
                {
                    // stop the recording progress
                    m_View.EndMovieRecording();

                    // re-enable the movie settings controls since there is
                    // no longer a movie in progress
                    EnableOrDisableRecordingControls(true);
                    EnableOrDisableControlsBasedOnMovieFormat();

                    // disable the Stop Recording button since there is no longer a movie in progress
                    StopRecordingButton.Enabled = false;

                    if (m_MovieInProgress && !string.IsNullOrWhiteSpace(FileNameTextBox.Text))
                    {
                        if (0 < m_CurrentFrame)
                        {
                            // if the user has checked the option to play the movie when finished,
                            // start the process to play the movie file
                            if (PlayCheckBox.Checked)
                            {
                                Process.Start(FileNameTextBox.Text);
                            }
                        }
                        else if (File.Exists(FileNameTextBox.Text))
                        {
                            File.Delete(FileNameTextBox.Text);
                        }
                    }

                    m_MovieInProgress = false;
                    m_CurrentFrame = 0;
                }
                catch
                {

                }
            }
        }

        /*
        Function
            SetView

        Abstract
            Sets the member view pointer to be the active view and initializes a movie recorder for the view.
        */

        private void SetView()
        {
            if (null != m_Application)
            {
                SolidEdgeFramework.Window ActiveWindow = m_Application.ActiveWindow;

                if (null != ActiveWindow)
                {
                    try
                    {
                        SolidEdgeFramework.View ActiveView = ActiveWindow.View;

                        if (null != ActiveView)
                        {
                            InitializeViewAndRecorder(ActiveView);
                        }
                    }
                    catch
                    {

                    }
                }
            }
        }

        /*
        Function
            DocumentOpening

        Abstract
            Sets the member document pointer when a document is opened from an application event.
        */

        private void DocumentOpening(object theDocument)
        {
            if (null == m_Document)
            {
                try
                {
                    m_Document = (SolidEdgeAssembly.AssemblyDocument)theDocument;
                }
                catch
                {

                }
            }
        }

#endregion

#region Control Handlers

        /*
        Function
            EnableOrDisableResolutionFieldsEnableOrDisableControlsBasedOnMovieFormat

        Abstract
            Enables or disables the controls that are only available for specific
            movie formats based on which format is selected.
        */

        private void EnableOrDisableControlsBasedOnMovieFormat()
        {
            if (Format_AVIIndex == FormatComboBox.SelectedIndex)
            {
                // disable controls not available for AVI files
                MovieInformationButton.Enabled = false;
                BitRateTextBox.Enabled = false;
            }
            else
            {
                // enable controls available for WMV files
                MovieInformationButton.Enabled = true;
                BitRateTextBox.Enabled = true;
            }
        }

        /*
        Function
            EnableOrDisableResolutionFields

        Abstract
            Enables or disables the resolution Width and Height fields based on the input flag.
            If a custom resolution is not being used, the fields will always be disabled since
            standard resolutions have fixed values.
        */

        private void EnableOrDisableResolutionFields(bool bEnable)
        {
            WidthLabel.Enabled = true;
            HeightLabel.Enabled = true;

            WidthTextBox.Enabled = bEnable;
            HeightTextBox.Enabled = bEnable;

            if (!CustomResolutionSelected())
            {
                WidthTextBox.Enabled = false;
                HeightTextBox.Enabled = false;
            }
        }

        /*
        Function
            EnableOrDisableRecordingControls

        Abstract
            Enables or disables the various movie settings controls based on the input flag.
        */

        private void EnableOrDisableRecordingControls(bool bEnable)
        {
            StartRecordingButton.Enabled = bEnable;
            FileNameTextBox.Enabled = bEnable;
            FrameRateTrackBar.Enabled = bEnable;
            QualityTrackBar.Enabled = bEnable;
            FormatComboBox.Enabled = bEnable;
            ResolutionComboBox.Enabled = bEnable;
            CodecComboBox.Enabled = bEnable;
            BitRateTextBox.Enabled = bEnable;
            MovieInformationButton.Enabled = bEnable;

            EnableOrDisableResolutionFields(bEnable);
        }

        /*
        Function
            DisableControlsForUnableToRecord

        Abstract
            Disables the various movie settings controls when recording is not possible (because of no view).
        */

        private void DisableControlsForUnableToRecord()
        {
            if (null == m_View)
            {
                EnableOrDisableRecordingControls(false);

                StopRecordingButton.Enabled = false;
            }
        }

        /*
        Function
            EnableControlsForAbleToRecord

        Abstract
            Enables the various movie settings controls when it is possible to record.
        */

        private void EnableControlsForAbleToRecord()
        {
            if (null != m_View)
            {
                EnableOrDisableRecordingControls(true);
                EnableOrDisableControlsBasedOnMovieFormat();

                StopRecordingButton.Enabled = false;
            }
        }

        /*
        Function
            SetResolutionFields

        Abstract
            Sets the resolution width and height field values with the appropriate values for standard
            resolutions. Does nothing if a custom resolution is being used.
        */

        private void SetResolutionFields()
        {
            int nSelectedResolution = ResolutionComboBox.SelectedIndex;
            int nWidth = 640;
            int nHeight = 480;

            switch (nSelectedResolution)
            {
                case Resolution_NTSCIndex:
                    nWidth = 640;
                    nHeight = 480;

                    WidthTextBox.Text = nWidth.ToString();
                    HeightTextBox.Text = nHeight.ToString();
                break;

                case Resolution_PALIndex:
                    nWidth = 768;
                    nHeight = 576;

                    WidthTextBox.Text = nWidth.ToString();
                    HeightTextBox.Text = nHeight.ToString();
                break;

                case Resolution_HDIndex:
                    nWidth = 1280;
                    nHeight = 780;

                    WidthTextBox.Text = nWidth.ToString();
                    HeightTextBox.Text = nHeight.ToString();
                break;

                case Resolution_FullHDIndex:
                    nWidth = 1920;
                    nHeight = 1080;

                    WidthTextBox.Text = nWidth.ToString();
                    HeightTextBox.Text = nHeight.ToString();
                break;

                case Resolution_CurrentViewIndex:
                    WidthTextBox.Text = "";
                    HeightTextBox.Text = "";

                    if (null != m_View)
                    {
                        SolidEdgeFramework.Window ActiveWindow = m_View.Window;

                        if (null != ActiveWindow)
                        {
                            WidthTextBox.Text = ActiveWindow.Width.ToString();
                            HeightTextBox.Text = ActiveWindow.Height.ToString();
                        }
                    }
                break;

                case Resolution_CustomIndex:
                break;
            }
        }

        /*
        Function
            SetQualityLabelText

        Abstract
            Updates the movie quality label and tooltip based on the current value of the quality track bar.
        */

        private void SetQualityLabelText()
        {
            string QualityValueString = QualityTrackBar.Value.ToString();

            QualityLable.Text = "Movie Quality - " + QualityValueString;

            ControlToolTips.SetToolTip(QualityTrackBar, QualityValueString);
        }

        /*
        Function
            SetFrameRateLabelText

        Abstract
            Updates the frame rate label and tooltip based on the current value of the frame rate track bar.
        */

        private void SetFrameRateLabelText()
        {
            string FrameRateValueString = FrameRateTrackBar.Value.ToString() + " frames/sec";

            FrameRateLabel.Text = "Frame Rate - " + FrameRateValueString;

            ControlToolTips.SetToolTip(FrameRateTrackBar, FrameRateValueString);
        }

        /*
        Function
            FrameRateTrackBar_ValueChanged

        Abstract
            Updates the movie's frame rate and updates the frame rate label on the form when the track bar value
            changes.
        */

        private void FrameRateTrackBar_ValueChanged(object sender, EventArgs e)
        {
            // update the label and tooltip
            SetFrameRateLabelText();

            if (null != m_View)
            {
                try
                {
                    // update the movie's frame rate
                    m_View.MovieFrameRate = (uint)FrameRateTrackBar.Value;
                }
                catch
                {

                }
            }
        }

        /*
        Function
            QualityTrackBar_ValueChanged

        Abstract
            Updates the movie's quality and updates the quality label on the form when the track bar value
            changes.
        */

        private void QualityTrackBar_ValueChanged(object sender, EventArgs e)
        {
            // update the label and tooltip
            SetQualityLabelText();

            if (null != m_View)
            {
                try
                {
                    // update the movie's quality
                    m_View.MovieQuality = (uint)QualityTrackBar.Value;
                }
                catch
                {

                }
            }
        }

        /*
        Function
            FormatComboBox_SelectedIndexChanged

        Abstract
            Updates the movie format when the user selects one in the combo box.
        */

        private void FormatComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (null != m_View)
            {
                try
                {
                    UpdateMovieFormat();
                }
                catch
                {

                }
            }
        }

        /*
        Function
            ResolutionComboBox_SelectedIndexChanged

        Abstract
            Updates the movie resolution settings when the user has selected a new resolution in the
            combo box.
        */

        private void ResolutionComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            seMovieStandardResolutionConstants resolution = seMovieStandardResolutionConstants.seMovieStandardResolutionNTSC;
            int nSelectedResolution = ResolutionComboBox.SelectedIndex;
            bool bCustomResolution = false;

            switch (nSelectedResolution)
            {
                case Resolution_NTSCIndex:
                    FrameRateTrackBar.Value = 30;

                    resolution = seMovieStandardResolutionConstants.seMovieStandardResolutionNTSC;
                break;

                case Resolution_PALIndex:
                    FrameRateTrackBar.Value = 25;

                    resolution = seMovieStandardResolutionConstants.seMovieStandardResolutionPAL;
                break;

                case Resolution_HDIndex:
                    FrameRateTrackBar.Value = 60;

                    resolution = seMovieStandardResolutionConstants.seMovieStandardResolutionHD;
                break;

                case Resolution_FullHDIndex:
                    FrameRateTrackBar.Value = 60;

                    resolution = seMovieStandardResolutionConstants.seMovieStandardResolutionFullHD;
                break;

                case Resolution_CurrentViewIndex:
                    resolution = seMovieStandardResolutionConstants.seMovieStandardResolutionCurrentView;
                break;

                case Resolution_CustomIndex:
                    bCustomResolution = true;
                break;
            }

            // update the resolution width and height fields
            SetResolutionFields();

            // enable the resolution fields (if possible)
            EnableOrDisableResolutionFields(true);

            if (null != m_View)
            {
                try
                {
                    // update the movie resolution
                    if (!bCustomResolution)
                    {
                        m_View.SetMovieResolution(resolution);
                    }
                    else
                    {
                        if (!string.IsNullOrWhiteSpace(WidthTextBox.Text) && !string.IsNullOrWhiteSpace(HeightTextBox.Text))
                        {
                            try
                            {
                                int nWidth = Convert.ToInt32(WidthTextBox.Text);
                                int nHeight = Convert.ToInt32(HeightTextBox.Text);

                                m_View.SetCustomMovieResolution(nWidth, nHeight);
                            }
                            catch
                            {
                            	
                            }
                        }
                    }

                    // reset the default bit rate since the frame rate changed
                    ResetDefaultBitRate();
                }
                catch
                {
                }
            }
        }

        /*
        Function
            SetMovieResolution

        Abstract
            Sets the resolution for the movie.
        */

        private void SetMovieResolution()
                {
                    seMovieStandardResolutionConstants resolution = seMovieStandardResolutionConstants.seMovieStandardResolutionNTSC;
                    int nSelectedResolution = ResolutionComboBox.SelectedIndex;
                    bool bCustomResolution = false;

                    switch (nSelectedResolution)
                    {
                        case Resolution_NTSCIndex:
                            resolution = seMovieStandardResolutionConstants.seMovieStandardResolutionNTSC;
                        break;

                        case Resolution_PALIndex:
                            resolution = seMovieStandardResolutionConstants.seMovieStandardResolutionPAL;
                        break;

                        case Resolution_HDIndex:
                            resolution = seMovieStandardResolutionConstants.seMovieStandardResolutionHD;
                        break;

                        case Resolution_FullHDIndex:
                            resolution = seMovieStandardResolutionConstants.seMovieStandardResolutionFullHD;
                        break;

                        case Resolution_CustomIndex:
                            bCustomResolution = true;
                        break;
                    }

                    if (null != m_View)
                    {
                        try
                        {
                            // update the movie resolution
                            if (!bCustomResolution)
                            {
                                m_View.SetMovieResolution(resolution);
                            }
                            else
                            {
                                if (!string.IsNullOrWhiteSpace(WidthTextBox.Text) && !string.IsNullOrWhiteSpace(HeightTextBox.Text))
                                {
                                    try
                                    {
                                        int nWidth = Convert.ToInt32(WidthTextBox.Text);
                                        int nHeight = Convert.ToInt32(HeightTextBox.Text);

                                        m_View.SetCustomMovieResolution(nWidth, nHeight);
                                    }
                                    catch
                                    {

                                    }
                                }
                            }
                        }
                        catch
                        {
                        }
                    }
                }

                /*
                Function
                    StartRecordingButton_Click

                Abstract
                    Starts the movie recording process when the Start Recording button is clicked.
                */

        private void StartRecordingButton_Click(object sender, EventArgs e)
        {
            StartRecordingMovie();
        }

        /*
        Function
            StopRecordingButton_Click

        Abstract
            Stops the movie recording process when the Stop Recording button is clicked.
        */

        private void StopRecordingButton_Click(object sender, EventArgs e)
        {
            StopRecordingMovie();
        }

        /*
        Function
            MovieInformationButton_Click

        Abstract
            Brings up the dialog for setting the movie summary information (not available for AVI movies).
        */

        private void MovieInformationButton_Click(object sender, EventArgs e)
        {
            SummaryInfoForm dlg = new SummaryInfoForm();

            // initialize the form with the current settings
            dlg.Title = m_Title;
            dlg.SubTitle = m_SubTitle;
            dlg.Description = m_Description;
            dlg.Copyright = m_Copyright;
            dlg.Author = m_Author;
            dlg.AuthorURL = m_AuthorURL;

            // update the settings if the user hit 'OK'
            if (DialogResult.OK == dlg.ShowDialog())
            {
                m_Title = dlg.Title;
                m_SubTitle = dlg.SubTitle;
                m_Description = dlg.Description;
                m_Copyright = dlg.Copyright;
                m_Author = dlg.Author;
                m_AuthorURL = dlg.AuthorURL;
            }
        }

#endregion

#region ISEAnimationEvents

        /*
        Function
            AnimationEvent

        Abstract
            Called when an animation event is received. Adds a frame to the movie if necessary.
        */

        public void AnimationEvent(AnimationEventConstants EventType, int Frame)
        {
            switch (EventType)
            {
                case AnimationEventConstants.AfterTimelineFrameUpdate:
                    // if there is a movie in progress, add a frame to the movie
                    // if the user has set the option to record animation editor timeline
                    // events
                    if (m_MovieInProgress && AnimationTimelineCheckBox.Checked)
                    {
                        AddFrameToMovie(Frame);
                    }
                break;

                case AnimationEventConstants.AfterDragComponentFrameUpdate:
                    // if there is a movie in progress, add a frame to the movie
                    // if the user has set the option to record drag component motion
                    // events
                    if (m_MovieInProgress && DragComponentCheckBox.Checked)
                    {
                        AddFrameToDragComponentMovie();
                    }
                break;
            }
        }

#endregion

#region ISEApplicationEvents

        #region Unimplemented Application Events
            public void AfterCommandRun(int theCommandID)
            {
            }

            public void AfterDocumentOpen(object theDocument)
            {
            }

            public void AfterDocumentPrint(object theDocument, int hDC, ref double ModelToDC, ref int Rect)
            {
            }

            public void AfterDocumentSave(object theDocument)
            {
            }

            public void AfterEnvironmentActivate(object theEnvironment)
            {
            }

            public void AfterNewDocumentOpen(object theDocument)
            {
            }

            public void AfterNewWindow(object theWindow)
            {
            }

            public void BeforeCommandRun(int theCommandID)
            {
            }

            public void BeforeDocumentPrint(object theDocument, int hDC, ref double ModelToDC, ref int Rect)
            {
            }

            public void BeforeDocumentSave(object theDocument)
            {
            }

            public void BeforeEnvironmentDeactivate(object theEnvironment)
            {
            }

            public void AfterWindowActivate(object theWindow)
            {
            }

        #endregion

        public void AfterActiveDocumentChange(object theDocument)
        {
            SolidEdgeAssembly.AssemblyDocument ActiveDocument = (SolidEdgeAssembly.AssemblyDocument)theDocument;

            CleanupViewData();

            m_Document = null;

            if (null != ActiveDocument)
            {
                m_Document = ActiveDocument;

                SetView();

                EnableControlsForAbleToRecord();
            }
            else
            {
                DisableControlsForUnableToRecord();
            }
        }

        public void BeforeDocumentClose(object theDocument)
        {
            if (m_Document == theDocument)
            {
                CleanupViewData();

                m_Document = null;

                DisableControlsForUnableToRecord();
            }
        }

        public void BeforeQuit()
        {
            UnhookEvents();

            CleanupAllData();
        }

        public void BeforeWindowDeactivate(object theWindow)
        {
            SolidEdgeFramework.Window ActiveWindow = (SolidEdgeFramework.Window)theWindow;

            if (null != ActiveWindow)
            {
                try
                {
                    SolidEdgeFramework.View ActiveView = ActiveWindow.View;

                    if ((null != ActiveView) && (ActiveView == m_View))
                    {
                        CleanupViewData();

                        DisableControlsForUnableToRecord();
                    }
                }
                catch
                {
                	
                }
            }
        }

#endregion

#region Event hooking-unhooking

        private void HookEvents(object source, Guid eventGuid)
        {
            IConnectionPointContainer connectionPointContainer = null;
            IConnectionPoint connectionPoint = null;
            int cookie = 0;

            connectionPointContainer = source as IConnectionPointContainer;
            if (connectionPointContainer != null)
            {
                connectionPointContainer.FindConnectionPoint(eventGuid, out connectionPoint);
                if (connectionPoint != null)
                {
                    connectionPoint.Advise(this, out cookie);
                    if (cookie != 0)
                    {
                        m_ConnectionPoints.Add(connectionPoint, cookie);
                    }
                    else
                    {
                        throw new System.Exception("Advisory connection between the connection point and the caller's sink object failed.");
                    }
                }
                else
                {
                    throw new System.Exception(String.Format("Connection point '{0}' not found.", eventGuid));
                }
            }
            else
            {
                throw new System.Exception("Source does not implement IConnectionPointContainer.");
            }

        }

        private void HookAnimationEvents(Guid eventGuid)
        {
            if (null != m_View)
            {
                IConnectionPointContainer connectionPointContainer = null;
                IConnectionPoint connectionPoint = null;
                int cookie = -1;

                connectionPointContainer = m_View.AnimationEvents as IConnectionPointContainer;
                if (connectionPointContainer != null)
                {
                    connectionPointContainer.FindConnectionPoint(eventGuid, out connectionPoint);
                    if (connectionPoint != null)
                    {
                        connectionPoint.Advise(this, out cookie);
                        if (cookie != 0)
                        {
                            m_AnimationConnectionPoints.Add(connectionPoint, cookie);
                        }
                        else
                        {
                            throw new System.Exception("Advisory connection between the connection point and the caller's sink object failed.");
                        }
                    }
                    else
                    {
                        throw new System.Exception(String.Format("Connection point '{0}' not found.", eventGuid));
                    }
                }
                else
                {
                    throw new System.Exception("Source does not implement IConnectionPointContainer.");
                }
            }
        }

        private void UnhookAnimationEvents()
        {
            Dictionary<IConnectionPoint, int>.Enumerator enumerator = m_AnimationConnectionPoints.GetEnumerator();

            while (enumerator.MoveNext())
            {
                enumerator.Current.Key.Unadvise(enumerator.Current.Value);
            }

            m_AnimationConnectionPoints.Clear();
        }

        private void UnhookEvents()
        {
            Dictionary<IConnectionPoint, int>.Enumerator enumerator = m_ConnectionPoints.GetEnumerator();

            while (enumerator.MoveNext())
            {
                enumerator.Current.Key.Unadvise(enumerator.Current.Value);
            }

            m_ConnectionPoints.Clear();
        }

#endregion

    }
}
