/// <summary>
        /// These messages give us the structure of the decks used.  They don't cause any
        /// navigation themselves, but the information contained is important later.
        /// </summary>
        /// <param name="tocem"></param>
        internal List <object> AddTableOfContentsEntry(CP3Msgs.TableOfContentsEntryMessage tocem)
        {
            string w;
            Guid   slideId = toc.AddTableOfContentsEntry(tocem, Guid.Empty, CP3.Model.Presentation.DeckDisposition.Whiteboard, out w);

            if ((w != null) && (w != ""))
            {
                warning += w + "  ";
            }
            else if (!slideId.Equals(Guid.Empty))
            {
                return(getCachedStrokes(slideId));
            }
            return(null);
        }
        /// <summary>
        /// Add a TOC entry.  If message.Parent.Parent is a DeckInformationMessage, the values of
        /// deckID and Disposition contained in that message will override any values given as parameters.
        /// Return the slideId if a new entry was added, else Guid.Empty
        /// </summary>
        /// <param name="tocem"></param>
        /// <param name="deckId"></param>
        /// <param name="disposition"></param>
        /// <param name="warning"></param>
        public Guid AddTableOfContentsEntry(CP3Msgs.TableOfContentsEntryMessage tocem,
                                            Guid deckId, CP3.Model.Presentation.DeckDisposition disposition, out string warning)
        {
            warning = null;
            Guid deckIdentifier = deckId;

            if ((tocem.Parent.Parent != null) && (tocem.Parent.Parent is CP3Msgs.DeckInformationMessage))
            {
                deckIdentifier = (Guid)tocem.Parent.Parent.TargetId;
                disposition    = ((CP3Msgs.DeckInformationMessage)tocem.Parent.Parent).Disposition;
            }

            if (deckIdentifier.Equals(Guid.Empty))
            {
                //If we don't know the deckID, skip.
                //warning = "Failed to add TOC entry because deck id is Guid.Empty";
                if (tocem.Parent is CP3Msgs.SlideInformationMessage)
                {
                    Debug.WriteLine("*****Failed to add TOC entry because deck id is Guid.Empty.  Slide ID=" + tocem.Parent.TargetId.ToString());
                }
                else
                {
                    Debug.WriteLine("*****Failed to add TOC entry because deck id is Guid.Empty.");
                }
                return(Guid.Empty);
            }

            if (!deckIds.Contains(deckIdentifier))
            {
                deckIds.Add(deckIdentifier);
            }

            if ((tocem.Parent is CP3Msgs.SlideInformationMessage) &&
                (tocem.PathFromRoot.Length == 1))
            {
                bool added = true;
                if (toc.ContainsKey(tocem.TargetId))
                {
                    Debug.WriteLine("Replacing Toc entry with id = " + tocem.TargetId.ToString());
                    toc.Remove(tocem.TargetId);
                    added = false;
                }
                if (tocBySlideId.ContainsKey(tocem.Parent.TargetId))
                {
                    tocBySlideId.Remove(tocem.Parent.TargetId);
                }
                TocEntry newEntry = new TocEntry(tocem, deckIdentifier, disposition, this.ssDeckId);
                Debug.WriteLine("*** New " + newEntry.ToString());
                toc.Add(tocem.TargetId, newEntry);
                tocBySlideId.Add(tocem.Parent.TargetId, newEntry);
                if (added)
                {
                    return((Guid)tocem.Parent.TargetId);
                }
                return(Guid.Empty);
            }
            else
            {
                if (tocem.PathFromRoot.Length != 1)
                {
                    //PathFromRoot defines the location of the Parent slide node in a tree structure.  This in turn defines the slide index.
                    string dbgstr = "";
                    for (int i = 0; i < tocem.PathFromRoot.Length; i++)
                    {
                        dbgstr += tocem.PathFromRoot[i].ToString() + " ";
                    }
                    warning = "Warning: TOC trees of depth greater than one are not yet supported: " +
                              "TableOfContentsEntryMessage: PathFromRoot len=" + tocem.PathFromRoot.Length.ToString() +
                              "; value=" + dbgstr + "; id=" + tocem.TargetId.ToString() + "; parent id=" + tocem.Parent.TargetId.ToString() +
                              "; parent parent id=" + tocem.Parent.Parent.TargetId.ToString();
                }
            }
            return(Guid.Empty);
        }
            public TocEntry(CP3Msgs.TableOfContentsEntryMessage tocem, Guid deckid, CP3.Model.Presentation.DeckDisposition disposition, Guid ssDeckId)
            {
                deckAssociation          = Guid.Empty;
                associationSlideId       = Guid.Empty;
                this.deckTypeAssociation = DeckTypeEnum.Undefined;
                slideAssociation         = -1;
                deckId = deckid;

                deckType = DeckTypeEnum.Presentation;

                if ((disposition & CP3.Model.Presentation.DeckDisposition.Whiteboard) != 0)
                {
                    deckType = DeckTypeEnum.Whiteboard;
                }
                if ((disposition & CP3.Model.Presentation.DeckDisposition.StudentSubmission) != 0)
                {
                    deckType = DeckTypeEnum.StudentSubmission;
                    if (!ssDeckId.Equals(Guid.Empty))
                    {
                        deckId = ssDeckId;
                    }
                }
                if ((disposition & CP3.Model.Presentation.DeckDisposition.QuickPoll) != 0)
                {
                    deckType = DeckTypeEnum.QuickPoll;
                }

                slideId = (Guid)tocem.Parent.TargetId;

                //Debug code:
                //if (slideId.Equals(new Guid("96c09fe9-f0be-4421-9cf4-7d26032382a1"))) {
                //    Debug.WriteLine("Found slide.");
                //}

                title     = ((CP3Msgs.SlideInformationMessage)tocem.Parent).Title;
                slideSize = ((CP3Msgs.SlideInformationMessage)tocem.Parent).Zoom;

                ///If this is Color.Empty then the slide will use the Deck background color.  If that one is also
                ///Color.Empty, then it will default to white.
                backgroundColor = ((CP3Msgs.SlideInformationMessage)tocem.Parent).SlideBackgroundColor;

                associationSlideId = ((CP3Msgs.SlideInformationMessage)tocem.Parent).AssociationSlideId;
                if (tocem.PathFromRoot.Length == 1)
                {
                    slideIndex = tocem.PathFromRoot[0]; //This is a zero-based index.
                }

                if (!associationSlideId.Equals(Guid.Empty))
                {
                    //About CP3 build 1603 we added a message extension to help map SS slides back to the source slide in the presentation.
                    CP3Msgs.SlideInformationMessage sim = (CP3Msgs.SlideInformationMessage)tocem.Parent;
                    if (sim.Extension != null)
                    {
                        CP3.Misc.ExtensionWrapper extw = sim.Extension as CP3.Misc.ExtensionWrapper;
                        if (extw != null)
                        {
                            if (extw.ExtensionType.Equals(CP3Msgs.SlideAssociationExtension.ExtensionId))
                            {
                                CP3Msgs.SlideAssociationExtension assnExt = (CP3Msgs.SlideAssociationExtension)(extw.ExtensionObject);
                                this.associationSlideId = assnExt.SlideID;
                                this.deckAssociation    = assnExt.DeckID;
                                this.slideAssociation   = assnExt.SlideIndex;
                                if ((assnExt.DeckType & CP3.Model.Presentation.DeckDisposition.StudentSubmission) != 0)
                                {
                                    this.deckTypeAssociation = DeckTypeEnum.StudentSubmission;
                                }
                                if ((assnExt.DeckType & CP3.Model.Presentation.DeckDisposition.Whiteboard) != 0)
                                {
                                    this.deckTypeAssociation = DeckTypeEnum.Whiteboard;
                                }
                                if ((assnExt.DeckType & CP3.Model.Presentation.DeckDisposition.QuickPoll) != 0)
                                {
                                    this.deckTypeAssociation = DeckTypeEnum.QuickPoll;
                                }
                                if (assnExt.DeckType == CP3.Model.Presentation.DeckDisposition.Empty)
                                {
                                    this.deckTypeAssociation = DeckTypeEnum.Presentation;
                                }
                            }
                        }
                    }
                }
            }