using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Net;
using System.Windows;
using System.Windows.Data;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

#if (SILVERLIGHT)
using C1.Silverlight;
using C1.Silverlight.Chart;
#else
using C1.WPF.C1Chart;
#endif

namespace ChartSamples
{
  [System.ComponentModel.Description("Select a range on the top chart and see the detail on the bottom chart")]
    public partial class ZoomChart : UserControl
    {
        // ** fields
        double _min = double.NaN, _max = double.NaN;
        Storyboard _sb;
        bool _sb_completed = true;
        double _minRange = 7.0 / 365;

        // ** ctor
        public ZoomChart()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(ZoomChart_Loaded);

            CSVData data = new CSVData();

            using (Stream stream = Assembly.GetExecutingAssembly().
                GetManifestResourceStream("ChartSamples.Resources.WeatherData.txt"))
            {
                data.Read(stream, true);
            }

            int len = data.Length;
            WeatherData[] wdata = new WeatherData[len];

            double min = double.MaxValue;
            double max = double.MinValue;

            for (int i = 0; i < len; i++)
            {
                wdata[i] = new WeatherData(DateTime.Parse(data[i, 0],CultureInfo.InvariantCulture),
                    double.Parse(data[i, "Max TemperatureF"], CultureInfo.InvariantCulture),
                    double.Parse(data[i, "Mean TemperatureF"], CultureInfo.InvariantCulture),
                    double.Parse(data[i, "Min TemperatureF"], CultureInfo.InvariantCulture));

                min = Math.Min(min, wdata[i].TMin);
                max = Math.Max(max, wdata[i].TMax);
            }

            _min = wdata[0].DateTime.ToOADate();
            _max = wdata[len - 1].DateTime.ToOADate();

            if (len > 0)
            {
                chart.BeginUpdate();
                legend.Chart = chart;
                CreateDataSeries(chart, wdata);
                chart.ChartType = ChartType.Line;
                chart.View.AxisX.AnnoFormat = "MMM";
                chart.View.AxisX.Min = _min;
                chart.View.AxisX.Max = _max;
                chart.EndUpdate();

                chartZoom.BeginUpdate();
                CreateDataSeries(chartZoom, wdata);
                chartZoom.ChartType = ChartType.Line;
                chartZoom.View.AxisX.AnnoFormat = "dd-MMM";
                chartZoom.View.AxisX.Max = _min + 0.25 * (_max - _min);
                chartZoom.EndUpdate();
            }
        }

        void ZoomChart_Loaded(object sender, RoutedEventArgs e)
        {
          if( Foreground is SolidColorBrush)
          {
            Color clr = ((SolidColorBrush)Foreground).Color;
            slider.Box.Fill = new SolidColorBrush(Color.FromArgb(32, clr.R, clr.G, clr.B));
            slider.Box.Stroke = new SolidColorBrush(Color.FromArgb(200, clr.R, clr.G, clr.B));
          }
          legend.Foreground = Foreground;
        }

        // ** zooming
        double Minimum
        {
            get { return double.IsNaN(_min) ? chart.View.AxisX.Min : _min; }
            set
            {
                if (value != _min)
                {
                    _min = value;
                    Update();
                }
            }
        }
        double Maximum
        {
            get { return double.IsNaN(_max) ? chart.View.AxisX.Max : _max; }
            set
            {
                if (value != _max)
                {
                    _max = value;
                    Update();
                }
            }
        }
        void Update()
        {
            if (_sb == null)
            {
                _sb = new Storyboard();
                _sb.Completed += _sb_Completed;
                _sb.Duration = new Duration(TimeSpan.FromSeconds(01));
            }
            if (_sb_completed)
            {
                _sb.Begin();
                _sb_completed = false;
            }
        }
        void _sb_Completed(object sender, EventArgs e)
        {
            PerformUpdate();
            _sb_completed = true;
        }

        void PerformUpdate()
        {
            chartZoom.BeginUpdate();
            chartZoom.View.AxisX.Min = Minimum;
            chartZoom.View.AxisX.Max = Maximum;
            chartZoom.EndUpdate();
        }

        // ** overrides
        protected override Size MeasureOverride(Size availableSize)
        {
          // adjust margin if necessary
            {
                Thickness mars = chart.View.Margin;
                double w = slider.ThumbWidth;
                mars.Left -= w - chart.Padding.Left; mars.Right -= w - chart.Padding.Right;
                mars.Top += chart.Padding.Top; mars.Bottom += chart.Padding.Bottom; 
                slider.Margin = mars;
                //slc.Margin = mars;
            }

            return base.MeasureOverride(availableSize);
        }

        // ** event handlers
        void slider_LowerValueChanged(object sender, EventArgs e)
        {
            if (chart != null && chartZoom != null)
            {
                if (slider.UpperValue - slider.LowerValue < _minRange)
                    slider.LowerValue = slider.UpperValue - _minRange;

                Axis ax = chart.View.AxisX;
                if (ax.Max != ax.Min)
                {
                    double min = ax.Min + slider.LowerValue * (ax.Max - ax.Min);
                    Minimum = min;
                }
            }
        }
        void slider_UpperValueChanged(object sender, EventArgs e)
        {
            if (chart != null && chartZoom != null)
            {
                if (slider.UpperValue - slider.LowerValue < _minRange)
                    slider.UpperValue = slider.LowerValue + _minRange;

                Axis ax = chart.View.AxisX;
                if (ax.Max != ax.Min)
                {
                    double max = ax.Min + slider.UpperValue * (ax.Max - ax.Min);
                    Maximum = max;
                }
            }
        }
        void slider_GotFocus(object sender, RoutedEventArgs e)
        {
            // prevent drawing focus rectangle
            VisualStateManager.GoToState(slider, "Unfocused", true);
        }

        // ** utilities
        void CreateDataSeries(C1Chart chart, WeatherData[] data)
        {
            chart.Data.Children.Clear();

#if DataBinding
      chart.Data.ItemsSource = data;
#else
            int len = data.Length;
            DateTime[] days = new DateTime[len];
            double[] tmin = new double[len];
            double[] tmax = new double[len];
            double[] tavg = new double[len];
            for (int i = 0; i < len; i++)
            {
                days[i] = data[i].DateTime;
                tmin[i] = data[i].TMin;
                tmax[i] = data[i].TMax;
                tavg[i] = data[i].TAvg;
            }
#endif

            XYDataSeries ds = new XYDataSeries(); ds.Label = "Minimum";
#if DataBinding
      ds.ValueBinding = new Binding("TMin");
      ds.XValueBinding = new Binding("DateTime");
#else
            ds.XValuesSource = days;
            ds.ValuesSource = tmin;
#endif
            ds.ConnectionStroke = new SolidColorBrush(Colors.Blue);
            chart.Data.Children.Add(ds);

            ds = new XYDataSeries(); ds.Label = "Maximum";
#if DataBinding
      ds.ValueBinding = new Binding("TMax");
      ds.XValueBinding = new Binding("DateTime");
#else
            ds.XValuesSource = days;
            ds.ValuesSource = tmax;
#endif
            ds.ConnectionStroke = new SolidColorBrush(Colors.Red);
            chart.Data.Children.Add(ds);

            ds = new XYDataSeries(); ds.Label = "Average";
#if DataBinding
      ds.ValueBinding = new Binding("TAvg");
      ds.XValueBinding = new Binding("DateTime");
#else
            ds.XValuesSource = days;
            ds.ValuesSource = tavg;
#endif
            chart.Data.Children.Add(ds);

            foreach (DataSeries ser in chart.Data.Children)
                ser.ConnectionStrokeThickness = 1;

            chart.View.AxisX.IsTime = true;
            chart.View.AxisX.AnnoPosition = AnnoPosition.Near;
        }
    }

    public class ChartSlider : C1RangeSlider
    {
        // ** fields
        Rectangle _box;
        double _tw;

        // ** ctor
        public ChartSlider()
        {
            _box = new Rectangle();
            _box.Fill = new SolidColorBrush(Color.FromArgb(32, 255, 255, 255));
            _box.Stroke = new SolidColorBrush(Color.FromArgb(200, 255, 255, 255));
      _box.StrokeThickness = 1;
            _box.IsHitTestVisible = false;
            Grid.SetColumn(_box, 1);
            Grid.SetColumnSpan(_box, 3);
        }

        // ** object model
        public double ThumbWidth
        {
            get { return _tw; }
        }

        public Rectangle Box
        {
          get { return _box; }
        }

        // ** overrides
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

      // insert rectangle that represents zoom area
      Grid root = GetTemplateChild("HorizontalTemplate") as Grid;
      if (root != null)
        root.Children.Insert(0, _box);

      Thumb lthumb = GetTemplateChild("LowerThumb") as Thumb;
      if (lthumb != null)
            {
        _tw = lthumb.Width;
                if (double.IsNaN(_tw))
                {
           lthumb.Measure(new Size(1000, 1000));
          _tw = lthumb.DesiredSize.Width;
                }
        double w = Math.Ceiling(_tw);
        // adjust zoom area margins
                _box.Margin = new Thickness(w, 0, w, 0);

        // move thumb on the border of zoom area
        lthumb.RenderTransform = new TranslateTransform() { X = 0.5 * _tw };

        // move thumb on the top of slider visual tree
        root.Children.Remove(lthumb);
        root.Children.Add(lthumb);
      }

      Thumb uthumb = GetTemplateChild("UpperThumb") as Thumb;
      if (uthumb != null)
        // move thumb on the border of zoom area
        uthumb.RenderTransform = new TranslateTransform() { X = -0.5 * _tw };

      // stretch middle thumb vertically
      Thumb mthumb = GetTemplateChild("MiddleThumb") as Thumb;
      if (mthumb != null)
        mthumb.Height = double.NaN;
        }
    }
}
