/// <summary>
        /// Check tt element validity
        /// </summary>
        protected override void ValidElements()
        {
            bool isValid = true;

            // we need an extra check to validate the root attributes in order
            // to ensure parameters are parsed.
            ValidAttributes();

            #region check this elements model
            switch (Children.Count)
            {
            case 0:
                return;

            case 1:
            {
                #region test if child element is head or body
                if (Children[0] is HeadElement)
                {
                    m_head  = Children[0] as HeadElement;
                    isValid = true;
                }
                else if (Children[0] is BodyElement)
                {
                    m_body = Children[0] as BodyElement;
                    m_head = new HeadElement();
                    Children.Clear();
                    Children.Add(m_head);
                    Children.Add(m_body);
                    isValid = true;
                }
                else
                {
                    isValid = false;
                }
                #endregion
            }
            break;

            case 2:
            {
                #region Check first child is head, and second is body
                if (Children[0] is HeadElement)
                {
                    m_head = Children[0] as HeadElement;
                }
                if (Children[1] is BodyElement)
                {
                    m_body = Children[1] as BodyElement;
                }
                else
                {
                    isValid = (m_body != null && m_head != null);
                }
                #endregion
            }
            break;

            default:
            {
                #region Cannot be valid
                isValid = false;
                #endregion
            }
            break;
            }
            #endregion

            if (!isValid)
            {
                Error("erroneous child in " + this.ToString());
            }

            #region now check each of the children is individually valid
            foreach (TimedTextElementBase element in Children)
            {
                element.Valid();
            }
            #endregion

            #region Add default region if none was specified
            if (isValid && Regions.Count < 1)
            {
                LayoutElement defaultLayout = new LayoutElement();
                defaultLayout.LocalName = "layout";
                defaultLayout.Namespace = m_head.Namespace;

                m_head.Children.Add(defaultLayout);
                defaultLayout.Parent = m_head;
                RegionElement defaultRegion = new RegionElement();
                defaultRegion.SetLocalStyle("backgroundColor", "black");
                defaultRegion.SetLocalStyle("color", "white");
                defaultLayout.Children.Add(defaultRegion);
                defaultRegion.Parent           = defaultLayout;
                defaultRegion.Id               = RegionElement.DefaultRegionName;
                Root.Regions[defaultRegion.Id] = defaultRegion;
            }
            #endregion
        }
        private static TimedTextElement BuildTimedTextElements(TimedTextElementBase element, RegionElement region)
        {
            TimedTextElement timedTextElement = CreateTimedTextElement(element, region);

            foreach (TimedTextElementBase c in element.Children)
            {
                TimedTextElement child = BuildTimedTextElements(c, region);
                if (child is TimedTextAnimation)
                {
#if HACK_XAMLTYPEINFO
                    var children = timedTextElement.Animations as MediaMarkerCollection<TimedTextAnimation>;
#else
                    var children = timedTextElement.Animations;
#endif
                    children.Add((TimedTextAnimation)child);
                }
                else if (timedTextElement is CaptionElement && child is CaptionElement)
                {
#if HACK_XAMLTYPEINFO
                    var children = timedTextElement.Children as MediaMarkerCollection<TimedTextElement>;
#else
                    var children = timedTextElement.Children;
#endif
                    ((CaptionElement)child).Index = children.Count;
                    children.Add((CaptionElement)child);
                }
            }

            return timedTextElement;
        }
        private static TimedTextElement CreateTimedTextElement(TimedTextElementBase element, RegionElement region)
        {
            var captionElement = element is SetElement
                                    ? (TimedTextElement)BuildCaptionAnimationElement(element)
                                    : new CaptionElement();

            var endTime = element.End.TotalSeconds >= TimeSpan.MaxValue.TotalSeconds
                ? TimeSpan.MaxValue
                : TimeSpan.FromSeconds(element.End.TotalSeconds);

            captionElement.End = endTime;
            captionElement.Begin = TimeSpan.FromSeconds(element.Begin.TotalSeconds);

            if (element is BrElement)
            {
                captionElement.CaptionElementType = TimedTextElementType.LineBreak;
            }
            else if (element is AnonymousSpanElement)
            {
                var span = element as AnonymousSpanElement;
                captionElement.CaptionElementType = TimedTextElementType.Text;
                captionElement.Content = HttpUtility.HtmlDecode(span.Text);
                captionElement.Style = TimedTextStyleParser.MapStyle(element, region);
            }
            else if (!(element is SetElement))
            {
                captionElement.CaptionElementType = TimedTextElementType.Container;
                captionElement.Style = TimedTextStyleParser.MapStyle(element, region);
            }

            return captionElement;
        }
        private static CaptionElement MapToCaption(PElement pElement, RegionElement region)
        {
            var captionElement = BuildTimedTextElements(pElement, region);
            captionElement.Id = pElement.Id ?? Guid.NewGuid().ToString();

            return captionElement as CaptionElement;
        }
        private static CaptionRegion MapToCaptionRegion(RegionElement regionElement)
        {
            var endTime = regionElement.End.TotalSeconds >= TimeSpan.MaxValue.TotalSeconds
                            ? TimeSpan.MaxValue
                            : TimeSpan.FromSeconds(regionElement.End.TotalSeconds);

            var captionRegion = new CaptionRegion
            {
                Id = regionElement.Id,
                Begin = TimeSpan.FromSeconds(regionElement.Begin.TotalSeconds),
                End = endTime,
                Style = TimedTextStyleParser.MapStyle(regionElement, null),
                TunneledData = regionElement.Root.Images.ToDictionary(ie => ie.Key, ie => new TunneledData() { Data = ie.Value.Data, Encoding = ie.Value.Encoding, MimeType = ie.Value.ImageType })
            };



            foreach (TimedTextElementBase element in regionElement.Children)
            {
                TimedTextElement child = BuildTimedTextElements(element, null);
                if (child != null && child.CaptionElementType == TimedTextElementType.Animation)
                {
#if HACK_XAMLTYPEINFO
                    var children = captionRegion.Animations as MediaMarkerCollection<TimedTextAnimation>;
#else
                    var children = captionRegion.Animations;
#endif
                    children.Add(child as TimedTextAnimation);
                }
            }

            return captionRegion;
        }
        private static TimedTextElement BuildTimedTextElements(TimedTextElementBase element, RegionElement region)
        {
            TimedTextElement timedTextElement = CreateTimedTextElement(element, region);

            foreach (TimedTextElementBase c in element.Children)
            {
                TimedTextElement child = BuildTimedTextElements(c, region);
                if (child is TimedTextAnimation)
                {
                    timedTextElement.Animations.Add((TimedTextAnimation)child);
                }
                else if (timedTextElement is CaptionElement && child is CaptionElement)
                {
                    ((CaptionElement)child).Index = timedTextElement.Children.Count;
                    timedTextElement.Children.Add((CaptionElement)child);
                }
            }

            return timedTextElement;
        }
        private static CaptionRegion MapToCaptionRegion(RegionElement regionElement)
        {
            var endTime = regionElement.End.TotalSeconds >= TimeSpan.MaxValue.TotalSeconds
                            ? TimeSpan.MaxValue
                            : TimeSpan.FromSeconds(regionElement.End.TotalSeconds);

            var captionRegion = new CaptionRegion
            {
                Id = regionElement.Id,
                Begin = TimeSpan.FromSeconds(regionElement.Begin.TotalSeconds),
                End = endTime,
                Style = TimedTextStyleParser.MapStyle(regionElement, null)
            };

            foreach (TimedTextElementBase element in regionElement.Children)
            {
                TimedTextElement child = BuildTimedTextElements(element, null);
                if (child != null && child.CaptionElementType == TimedTextElementType.Animation)
                {
                    captionRegion.Animations.Add(child as TimedTextAnimation);
                }
            }

            return captionRegion;
        }
        /// <summary>
        /// Check tt element validity
        /// </summary>
        protected override void ValidElements()
        {
            bool isValid = true;
            // we need an extra check to validate the root attributes in order
            // to ensure parameters are parsed.
            ValidAttributes();

            #region check this elements model
            switch (Children.Count)
            {
                case 0:
                    return;
                case 1:
                    {
                        #region test if child element is head or body
                        if (Children[0] is HeadElement)
                        {
                            m_head = Children[0] as HeadElement;
                            isValid = true;
                        }
                        else if (Children[0] is BodyElement)
                        {
                            m_body = Children[0] as BodyElement;
                            m_head = new HeadElement();
                            Children.Clear();
                            Children.Add(m_head);
                            Children.Add(m_body);
                            isValid = true;
                        }
                        else
                        {
                            isValid = false;
                        }
                        #endregion
                    }
                    break;
                case 2:
                    {
                        #region Check first child is head, and second is body
                        if (Children[0] is HeadElement)
                        {
                            m_head = Children[0] as HeadElement;
                        }
                        if (Children[1] is BodyElement)
                        {
                            m_body = Children[1] as BodyElement;
                        }
                        else
                        {
                            isValid = (m_body != null && m_head != null);
                        }
                        #endregion
                    }
                    break;
                default:
                    {
                        #region Cannot be valid
                        isValid = false;
                        #endregion
                    }
                    break;
            }
            #endregion

            if (!isValid)
            {
                Error("erroneous child in " + this.ToString());
            }

            #region now check each of the children is individually valid
            foreach (TimedTextElementBase element in Children)
            {
                element.Valid();
            }
            #endregion

            #region Add default region if none was specified
            if (isValid && Regions.Count < 1)
            {
                LayoutElement defaultLayout = new LayoutElement();
                defaultLayout.LocalName = "layout";
                defaultLayout.Namespace = m_head.Namespace;

                m_head.Children.Add(defaultLayout);
                defaultLayout.Parent = m_head;
                RegionElement defaultRegion = new RegionElement();
                defaultRegion.SetLocalStyle("backgroundColor", "black");
                defaultRegion.SetLocalStyle("color", "white");
                defaultLayout.Children.Add(defaultRegion);
                defaultRegion.Parent = defaultLayout;
                defaultRegion.Id = RegionElement.DefaultRegionName;
                Root.Regions[defaultRegion.Id] = defaultRegion;
            }
            #endregion

        }