using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Reflection;
using System.Diagnostics;

using C1.Silverlight;
using C1.Silverlight.RichTextBox;
using C1.Silverlight.RichTextBox.Documents;
using C1.Silverlight.Extended;
using C1.Silverlight.Uploader;
using C1.Silverlight.Maps;
using C1.Silverlight.Chart;
using System.IO;
using C1.Silverlight.RichTextBox.Documents;
using C1.Silverlight.Imaging;

namespace QuickStart
{
    public partial class Page : UserControl
    {
        //-----------------------------------------------------------------------------------
        #region ** Initialize page

        public Page()
        {
            InitializeComponent();

            // initialize the C1ComboBoxes
            _cmb1.IsEditable = false;
            _cmb1.SelectedItemChanged += _cmb_SelectedItemChanged;
            PopulateCombo(_cmb1);

            _cmb2.IsEditable = true;
            _cmb2.SelectedItemChanged += _cmb_SelectedItemChanged;
            PopulateCombo(_cmb2);

            // initialize the C1Menu
            InitializeMenu();

            // initialize the C1TreeView
            InitializeTreeView();

            // initialize the C1HyperPanels
            FillHyperPanel(_hp1);
            FillHyperPanel(_hp2);

            // initialize the C1DragDropManager
            C1DragDropManager dd = new C1DragDropManager();
            dd.RegisterDropTarget(_ddGrid, true);
            foreach (UIElement e in _ddGrid.Children)
            {
                dd.RegisterDragSource(e, DragDropEffect.Move, ModifierKeys.None);
            }
            dd.DragDrop += dd_DragDrop;

            // initialize the C1Accordion
            PopulateAccordion();

            // initialize the C1RichTextBox
            _btnBold.Click += _btnBold_Click;
            _btnItalics.Click += _btnItalics_Click;
            _btnUnderline.Click += _btnUnderline_Click;
            _rtb.SelectionChanged += _rtb_SelectionChanged;

            // initialize the chart
            _legend.Chart = _chart; // connect legend to chart
            GenerateChart();        // show the chart
        }

        #endregion

        //-----------------------------------------------------------------------------------
        #region ** C1Combo methods

        void _cmb_SelectedItemChanged(object sender, PropertyChangedEventArgs<object> e)
        {
            C1ComboBox cmb = sender as C1ComboBox;
            Debug.WriteLine("SelectedItemChanged on {0}: new value is '{1}'",
                cmb.Name, cmb.Text);//.SelectedItem);
        }
        void PopulateCombo(C1ComboBox cmb)
        {
            foreach (PropertyInfo pi in cmb.GetType().GetProperties())
                cmb.Items.Add(pi.Name);
        }
        #endregion

        //-----------------------------------------------------------------------------------
        #region ** C1RichTextBox methods

        void _btnBold_Click(object sender, RoutedEventArgs e)
        {
            if (_btnBold.IsChecked.HasValue)
            {
                _rtb.Selection.FontWeight = _btnBold.IsChecked.Value
                    ? FontWeights.Bold
                    : FontWeights.Normal;
            }
        }
        void _btnItalics_Click(object sender, RoutedEventArgs e)
        {
            if (_btnItalics.IsChecked.HasValue)
            {
                _rtb.Selection.FontStyle = _btnItalics.IsChecked.Value
                    ? FontStyles.Italic
                    : FontStyles.Normal;
            }
        }
        void _btnUnderline_Click(object sender, RoutedEventArgs e)
        {
            if (_btnUnderline.IsChecked.HasValue)
            {
                _rtb.Selection.TextDecorations = _btnUnderline.IsChecked.Value
                    ? C1TextDecorations.Underline 
                    : null;
            }
        }
        void _rtb_SelectionChanged(object sender, EventArgs e)
        {
            // get current selection
            var sel = _rtb.Selection;

            // update state of bold button
            FontWeight? fw = sel.FontWeight;
            if (fw.HasValue)
                _btnBold.IsChecked = fw.Value == FontWeights.Bold;
            else
                _btnBold.IsChecked = null;

            // update state of italics button
            FontStyle? fs = sel.FontStyle;
            if (fs.HasValue)
                _btnItalics.IsChecked = fs.Value == FontStyles.Italic;
            else
                _btnItalics.IsChecked = null;

            // update state of underline button
            _btnUnderline.IsChecked = (sel.TextDecorations != null);
        }

        #endregion

        //-----------------------------------------------------------------------------------
        #region ** C1TreeView methods

        void InitializeTreeView()
        {
            // remove items that were added at design time
            _tv.Items.Clear();

            // scan every type in the assembly
            foreach (Type type in _tv.GetType().Assembly.GetTypes())
            {
                if (type.IsPublic && !type.IsSpecialName && !type.IsAbstract)
                {
                    // add node for this type
                    C1TreeViewItem node = new C1TreeViewItem();
                    node.Header = type.Name;
                    node.FontWeight = FontWeights.Bold;
                    node.Tag = type;
                    _tv.Items.Add(node);

                    // add subnodes for properties, events, and methods
                    node.Items.Add(CreateMemberNode("Properties", MemberTypes.Property));
                    node.Items.Add(CreateMemberNode("Events", MemberTypes.Event));
                    node.Items.Add(CreateMemberNode("Methods", MemberTypes.Method));
                }
            }
        }
        C1TreeViewItem CreateMemberNode(string header, MemberTypes memberTypes)
        {
            // create the node
            C1TreeViewItem node = new C1TreeViewItem();
            node.Header = header;
            node.Foreground = new SolidColorBrush(Colors.DarkGray);

            // hook up event hander to populate the node before expanding it
            node.Expanding += node_Expanding;

            // save information needed to populate the node
            node.Tag = memberTypes;

            // add a dummy node so this node can be expanded
            node.Items.Add(new C1TreeViewItem());
            node.IsExpanded = false;

            // done
            return node;
        }
        void node_Expanding(object sender, SourcedEventArgs e)
        {
            // get the node that fired the event
            C1TreeViewItem node = sender as C1TreeViewItem;

            // unhook event handler (we'll populate the node and be done with it)
            node.Expanding -= node_Expanding;

            // remove dummy node
            Debug.Assert(node.Items.Count == 1);
            node.Items.Clear();

            // populate the node
            Type type = (Type)node.Parent.Tag;
            MemberTypes memberTypes = (MemberTypes)node.Tag;

            BindingFlags bf = BindingFlags.Public | BindingFlags.Instance;
            foreach (MemberInfo mi in type.GetMembers(bf))
            {
                if (mi.MemberType == memberTypes)
                {
                    if (!mi.Name.StartsWith("get_") && !mi.Name.StartsWith("set_"))
                    {
                        C1TreeViewItem item = new C1TreeViewItem();
                        item.Header = mi.Name;
                        item.FontSize = 12;
                        node.Items.Add(item);
                    }
                }
            }
        }
        #endregion

        //-----------------------------------------------------------------------------------
        #region ** C1Menu methods

        private void InitializeMenu()
        {
            // Remove items that were added at design time
            _menu.Items.Clear();

            // create File menu
            C1MenuItem fileMenu = new C1MenuItem();
            fileMenu.Header = "File";
            CreateSubMenu("New", fileMenu);
            CreateSubMenu("Open", fileMenu);
            CreateSubMenu("Add", fileMenu);
            CreateSubMenu("Close", fileMenu);
            CreateSubMenu("Save", fileMenu);
            CreateSubMenu("Save As", fileMenu);
            CreateSubMenu("Save All", fileMenu);

            // create Window menu when the page loads
            C1MenuItem windowMenu = new C1MenuItem();
            windowMenu.Header = "Window";
            windowMenu.Loaded += windowMenuLoaded;

            // populate main menu
            _menu.Items.Add(fileMenu);
            _menu.Items.Add(windowMenu);
        }
        private void CreateSubMenu(string header, C1MenuItem parent)
        {
            C1MenuItem menuItem = new C1MenuItem();
            menuItem.Header = header;
            parent.Items.Add(menuItem);
        }
        void windowMenuLoaded(object sender, RoutedEventArgs e)
        {
            C1MenuItem windowMenu = sender as C1MenuItem;
            windowMenu.ItemsSource = GetSubmenus();
        }
        private List<object> GetSubmenus()
        {
            List<object> menuList = new List<object>(10);
            for (int i = 0; i < 10; i++)
            {
                C1MenuItem menuItem = new C1MenuItem();
                menuItem.Header = "Submenu " + i;
                menuList.Add(menuItem);
            }
            return menuList;
        }
        #endregion

        //-----------------------------------------------------------------------------------
        #region ** C1HyperPanel methods

        void FillHyperPanel(C1HyperPanel hp)
        {
            for (double p = 0; p <= 1; p += 0.05)
            {
                // create Color
                byte red = (byte)(255 * p);
                byte green = (byte)((red + 255 / 3) % 255);
                byte blue = (byte)((green + 255 / 3) % 255);
                Color c = Color.FromArgb(255, red, green, blue);

                // create Rectangle element
                Rectangle r = new Rectangle();
                r.Fill = new SolidColorBrush(c);
                r.Width = r.Height = 30;
                r.Margin = new Thickness(2);
                r.RadiusX = r.RadiusY = 4;
                r.Stroke = new SolidColorBrush(Colors.Black);
                r.StrokeThickness = 1;
                r.VerticalAlignment = VerticalAlignment.Bottom;

                // add rectangle to C1HyperPanel
                hp.Children.Add(r);
            }
        }
        #endregion

        //-----------------------------------------------------------------------------------
        #region ** C1Accordion methods

        void PopulateAccordion()
        {
            for (int i = 1; i <= 4; i++)
            {
                string key = string.Format("Key {0}", i);
                string value = string.Format("This is value {0}", i);
                _templatedAccordion.Items.Add(new KeyValuePair<string, string>(key, value));
            }
        }
        #endregion

        //-----------------------------------------------------------------------------------
        #region ** C1Window methods

        void OpenWindow(object sender, RoutedEventArgs e)
        {
            var window = new C1Window();
            window.Content = new MyWindow();
            window.CenterOnScreen();
            window.Show();
        }
        void ShowDialog(object sender, RoutedEventArgs e)
        {
            var window = new C1Window();
            window.Content = new MyWindow();
            window.CenterOnScreen();
            window.ShowModal();
        }
        #endregion

        //-----------------------------------------------------------------------------------
        #region ** C1MessageBox methods

        void ShowMessageBox(object sender, RoutedEventArgs e)
        {
            C1MessageBox.Show("To be or not to be?", "The question",
                C1MessageBoxButton.YesNoCancel,
                C1MessageBoxIcon.Question,
                MessageBoxCallback);
        }
        void MessageBoxCallback(MessageBoxResult result)
        {
            switch (result)
            {
                case MessageBoxResult.Yes:
                    C1MessageBox.Show("You are!");
                    break;
                case MessageBoxResult.No:
                    C1MessageBox.Show("You are not!");
                    break;
                case MessageBoxResult.Cancel:
                    C1MessageBox.Show("OK, I won't ask again ;-)");
                    break;
            }
        }

        #endregion

        //-----------------------------------------------------------------------------------
        #region ** C1Uploader methods

        private void Upload_Click(object sender, RoutedEventArgs e)
        {
            // configure OpenFileDialg
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "All|*.*|Images|*.jpg;*.png;*.gif";
            dlg.FilterIndex = 2;
            dlg.Multiselect = true;

            // show OpenFileDialg
            if ((bool)dlg.ShowDialog())
            {
                try
                {
                    // check that the files really are images
                    foreach (FileInfo fdi in dlg.Files)
                    {
                        System.Windows.Media.Imaging.BitmapImage img =
                            new System.Windows.Media.Imaging.BitmapImage();
                        img.SetSource(fdi.OpenRead());
                    }
                }
                catch
                {
                    C1MessageBox.Show(
                        "Sorry, at least one of these files doesn't look like an image...",
                        "Upload Canceled",
                        C1MessageBoxButton.OK, C1MessageBoxIcon.Warning);
                    return;
                }

                // create and configure uploader
                Uri uri = C1.Silverlight.Extensions.GetAbsoluteUri("photoUpload.ashx");
                C1Uploader uploader = new C1UploaderPost(uri);
                uploader.UploadProgressChanged += uploader_UploadProgressChanged;
                uploader.UploadCompleted += uploader_UploadCompleted;

                // upload selected files
                uploader.AddFiles(dlg.Files);
                uploader.BeginUploadFiles();
            }
        }
        void uploader_UploadProgressChanged(object sender, C1.Silverlight.Uploader.UploadProgressChangedEventArgs e)
        {
            Debug.WriteLine("uploaded {0} of {1} bytes, {2}%", e.BytesUploaded, e.TotalBytesToUpload, e.ProgressPercentage);
        }
        void uploader_UploadCompleted(object sender, UploadCompletedEventArgs e)
        {
            if (e.Success)
            {
                foreach (string fileName in e.Files)
                {
                    // holder for picture and title
                    StackPanel picHolder = new StackPanel();
                    picHolder.Background = new SolidColorBrush(Colors.LightGray);
                    picHolder.Margin = new Thickness(10);
                    picHolder.Width = 200;

                    // create Image to show the picture
                    System.Windows.Media.Imaging.BitmapImage bmp = new System.Windows.Media.Imaging.BitmapImage();
                    bmp.UriSource = C1.Silverlight.Extensions.GetAbsoluteUri("Pictures/" + fileName);
                    Image img = new Image();
                    img.Source = bmp;
                    img.Margin = new Thickness(10, 10, 10, 0);
                    picHolder.Children.Add(img);

                    // create image title
                    TextBlock tb = new TextBlock();
                    tb.Text = fileName;
                    tb.FontSize = 12;
                    tb.HorizontalAlignment = HorizontalAlignment.Center;
                    tb.Margin = new Thickness(10, 0, 10, 10);
                    picHolder.Children.Add(tb);

                    // add picture holder to panel
                    _spPictures.Children.Add(picHolder);
                }
                Debug.WriteLine("{0} files uploaded successfully.", e.Files.Length);
            }
            else
            {
                Debug.WriteLine("Upload failed: {0}", e.Error != null ? e.Error.Message : "??");
            }
        }
        
        #endregion

        //-----------------------------------------------------------------------------------
        #region ** C1DragDropManager methods

        void dd_DragDrop(object source, DragDropEventArgs e)
        {
            // get mouse position
            Point pMouse = e.GetPosition(_ddGrid);

            // translate into grid row/col coordinates
            int row, col;
            Point pGrid = new Point(0, 0);
            for (row = 0; row < _ddGrid.RowDefinitions.Count; row++)
            {
                pGrid.Y += _ddGrid.RowDefinitions[row].ActualHeight;
                if (pGrid.Y > pMouse.Y)
                    break;
            }
            for (col = 0; col < _ddGrid.ColumnDefinitions.Count; col++)
            {
                pGrid.X += _ddGrid.ColumnDefinitions[col].ActualWidth;
                if (pGrid.X > pMouse.X)
                    break;
            }

            // move the element to the new position
            e.DragSource.SetValue(Grid.RowProperty, row);
            e.DragSource.SetValue(Grid.ColumnProperty, col);
        }
        #endregion

        //-----------------------------------------------------------------------------------
        #region ** C1Gauge methods

        private void _slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            double value = ((Slider)sender).Value;
            if (_gauge1 != null && _gauge2 != null)
            {
                _gauge1.Value = _gauge2.Value = value;
            }
            if (_txtGaugeValue != null)
            {
                _txtGaugeValue.Text = value.ToString("n0");
            }
        }
        #endregion

        //-----------------------------------------------------------------------------------
        #region ** C1Maps methods

        private void C1Maps_MouseMove(object sender, MouseEventArgs e)
        {
            C1Maps map = sender as C1Maps;
            Point p = map.ScreenToGeographic(e.GetPosition(map));
            _tbMapCoords.Text = string.Format("{0:f6},{1:f6}", p.X, p.Y);
        }
        #endregion

        //-----------------------------------------------------------------------------------
        #region ** C1Chart methods

        // change chart type
        private void _cbChartType_SelectedItemChanged(object sender, SelectionChangedEventArgs e)
        {
            if (_cbChartType == null) return;
            switch (_cbChartType.SelectedIndex)
            {
                case 0:
                    _chart.ChartType = ChartType.LineSymbols;
                    break;
                case 1:
                    _chart.ChartType = ChartType.AreaStacked;
                    break;
                case 2:
                    _chart.ChartType = ChartType.ColumnStacked;
                    break;
            }
        }

        // change chart palette
        private void _cbPalette_SelectedItemChanged(object sender, SelectionChangedEventArgs e)
        {
            if (_cbPalette == null) return;
            _chart.Palette = (Palette)_cbPalette.SelectedIndex;
        }

        // re-generate chart
        private void _btnChart_Click(object sender, RoutedEventArgs e)
        {
            GenerateChart();
        }

        // populate chart with some random series
        void GenerateChart()
        {
            // don't repaint while creating the chart
            _chart.BeginUpdate();

            // initial chart type
            _chart.ChartType = ChartType.LineSymbols;

            // clear existing content if any
            _chart.Data.Children.Clear();

            // configure X axis
            _chart.View.AxisX.IsTime = true;
            _chart.View.AxisX.AnnoFormat = "MMM dd";

            // configure Y axis
            _chart.View.AxisY.AnnoFormat = "0 ";

            // add a few data series
            foreach (string seriesName in "North;East;South;West;Center;Overseas".Split(';'))
            {
                AddSeries(_chart, seriesName + " Region");
            }

            // done
            _chart.EndUpdate();
        }

        // add a series with some random data
        Random _rnd = new Random(0);
        void AddSeries(C1Chart chart, string name)
        {
            // create some random data to plot
            int len = 50;
            DateTime[] x = new DateTime[len];
            double[] y = new double[len];
            double lastY = 0;
            for (int i = 0; i < len; i++)
            {
                x[i] = DateTime.Today.AddDays(i);
                y[i] = Math.Max(0, lastY + (_rnd.NextDouble() - 0.45) * 10);
                lastY = y[i];
            }

            // create the series
            XYDataSeries ds = new XYDataSeries();
            ds.XValuesSource = x;
            ds.ValuesSource = y;
            ds.Label = name;
            ds.ConnectionStrokeThickness = 3;

            // add series to chart
            chart.Data.Children.Add(ds);
        }
        #endregion

        //-----------------------------------------------------------------------------------
        #region ** C1ContextMenu methods

        private void C1ContextMenu_ItemClick(object sender, SourcedEventArgs e)
        {
            var item = (C1MenuItem)e.Source;
            string msg = string.Format("Thank you for clicking me.\r\n" +
                "If this were a real application, I would now '{0}'.",
                item.Header);
            C1MessageBox.Show(msg, "C1ContextMenu");
        }
        #endregion
    }
}
