using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using C1.Silverlight;
using System.ComponentModel;

namespace C1DataGrid_Demo2010
{
    public partial class Viewport : UserControl, INotifyPropertyChanged
    {
        DispatcherTimer _timer;
        bool _animationRunning = false;

        public Viewport()
        {
            InitializeComponent();

            _timer = new DispatcherTimer();
            _timer.Interval = TimeSpan.FromMilliseconds(50);
            _timer.Tick += new EventHandler(m_objTimer_Tick);
            btnAnimation.DataContext = this;

            DataContext = GetProducts();

            //Listen to the drag events of the viewport border 
            //in order to set the scroll position as the border is dragged.
            var mh = new C1DragHelper(viewportElement, captureElementOnPointerPressed: true);
            double x = 0, y = 0;
            mh.DragStarted += (s, e) =>
            {
                x = grid.Viewport.HorizontalOffset;
                y = grid.Viewport.VerticalOffset;
            };
            mh.DragDelta += (s, e) =>
            {
                grid.Viewport.ScrollToHorizontalOffset(x + (e.CumulativeTranslation.X * grid.Viewport.ExtentSize.Width / extentSizeElement.ActualWidth));
                grid.Viewport.ScrollToVerticalOffset(y + (e.CumulativeTranslation.Y * grid.Viewport.ExtentSize.Height / extentSizeElement.ActualHeight));
            };
        }

        #region ** data

        public static IEnumerable<Product> GetProducts()
        {
            IEnumerable<Product> products = Data.GetProducts((product) => !string.IsNullOrEmpty(product.Element("ProductModelID").Value)).Take(30);
            foreach (var product in products)
            {
                product.ExpirationDate = GetDate(product.StandardCost);
                product.Available = GetAvailable(product.Name);
            }
            return products;
        }

        private static bool? GetAvailable(string seed)
        {
            return (seed.Length % 3 == 0 ? (bool?)true : (seed.Length % 3 == 1 ? (bool?)false : (bool?)null));
        }

        private static DateTime? GetDate(double seed)
        {
            return new DateTime(DateTime.Now.Ticks - ((long)seed * 10000000000));
        }

        #endregion

        private void grid_AutoGeneratingColumn(object sender, C1.Silverlight.DataGrid.DataGridAutoGeneratingColumnEventArgs e)
        {
            Common.HandleColumnAutoGeneration(e);
            if (e.Column.Width.IsAutoStar)
            {
                e.Column.Width = new C1.Silverlight.DataGrid.DataGridLength(200);
            }
        }

        private void grid_LayoutUpdated(object sender, EventArgs e)
        {
            //It's mandatory to use the dispatcher in order to avoid layout cycles
            Dispatcher.BeginInvoke(() =>
            {
                //CAUTION: The code executed in this area must be fast to don't degrade the general performance.

                txtOffset.Text = string.Format("H = {0:F0}, V = {1:F0}", grid.Viewport.HorizontalOffset, grid.Viewport.VerticalOffset);

                //Calculates the size of the borders used to draw the viewport info.
                var extentSize = grid.Viewport.ExtentSize;
                var viewportSize = grid.Viewport.Size;
                double actualWidth, actualHeight;
                if (extentSize.Width < extentSize.Height)
                {
                    actualWidth = Math.Max(10, scrollCanvas.ActualWidth * extentSize.Width / extentSize.Height);
                    actualHeight = scrollCanvas.ActualHeight;
                }
                else
                {
                    actualWidth = scrollCanvas.ActualWidth;
                    actualHeight = Math.Max(10, scrollCanvas.ActualHeight * extentSize.Height / extentSize.Width);
                }
                viewportElement.Width = Math.Max(10, actualWidth * viewportSize.Width / extentSize.Width);
                viewportElement.Height = Math.Max(10, actualHeight * viewportSize.Height / extentSize.Height);
                Canvas.SetTop(viewportElement, extentSize.Height - viewportSize.Height == 0 ? 0 : (actualHeight - viewportElement.Height) * grid.Viewport.VerticalOffset / (extentSize.Height - viewportSize.Height));
                Canvas.SetLeft(viewportElement, extentSize.Width - viewportSize.Width == 0 ? 0 : (actualWidth - viewportElement.Width) * grid.Viewport.HorizontalOffset / (extentSize.Width - viewportSize.Width));
                extentSizeElement.Width = actualWidth;
                extentSizeElement.Height = actualHeight;
            });
        }

        void m_objTimer_Tick(object sender, EventArgs e)
        {
            if (grid.Viewport.VerticalOffset + grid.Viewport.Size.Height < grid.Viewport.ExtentSize.Height)
            {
                grid.Viewport.ScrollToVerticalOffset(grid.Viewport.VerticalOffset + 1);
            }
            else
            {
                IsAnimationRunning = false;
            }
        }

        public bool IsAnimationRunning
        {
            get
            {
                return _animationRunning;
            }
            set
            {
                if (value != _animationRunning)
                {
                    if (value)
                    {
                        _timer.Start();
                    }
                    else
                    {
                        _timer.Stop();
                    }
                    _animationRunning = value;
                    if (PropertyChanged != null)
                        PropertyChanged(this, new PropertyChangedEventArgs("IsAnimationRunning"));
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
