/// <summary>
        /// Initializes a new instance of the class.
        /// <list type="number">
        /// <item><description>Clear the existing list of worksets.</description></item>
        /// <item><description>Create a baseline workset and add this to the list of worksets.</description></item>
        /// <item><description>Set the newly created baseline workset to be the default workset.</description></item>
        /// <item><description>Copy the project information specified in the data dictionary to the project information field.</description></item>
        /// </list>
        /// </summary>
        /// <param name="worksetCollectionType">The type of workset collection.</param>
        /// <param name="entryCountMax">The maximum number of entries that each workset can support.</param>
        /// <param name="columnCountMax">The maximum number of display columns that each workset can support.</param>
        public void Initialize(WorksetCollectionType worksetCollectionType, short entryCountMax, short columnCountMax)
        {
            m_WorksetCollectionFile_t = new WorksetCollectionFile_t();
            m_WorksetCollectionFile_t.ProjectInformation = Parameter.ProjectInformation;
            m_WorksetCollectionFile_t.WorksetCollectionType = worksetCollectionType;
            m_WorksetCollectionFile_t.EntryCountMax = entryCountMax;
            m_WorksetCollectionFile_t.ColumnCountMax = columnCountMax;

            // Instantiate the list of workset structures.
            m_WorksetCollectionFile_t.WorksetList = new List<Workset_t>();

            // Create a new baseline workset i.e. one containing ALL watch variable references, ordered by watch identifier.
            Workset_t workset = new Workset_t();
            workset = CreateBaselineWorkset();

            // Add this baseline workset to the list.
            m_WorksetCollectionFile_t.WorksetList.Add(workset);

            // Set the active index to point at the baseline workset.
            m_WorksetCollectionFile_t.ActiveIndex = 0;

            // Set the default index to point at the baseline workset.
            m_WorksetCollectionFile_t.DefaultIndex = 0;
        }
        /// <summary>
        /// Load and validate the <see cref="WorksetCollectionFile_t"/> structure contained within the specified workset file.
        /// </summary>
        /// <param name="fullFilename">The fully qualified file name of the workset file.</param>
        public void Load(string fullFilename)
        {
            // Flag to indicate whether the workset is compatible with the current data dictionary i.e. the number of watch identifiers associated with the workset file 
            // is the same as the number of watch identifiers in the current data dictionary.
            bool isCompatible = false;

            FileInfo fileInfo = new FileInfo(fullFilename);
            if (fileInfo.Exists == true)
            {
                m_Filename = fileInfo.Name;
            }

            // De-serialize the workset file.
            m_WorksetCollectionFile_t = Deserialize(fullFilename);
            Thread.Sleep(SleepDeSerialize);

            // Check whether the de-serialized workset file is compatible with the current data dictionary.
            isCompatible = CheckCompatibility(m_WorksetCollectionFile_t);
            if (isCompatible == false)
            {
                // No, update the WatchItems and WatchElementList properies of each workset in the collection to be compatible with the new data dictionary.
                Update(ref m_WorksetCollectionFile_t);

                // Serialize the updated workset file to disk.
                Serialize(fullFilename);
            }

            // set the active workset to be the baseline workset.
            m_WorksetCollectionFile_t.ActiveIndex = 0;
        }
        /// <summary>
        /// Get a list of those worksets that contain more watch variables than the specified watch size.
        /// </summary>
        /// <param name="worksetCollectionFile">The structure containing the de-serialized workset file.</param>
        /// <param name="watchSize">The permitted number of watch variables, this is defined by the <c>WatchSize</c> field in the <c>ConfigurePTU</c> table of the 
        /// data dictionary.</param>
        /// <returns>A list of those worksets that contain more watch variables than the specified watch size.</returns>
        private static List<Workset_t> GetIncompatibleWorksetList(WorksetCollectionFile_t worksetCollectionFile, short watchSize)
        {
            List<Workset_t> incompatibleWorksetList = new List<Workset_t>();
            foreach (Workset_t workset in worksetCollectionFile.WorksetList)
            {
                // Skip the baseline workset as this is corrected automatically.
                if (workset.Name.Equals(Resources.NameBaselineWorkset))
                {
                    continue;
                }

                if (workset.Count > watchSize)
                {
                    incompatibleWorksetList.Add(workset);
                }
            }

            return incompatibleWorksetList;
        }
        /// <summary>
        /// Get a list of those worksets that contain one or more old identifier references that are not defined in the current data dictionary.
        /// </summary>
        /// <param name="worksetCollectionFile">The structure containing the de-serialized workset file.</param>
        /// <param name="incompatibleOldIdentifierList">A list of list of those old identifiers that are included in the workset file but are not defined in the 
        /// current data dictionary.</param>
        /// <returns>A list of those worksets that contain one or more old identifier references that are not defined in the current data dictionary.</returns>
        private static List<Workset_t> GetIncompatibleWorksetList(WorksetCollectionFile_t worksetCollectionFile, List<short> incompatibleOldIdentifierList)
        {
            // Generate a list of the worksets that contain the specified invalid old identifiers.
            List<Workset_t> incompatibleWorksetList = worksetCollectionFile.WorksetList.FindAll(delegate(Workset_t searchWorkset)
            {
                foreach (short value in incompatibleOldIdentifierList)
                {
                    for (int columnIndex = 0; columnIndex < searchWorkset.Column.Length; columnIndex++)
                    {
                        if (searchWorkset.Column[columnIndex].OldIdentifierList.Contains(value))
                        {
                            return true;
                        }
                    }
                }
                return false;
            });

            // Remove the baseline workset as this is corrected automatically.
            Workset_t workset = worksetCollectionFile.WorksetList[0];
            if (incompatibleWorksetList.Contains(workset) == true)
            {
                incompatibleWorksetList.Remove(workset);
            }

            return incompatibleWorksetList;
        }
        /// <summary>
        /// Get a list of those old identifiers that are included in the workset file but are not defined in the current data dictionary. 
        /// </summary>
        /// <param name="worksetCollectionFile">The structure containing the de-serialized workset file.</param>
        /// <returns>A list of those old identifiers that are included in the workset file but are not defined in the current data dictionary.</returns>
        private static List<short> GetIncompatibleOldIdentifierList(WorksetCollectionFile_t worksetCollectionFile)
        {
            // Create a list of all unique old identifiers used in the workset collection.
            List<short> oldIdentifierList = new List<short>();
            short oldIdentifier;
            for (short worksetIndex = 0; worksetIndex < worksetCollectionFile.WorksetList.Count; worksetIndex++)
            {
                for (int columnIndex = 0; columnIndex < worksetCollectionFile.WorksetList[worksetIndex].Column.Length; columnIndex++)
                {
                    for (int rowIndex = 0; rowIndex < worksetCollectionFile.WorksetList[worksetIndex].Column[columnIndex].OldIdentifierList.Count; rowIndex++)
                    {
                        oldIdentifier = worksetCollectionFile.WorksetList[worksetIndex].Column[columnIndex].OldIdentifierList[rowIndex];
                        short returnedValue = oldIdentifierList.Find(delegate(short value) { return value == oldIdentifier; });

                        if (returnedValue == 0)
                        {
                            oldIdentifierList.Add(oldIdentifier);
                        }
                    }
                }
            }

            oldIdentifierList.Sort();

            // Now check if any of the watch variables corresponding to these old identifier values are no longer defined in the database.
            List<short> invalidOldIdentifierList = new List<short>();
            WatchVariable watchVariable;
            for (int index = 0; index < oldIdentifierList.Count; index++)
            {
                try
                {
                    watchVariable = Lookup.WatchVariableTableByOldIdentifier.Items[oldIdentifierList[index]];
                    if (watchVariable == null)
                    {
                        invalidOldIdentifierList.Add(oldIdentifierList[index]);
                    }
                }
                catch (Exception)
                {
                    invalidOldIdentifierList.Add(oldIdentifierList[index]);
                }
            }

            return invalidOldIdentifierList;
        }
        /// <summary>
        /// For the specified workset file update: (a) the baseline workset; (b) the WatchItems, WatchElementList and CountMax properties of all other worksets and (c) 
        /// the EntryCountMax field to be compatible with the new data dictionary. Also report any worksets that: (a) contain more watch values than are permitted 
        /// or (b) include one or more invalid old identifier references.
        /// </summary>
        /// <param name="worksetCollectionFile">The structure containing the de-serialized workset file.</param>
        private void Update(ref WorksetCollectionFile_t worksetCollectionFile)
        {
            // Get the number of watch variables and the number of oldIdentifiers associated with the current data dictionary and the data dictionary associated with 
            // the workset.
            int dataDictionaryOldIdentifierCount = Lookup.WatchVariableTableByOldIdentifier.RecordList.Count;
            int dataDictionaryWatchIdentifierCount = Lookup.WatchVariableTable.RecordList.Count;
            int worksetOldIdentifierCount = worksetCollectionFile.WorksetList[0].WatchItems.Length;
            int worksetWatchIdentifierCount = 0;
            for (int elementIndex = 0; elementIndex < worksetOldIdentifierCount; elementIndex++)
            {
                if (worksetCollectionFile.WorksetList[0].WatchItems[elementIndex].Exists == true)
                {
                    worksetWatchIdentifierCount++;
                }
            }

            int watchVariablesAddedTo = 0;
            int watchVariablesDeletedFrom = 0;
            if (dataDictionaryOldIdentifierCount > worksetOldIdentifierCount)
            {
                watchVariablesAddedTo = dataDictionaryOldIdentifierCount - worksetOldIdentifierCount;
                watchVariablesDeletedFrom = watchVariablesAddedTo - (dataDictionaryWatchIdentifierCount - worksetWatchIdentifierCount);
            }
            else if (worksetOldIdentifierCount > dataDictionaryOldIdentifierCount)
            {
                watchVariablesDeletedFrom = worksetOldIdentifierCount - dataDictionaryOldIdentifierCount;
                watchVariablesAddedTo = watchVariablesDeletedFrom - (worksetWatchIdentifierCount - dataDictionaryWatchIdentifierCount);
            }

            // Check whether the WatchItems property of the worksets in the specified workset collection need be updated i.e. check whether any watch variables have been 
            // added to or deleted from the the data dictionary since the workset was created.
            List<short> invalidOldIdentifierList;
            List<Workset_t> invalidOldIdentifierWorksetList, invalidWatchSizeWorksetList;
            if ((dataDictionaryOldIdentifierCount != worksetOldIdentifierCount) ||
                (dataDictionaryWatchIdentifierCount != worksetWatchIdentifierCount))
            {
                #region - [Error Reporting] -
                // Check whether any watch variables have been deleted from the current data dictionary since the worksets were defined.
                if (watchVariablesDeletedFrom > 0)
                {
                    // Yes - Get a list of any old identifiers in the workset file that are incompatible with the current data dictionary.
                    invalidOldIdentifierList = GetIncompatibleOldIdentifierList(worksetCollectionFile);
                    if (invalidOldIdentifierList.Count > 0)
                    {
                        // Get the list of worksets that are effected.
                        invalidOldIdentifierWorksetList = GetIncompatibleWorksetList(worksetCollectionFile, invalidOldIdentifierList);

                        if (invalidOldIdentifierWorksetList.Count > 0)
                        {
                            ReportIncompatibleWorksets(invalidOldIdentifierWorksetList, invalidOldIdentifierList, worksetCollectionFile.WorksetCollectionType); 
                        }
                    }
                }
                #endregion - [Error Reporting] -

                #region - [WatchItems/WatchElementList Update] -
                // ------------------------------------------------------------------------------------
                // Update the WatchItems and WatchElementList fields of all of the workset in the file.
                // ------------------------------------------------------------------------------------
                for (short worksetIndex = 0; worksetIndex < worksetCollectionFile.WorksetList.Count; worksetIndex++)
                {
                    // Replicate the workset.
                    Workset_t workset = new Workset_t();
                    workset.Replicate(worksetCollectionFile.WorksetList[worksetIndex]);

                    //Create a new WatchItems propery for the current workset based upon the current data dictionary with the Added property of all elements set to false.
                    workset.WatchItems = new WatchItem_t[dataDictionaryOldIdentifierCount];
                    WatchItem_t watchItem;
                    for (short watchItemIndex = 0; watchItemIndex < dataDictionaryOldIdentifierCount; watchItemIndex++)
                    {
                        watchItem = new WatchItem_t();
                        watchItem.OldIdentifier = watchItemIndex;
                        watchItem.Added = false;

                        try
                        {
                            // Check whether the watch variable exists and set the Exists property of the watch item appropriately.
                            WatchVariable watchVariable = Lookup.WatchVariableTableByOldIdentifier.Items[watchItemIndex];
                            watchItem.Exists = (watchVariable == null) ? false : true;
                        }
                        catch (Exception)
                        {
                            watchItem.Exists = false;
                        }

                        workset.WatchItems[watchItemIndex] = watchItem;
                    }

                    // Update the WatchElementList and the WatchItems properties of the workset using the old identifier values stored in each column of the workset.
                    workset.WatchElementList = new List<short>();
                    short oldIdentifier;
                    for (int columnIndex = 0; columnIndex < workset.Column.Length; columnIndex++)
                    {
                        for (int rowIndex = 0; rowIndex < workset.Column[columnIndex].OldIdentifierList.Count; rowIndex++)
                        {
                            // Get the old identifier value.
                            oldIdentifier = workset.Column[columnIndex].OldIdentifierList[rowIndex];

                            // Check whether the watch variable associated with the old identifier value exists in the current workset.
                            try
                            {
                                WatchVariable watchVariable = Lookup.WatchVariableTableByOldIdentifier.Items[oldIdentifier];
                                if (watchVariable == null)
                                {
                                    // No, add the watch identifier value used to represent the watch variable not being defined in the current data dictionary.
                                    workset.WatchElementList.Add(CommonConstants.WatchIdentifierNotDefined);
                                }
                                else
                                {
                                    // Add the watch identifier of the watch variable corresponding to the specified old identifier to the list of watch identifiers.
                                    workset.WatchElementList.Add(watchVariable.Identifier);

                                    // Update the Exists and Added properties of the WatchItem element corresponding to the specified old identifier.
                                    workset.WatchItems[oldIdentifier].Added = true;
                                    workset.WatchItems[oldIdentifier].Exists = true;
                                }
                            }
                            catch (Exception)
                            {
                                // No, add the watch identifier value used to represent the watch variable not being defined in the current data dictionary.
                                workset.WatchElementList.Add(CommonConstants.WatchIdentifierNotDefined);
                            }
                        }
                    }

                    workset.WatchElementList.Sort();

                    // Replace the workset.
                    worksetCollectionFile.WorksetList[worksetIndex] = workset;
                    #endregion - [WatchItems/WatchElementList Update] -
                }
            }

            // Only carry out watch size processing if the workset collection corresponds to a watch window workset.
            if (worksetCollectionFile.WorksetCollectionType == Configuration.WorksetCollectionType.RecordedWatch)
            {
                #region - [Error Reporting] -
                invalidWatchSizeWorksetList = GetIncompatibleWorksetList(worksetCollectionFile, Parameter.WatchSize);
                if (invalidWatchSizeWorksetList.Count > 0)
                {
                    ReportIncompatibleWorksets(invalidWatchSizeWorksetList);
                }
                #endregion - [Error Reporting] -

                #region - [WatchSize Update] -
                // Update the EntryCountMax field of the workset file, if required.
                if (worksetCollectionFile.EntryCountMax != Parameter.WatchSize)
                {
                    worksetCollectionFile.EntryCountMax = Parameter.WatchSize;
                }

                // Update the baseline workset and the EntryCount max field of individual worksets, if required.
                for (int worksetIndex = 0; worksetIndex < worksetCollectionFile.WorksetList.Count; worksetIndex++)
                {
                    Workset_t workset;
                    if (worksetCollectionFile.WorksetList[worksetIndex].CountMax != Parameter.WatchSize)
                    {
                        // If the workset is the baseline workset, update it.
                        if (worksetIndex == 0)
                        {
                            workset = CreateBaselineWorkset();

                        }
                        else
                        {
                            workset = worksetCollectionFile.WorksetList[worksetIndex];
                            workset.CountMax = Parameter.WatchSize;
                        }

                        worksetCollectionFile.WorksetList[worksetIndex] = workset;
                    }
                }
                #endregion - [WatchSize Update] -
            }
        }
        /// <summary>
        /// Check whether the specified workset file is compatible with the current data dictionary. For the workset file to be compatible: (a) no watch variables can 
        /// have been added to or deleted from the data dictionary since the workset was created/updated and (b) the the CountMax fields of all individual worksets and 
        /// the EntryCountMax field of the <c>WorksetCollectionFile_t</c> structure must be consistent with the <c>WatchSize</c> defined in the current data dictionary.
        /// </summary>
        /// <param name="worksetCollectionFile">The workset file retrieved from disk that is to be checked.</param>
        /// <returns>A flag to indicate whether the workset file is compatible with the current data dictionary. True, if the workset file is compatible; 
        /// otherwise, false.</returns>
        private bool CheckCompatibility(WorksetCollectionFile_t worksetCollectionFile)
        {
            bool isCompatible = false;

            // Get the number of watch variables and the number of oldIdentifiers associated with the current data dictionary and the data dictionary associated with 
            // the workset.
            int dataDictionaryOldIdentifierCount = Lookup.WatchVariableTableByOldIdentifier.RecordList.Count;
            int dataDictionaryWatchIdentifierCount = Lookup.WatchVariableTable.RecordList.Count;
            int worksetOldIdentifierCount = worksetCollectionFile.WorksetList[0].WatchItems.Length;
            int worksetWatchIdentifierCount = 0;
            for (int elementIndex = 0; elementIndex < worksetOldIdentifierCount; elementIndex++)
            {
                if (worksetCollectionFile.WorksetList[0].WatchItems[elementIndex].Exists == true)
                {
                    worksetWatchIdentifierCount++;
                }
            }

            // Check whether any watch variables have been added to or deleted from the data dictionary since the workset was created.
            if ((dataDictionaryOldIdentifierCount != worksetOldIdentifierCount) ||
                (dataDictionaryWatchIdentifierCount != worksetWatchIdentifierCount))
            {
                isCompatible = false;
                return isCompatible;
            }

            // Only carry out watch size processing if the workset collection corresponds to a watch window workset.
            if (worksetCollectionFile.WorksetCollectionType == Configuration.WorksetCollectionType.RecordedWatch)
            {
                // Yes - Check whether the EntryCountMax field of the workset collection needs updating
                if (worksetCollectionFile.EntryCountMax != Parameter.WatchSize)
                {
                    isCompatible = false;
                    return isCompatible;
                }
                else
                {
                    // Check whether any of the individual workset CountMax fields need updating.
                    foreach (Workset_t workset in worksetCollectionFile.WorksetList)
                    {
                        if (workset.CountMax != Parameter.WatchSize)
                        {
                            isCompatible = false;
                            return isCompatible;
                        }
                    }
                }
            }

            isCompatible = true;
            return isCompatible;
        }