/// <summary>
        /// Parses the view count history.
        /// </summary>
        /// <param name="element">The DIV element.</param>
        private void ParseHtmlStatsBigChart(XElement element)
        {
            // Search all IMG child elements.
            foreach (XElement img in element.Elements(XName.Get("img")))
            {
                // Get the element CLASS attribute.
                XAttribute attribute = img.Attribute(XName.Get("class"));

                // If the element has a CLASS attribute.
                if (null != attribute)
                {
                    switch (attribute.Value)
                    {
                        case "stats-big-chart-expanded":
                            this.ViewsHistory = AjaxViewsHistory.Parse(img.Attribute(XName.Get("src")).Value);
                            break;
                    }
                }
            }
        }
        /// <summary>
        /// Displays the history variation for the current statistics.
        /// </summary>
        /// <param name="history">The views history.</param>
        /// <param name="axisX">The X axis.</param>
        /// <param name="axisY">The Y axis.</param>
        private void DisplayHistoryVariation(AjaxViewsHistory history, string axisX, string axisY)
        {
            if (null == history) return;

            this.chart.Series.Clear();
            this.chart.Annotations.Clear();
            this.listViewDiscovery.Items.Clear();

            // Update the chart.
            Series series = new Series("Video {0}".FormatWith(this.textBox));
            series.ChartType = SeriesChartType.Line;
            series.XValueType = ChartValueType.DateTime;
            series.YValueType = ChartValueType.Int32;
            series.Font = new Font(this.Font.FontFamily, this.Font.Size, this.Font.Style);
            series.MarkerStyle = MarkerStyle.Circle;

            DateTime[] time = new DateTime[history.Series.Length - 1];
            double[] popularity = new double[history.Series.Length - 1];
            for (int index = 1; index < history.Series.Length; index++)
            {
                TimeSpan dx = history.Series[index].Time - history.Series[index - 1].Time;
                time[index - 1] = new DateTime((history.Series[index].Time.Ticks + history.Series[index - 1].Time.Ticks) / 2);
                double dy = history.Series[index].Value - history.Series[index - 1].Value;
                popularity[index - 1] = dy / dx.TotalDays;

                series.Points.AddXY(time[index - 1], popularity[index - 1]);
            }

            this.chart.Series.Add(series);
            this.chart.ChartAreas[0].AxisX.Title = axisX;
            this.chart.ChartAreas[0].AxisY.Title = axisY;

            AjaxHistoryMarker? lastMarker = null;
            RectangleAnnotation lastAnnotation = null;

            // For all markers.
            foreach (AjaxHistoryMarker marker in history.Markers)
            {
                // Get the history point closest to the marker.
                AjaxHistoryPoint? point = history.GetPointAt(marker);

                // If the point does not exist, continue.
                if (null == point) continue;

                // Get index of the point.
                int index = Array.IndexOf<AjaxHistoryPoint>(history.Series, point.Value);

                // If the index is not found, skip the point.
                if (-1 == index) continue;

                // If the index is greater than the number of popularity points, limit the index to the size of the popularity array.
                if (index >= popularity.Length) index = popularity.Length - 1;

                // If the last marker and last annotation exist.
                if ((lastMarker != null) && (lastAnnotation != null))
                {
                    // If the last marker has the same date with the current one, only update the annotation text.
                    if (lastMarker.Value.Time == marker.Time)
                    {
                        lastAnnotation.Text += " " + marker.Name;
                        continue;
                    }
                }

                RectangleAnnotation rect = new RectangleAnnotation();
                rect.Text = marker.Name;
                rect.ForeColor = Color.Black;
                rect.AxisX = this.chart.ChartAreas[0].AxisX;
                rect.AxisY = this.chart.ChartAreas[0].AxisY;
                rect.AnchorX = time[index].ToOADate();
                rect.AnchorY = popularity[index];
                rect.AnchorOffsetX = 0;
                rect.AnchorOffsetY = 5;
                rect.ShadowColor = Color.Gray;
                rect.ShadowOffset = 5;

                VerticalLineAnnotation line = new VerticalLineAnnotation();
                line.AxisX = this.chart.ChartAreas[0].AxisX;
                line.AxisY = this.chart.ChartAreas[0].AxisY;
                line.AnchorX = time[index].ToOADate();
                line.AnchorY = popularity[index];
                line.Height = -5;

                this.chart.Annotations.Add(line);
                this.chart.Annotations.Add(rect);
                this.chart.ResetAutoValues();

                lastAnnotation = rect;
                lastMarker = marker;
            }

            // Add discovery events.
            foreach (KeyValuePair<string, AjaxViewsHistoryDiscoveryEvent> evt in history.DiscoveryEvents)
            {
                ListViewItem item = new ListViewItem(new string[] {
                        evt.Value.Name,
                        evt.Value.Marker != null ? evt.Value.Marker.Value.Time.ToString() : "Unknown",
                        AjaxViewsHistoryDiscoveryEvent.GetTypeDescription(evt.Value.Type),
                        evt.Value.Extra != null ? evt.Value.Extra : string.Empty }, 0);
                item.Tag = evt.Value;

                this.listViewDiscovery.Items.Add(item);
            }
        }
 /// <summary>
 /// Parses a string containing history data in Google chart format, and creates a history object.
 /// </summary>
 /// <param name="data">A string containing history data in Google chart format.</param>
 /// <returns>A history object</returns>
 public static new AjaxViewsHistory Parse(string data)
 {
     AjaxViewsHistory history = new AjaxViewsHistory(ChartType.Lc);
     history.ParseSeries(data);
     return history;
 }
        /// <summary>
        /// Displays the history for the current statistics.
        /// </summary>
        /// <param name="history">The views history.</param>
        /// <param name="axisX">The X axis.</param>
        /// <param name="axisY">The Y axis.</param>
        private void DisplayHistory(AjaxViewsHistory history, string axisX, string axisY)
        {
            if (null == history) return;

            this.chart.Series.Clear();
            this.chart.Annotations.Clear();
            this.listViewDiscovery.Items.Clear();

            // Update the chart.
            Series series = new Series("Video {0}".FormatWith(this.textBox));
            series.ChartType = SeriesChartType.Line;
            series.XValueType = ChartValueType.DateTime;
            series.YValueType = ChartValueType.Int32;
            series.Font = new Font(this.Font.FontFamily, this.Font.Size, this.Font.Style);
            series.MarkerStyle = MarkerStyle.Circle;

            foreach (AjaxHistoryPoint point in history.Series)
                series.Points.AddXY(point.Time, point.Value);

            this.chart.Series.Add(series);
            this.chart.ChartAreas[0].AxisX.Title = axisX;
            this.chart.ChartAreas[0].AxisY.Title = axisY;

            AjaxHistoryMarker? lastMarker = null;
            RectangleAnnotation lastAnnotation = null;

            // For all markers.
            foreach (AjaxHistoryMarker marker in history.Markers)
            {
                // Get the history point closest to the marker.
                AjaxHistoryPoint? point = history.GetPointAt(marker);

                // If the point does not exist, continue.
                if (null == point) continue;

                // If the last marker and last annotation exist.
                if ((lastMarker != null) && (lastAnnotation != null))
                {
                    // If the last marker has the same date with the current one, only update the annotation text.
                    if (lastMarker.Value.Time == marker.Time)
                    {
                        lastAnnotation.Text += " " + marker.Name;
                        continue;
                    }
                }

                RectangleAnnotation rect = new RectangleAnnotation();
                rect.Text = marker.Name;
                rect.ForeColor = Color.Black;
                rect.AxisX = this.chart.ChartAreas[0].AxisX;
                rect.AxisY = this.chart.ChartAreas[0].AxisY;
                rect.AnchorX = marker.Time.ToOADate();
                rect.AnchorY = point.Value.Value;
                rect.AnchorOffsetX = 0;
                rect.AnchorOffsetY = 5;
                rect.ShadowColor = Color.Gray;
                rect.ShadowOffset = 5;

                VerticalLineAnnotation line = new VerticalLineAnnotation();
                line.AxisX = this.chart.ChartAreas[0].AxisX;
                line.AxisY = this.chart.ChartAreas[0].AxisY;
                line.AnchorX = marker.Time.ToOADate();
                line.AnchorY = point.Value.Value;
                line.Height = -5;

                this.chart.Annotations.Add(line);
                this.chart.Annotations.Add(rect);
                this.chart.ResetAutoValues();

                lastAnnotation = rect;
                lastMarker = marker;
            }

            // Add discovery events.
            foreach (KeyValuePair<string, AjaxViewsHistoryDiscoveryEvent> evt in history.DiscoveryEvents)
            {
                ListViewItem item = new ListViewItem(new string[] {
                        evt.Value.Name,
                        evt.Value.Marker != null ? evt.Value.Marker.Value.Time.ToString() : "Unknown",
                        AjaxViewsHistoryDiscoveryEvent.GetTypeDescription(evt.Value.Type),
                        evt.Value.Extra != null ? evt.Value.Extra : string.Empty }, 0);
                item.Tag = evt.Value;

                this.listViewDiscovery.Items.Add(item);
            }
        }