/// <summary>
        /// Choose an IAnnotationComponent for a given IAttachedAnnotation.  Implementation in AnnotationComponentChooser knows
        /// about all out-of-box IAnnotationComponents.  The default mapping will be stated here later.
        /// Subclasses can overwrite this method to return application specific mapping.
        /// Note: In future release this method should be made virtual.
        /// </summary>
        /// <param name="attachedAnnotation">The IAttachedAnnotation that needs an IAnnotationComponent </param>
        /// <returns></returns>
        public IAnnotationComponent ChooseAnnotationComponent(IAttachedAnnotation attachedAnnotation)
        {           
            if (attachedAnnotation == null) throw new ArgumentNullException("attachedAnnotation");
                                    
            IAnnotationComponent ac = null;

            // Text StickyNote
            if (attachedAnnotation.Annotation.AnnotationType == StickyNoteControl.TextSchemaName)
            {
                ac = new StickyNoteControl(StickyNoteType.Text) as IAnnotationComponent;
            }
            // Ink StickyNote
            else if (attachedAnnotation.Annotation.AnnotationType == StickyNoteControl.InkSchemaName)
            {
                ac = new StickyNoteControl(StickyNoteType.Ink) as IAnnotationComponent;
            }
            // Highlight
            else if (attachedAnnotation.Annotation.AnnotationType == HighlightComponent.TypeName)
            {
                ac = new HighlightComponent() as IAnnotationComponent;
            }

            return ac;
        }
        /// <summary>
        /// Update the metadata tokens specified in token.
        /// </summary>
        private static void UpdateMetaData(XmlToken token, StickyNoteControl snc, SNCAnnotation sncAnnotation)
        {
            bool newCargo, newRoot;
            AnnotationResource cargo;
            XmlElement root;

            GetCargoAndRoot(sncAnnotation, XmlToken.MetaData, out cargo, out root, out newCargo, out newRoot);

            // Update Expanded
            if ((token & XmlToken.IsExpanded) != 0)
            {
                bool expanded = snc.IsExpanded;
                sncAnnotation.UpdateAttribute(root, XmlToken.IsExpanded, expanded.ToString(CultureInfo.InvariantCulture));
            }

            // Update Height
            if ((token & XmlToken.Height) != 0)
            {
                Debug.Assert(snc.IsExpanded);
                double height = (double)snc.GetValue(FrameworkElement.HeightProperty);
                sncAnnotation.UpdateAttribute(root, XmlToken.Height, height.ToString(CultureInfo.InvariantCulture));
            }

            // Update Width
            if ((token & XmlToken.Width) != 0)
            {
                Debug.Assert(snc.IsExpanded);
                double width = (double)snc.GetValue(FrameworkElement.WidthProperty);
                sncAnnotation.UpdateAttribute(root, XmlToken.Width, width.ToString(CultureInfo.InvariantCulture));
            }

            // Update Left
            if ((token & XmlToken.Left) != 0)
            {
                double left = snc.PositionTransform.X;
                // All 'left' values are persisted assuming two things:
                //  1) the top-left corner (visually) of the StickyNote is the origin of its coordinate space
                //  2) the positive x-axis of its parent is to the right
                // This flag signals that we have a positive x-axis to the left and our
                // top-right corner (visually) is our origin.  So we need to flip the
                // value before persisting it.
                if (snc.FlipBothOrigins)
                {
                    left = -(left + snc.Width);
                }
                sncAnnotation.UpdateAttribute(root, XmlToken.Left, left.ToString(CultureInfo.InvariantCulture));
            }

            // Update Top
            if ((token & XmlToken.Top) != 0)
            {
                sncAnnotation.UpdateAttribute(root, XmlToken.Top, snc.PositionTransform.Y.ToString(CultureInfo.InvariantCulture));
            }

            // Update XOffset
            if ((token & XmlToken.XOffset) != 0)
            {
                sncAnnotation.UpdateAttribute(root, XmlToken.XOffset, snc.XOffset.ToString(CultureInfo.InvariantCulture));
            }

            // Update YOffset
            if ((token & XmlToken.YOffset) != 0)
            {
                sncAnnotation.UpdateAttribute(root, XmlToken.YOffset, snc.YOffset.ToString(CultureInfo.InvariantCulture));
            }

            // Update ZOrder
            if ((token & XmlToken.ZOrder) != 0)
            {
                sncAnnotation.UpdateAttribute(root, XmlToken.ZOrder, ((IAnnotationComponent)snc).ZOrder.ToString(CultureInfo.InvariantCulture));
            }

            if (newRoot)
            {
                cargo.Contents.Add(root);
            }
            if (newCargo)
            {
                sncAnnotation._annotation.Cargos.Add(cargo);
            }
        }
        /// <summary>
        /// This static method will update a StickyNoteControl object with the specified data in an Annotation
        /// </summary>
        /// <param name="token">A flag which indicates the data needs to be updated. The flag can be combinated with the any valid bits.</param>
        /// <param name="snc">A StickyNoteControl instance</param>
        /// <param name="sncAnnotation">An SNCAnnotation object which contains a CAF annotation object</param>
        public static void UpdateStickyNoteControl(XmlToken token, StickyNoteControl snc, SNCAnnotation sncAnnotation)
        {
            Invariant.Assert((token & AllValues) != 0, "No token specified.");
            Invariant.Assert(snc != null, "Sticky Note Control is null.");
            Invariant.Assert(sncAnnotation != null, "Annotation is null.");

            // 




            XmlAttribute node;

            // Update Ink
            if ((token & XmlToken.Ink) != 0 && sncAnnotation.HasInkData)
            {
                sncAnnotation.UpdateContent(snc, false, XmlToken.Ink);
            }

            // Update Text
            if ((token & XmlToken.Text) != 0 && sncAnnotation.HasTextData)
            {
                sncAnnotation.UpdateContent(snc, false, XmlToken.Text);
            }

            // Update Author
            if ((token & XmlToken.Author) != 0)
            {
                int nCount = sncAnnotation._annotation.Authors.Count;
                // Get the culture specific text separator.
                string listSeparator = snc.Language.GetSpecificCulture().TextInfo.ListSeparator;
                string authors = string.Empty;
                for (int i = 0; i < nCount; i++)
                {
                    if (i != 0)
                    {
                        authors += listSeparator + sncAnnotation._annotation.Authors[i];
                    }
                    else
                    {
                        authors += sncAnnotation._annotation.Authors[i];
                    }
                }

                // Setting the author property will cause the UI to update
                snc.SetValue(StickyNoteControl.AuthorPropertyKey, authors);
            }

            // Update Height
            if ((token & XmlToken.Height) != 0)
            {
                node = (XmlAttribute)sncAnnotation.FindData(XmlToken.Height);
                if (node != null)
                {
                    double height = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture);
                    snc.SetValue(FrameworkElement.HeightProperty, height);
                }
                else
                {
                    snc.ClearValue(FrameworkElement.HeightProperty);
                }
            }

            // Update Width
            if ((token & XmlToken.Width) != 0)
            {
                node = (XmlAttribute)sncAnnotation.FindData(XmlToken.Width);
                if (node != null)
                {
                    double width = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture);
                    snc.SetValue(FrameworkElement.WidthProperty, width);
                }
                else
                {
                    snc.ClearValue(FrameworkElement.WidthProperty);
                }
            }

            // Update IsExpanded
            if ((token & XmlToken.IsExpanded) != 0)
            {
                node = (XmlAttribute)sncAnnotation.FindData(XmlToken.IsExpanded);
                if (node != null)
                {
                    bool expanded = Convert.ToBoolean(node.Value, CultureInfo.InvariantCulture);
                    snc.IsExpanded = expanded;
                }
                else
                {
                    snc.ClearValue(StickyNoteControl.IsExpandedProperty);
                }
            }

            // Update ZOrder
            if ((token & XmlToken.ZOrder) != 0)
            {
                node = (XmlAttribute)sncAnnotation.FindData(XmlToken.ZOrder);
                if (node != null)
                {
                    ((IAnnotationComponent)snc).ZOrder = Convert.ToInt32(node.Value, CultureInfo.InvariantCulture);
                }
            }

            // Update Position
            if ((token & PositionValues) != 0)
            {
                TranslateTransform transform = new TranslateTransform();
                if ((token & XmlToken.Left) != 0)
                {
                    node = (XmlAttribute)sncAnnotation.FindData(XmlToken.Left);
                    if (node != null)
                    {
                        double left = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture);
                        // All 'left' values are persisted assuming two things:
                        //  1) the top-left corner (visually) of the StickyNote is the origin of its coordinate space
                        //  2) the positive x-axis of its parent is to the right
                        // This flag signals that we have a positive x-axis to the left and our
                        // top-right corner (visually) is our origin.  So we need to flip the
                        // value before using it.
                        if (snc.FlipBothOrigins)
                        {
                            left = -(left + snc.Width);
                        }
                        transform.X = left;
                    }
                }

                if ((token & XmlToken.Top) != 0)
                {
                    node = (XmlAttribute)sncAnnotation.FindData(XmlToken.Top);
                    if (node != null)
                    {
                        double top = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture);
                        transform.Y = top;
                    }
                }

                // Now, we update the StickyNote offset
                if ((token & XmlToken.XOffset) != 0)
                {
                    node = (XmlAttribute)sncAnnotation.FindData(XmlToken.XOffset);
                    if (node != null)
                    {
                        snc.XOffset = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture);
                    }
                }

                if ((token & XmlToken.YOffset) != 0)
                {
                    node = (XmlAttribute)sncAnnotation.FindData(XmlToken.YOffset);
                    if (node != null)
                    {
                        snc.YOffset = Convert.ToDouble(node.Value, CultureInfo.InvariantCulture);
                    }
                }

                // Set the adorner layer transform.
                snc.PositionTransform = transform;
            }
        }
        // Update ink data from/to SNC.
        private void UpdateContent(StickyNoteControl snc, bool updateAnnotation, XmlToken token)
        {
            Invariant.Assert(snc != null, "Sticky Note Control is null.");
            Invariant.Assert((token & AllContents) != 0, "No token specified.");

            StickyNoteContentControl contentControl = snc.Content;

            // Template hasn't been applied yet.  Once it has the content control will then be setup.
            if (contentControl == null)
            {
                return;
            }

            // Check whether the annotation data matches the content control.
            if ((token == XmlToken.Ink && contentControl.Type != StickyNoteType.Ink)
                || (token == XmlToken.Text && contentControl.Type != StickyNoteType.Text))
            {
                Debug.Assert(false, "The annotation data does match with the current content control in StickyNote");
                return;
            }

            XmlElement root = null;

            if (updateAnnotation)
            {
                // Update annotation from SNC

                AnnotationResource cargo = null;
                bool newRoot = false;
                bool newCargo = false;

                // Check if the text is empty.
                if (!contentControl.IsEmpty)
                {
                    GetCargoAndRoot(this, token, out cargo, out root, out newCargo, out newRoot);
                    contentControl.Save(root);
                }
                else
                {
                    string cargoName = GetCargoName(token);
                    cargo = FindCargo(cargoName);
                    if (cargo != null)
                    {
                        _annotation.Cargos.Remove(cargo);
                        _cachedXmlElements.Remove(token);
                    }
                }
                if (newRoot)
                {
                    Invariant.Assert(root != null, "XmlElement should have been created.");
                    Invariant.Assert(cargo != null, "Cargo should have been retrieved.");
                    cargo.Contents.Add(root);
                }
                if (newCargo)
                {
                    Invariant.Assert(cargo != null, "Cargo should have been created.");
                    _annotation.Cargos.Add(cargo);
                }
            }
            else
            {
                // Update SNC from annotation

                // Check if we have the text data in the xml store.
                XmlElement node = (XmlElement)FindData(token);
                if (node != null)
                {
                    contentControl.Load(node);
                }
                else
                {
                    if (!contentControl.IsEmpty)
                    {
                        contentControl.Clear();
                    }
                }
            }
        }
        //-------------------------------------------------------------------------------
        //
        // Public Methods
        //
        //-------------------------------------------------------------------------------

        #region Public Methods

        /// <summary>
        /// This static method will update an Annotation object with the specified data in a StickyNoteControl
        /// </summary>
        /// <param name="token">A flag which indicates the data needs to be updated. The flag can be combinated with the any valid bits.</param>
        /// <param name="snc">A StickyNoteControl instance</param>
        /// <param name="sncAnnotation">An SNCAnnotation object which contains a CAF annotation object</param>
        public static void UpdateAnnotation(XmlToken token, StickyNoteControl snc, SNCAnnotation sncAnnotation)
        {
            AnnotationService service = null;
            bool autoFlush = false;
            try
            {
                service = AnnotationService.GetService(((IAnnotationComponent)snc).AnnotatedElement);
                if (service != null && service.Store != null)
                {
                    autoFlush = service.Store.AutoFlush;
                    // Temporarily turn off autoflush until we are done
                    // updating all the necessary values
                    service.Store.AutoFlush = false;
                }

                Debug.Assert((token & AllValues) != 0);

                // Update Ink
                if ((token & XmlToken.Ink) != 0 && snc.Content.Type == StickyNoteType.Ink)
                {
                    sncAnnotation.UpdateContent(snc, true, XmlToken.Ink);
                }

                // Update Text
                if ((token & XmlToken.Text) != 0 && snc.Content.Type == StickyNoteType.Text)
                {
                    sncAnnotation.UpdateContent(snc, true, XmlToken.Text);
                }


                // Update MetaData
                if ((token & NegativeAllContents) != 0)
                {
                    UpdateMetaData(token, snc, sncAnnotation);
                }
            }
            finally
            {
                if (service != null && service.Store != null)
                {
                    // If auto flush was true before, setting it to true again should cause a flush.
                    service.Store.AutoFlush = autoFlush;
                }
            }
        }