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 Telerik.Windows.Controls.DragDrop;
using System.Collections.ObjectModel;
using System.Windows.Media.Imaging;
using System.ComponentModel;

namespace DragCanvasTest
{
    public partial class MainPage : UserControl
    {
        ObservableCollection<ImageItem> imgItems = new ObservableCollection<ImageItem>();

        public MainPage()
        {
            InitializeComponent();

            // Set handlers for RadDragAndDrop operations
            RadDragAndDropManager.AddDragQueryHandler(this, onDragQuery);
            RadDragAndDropManager.AddDropQueryHandler(this, onDropQuery);
            RadDragAndDropManager.AddDragInfoHandler(this, onDragInfo);
            RadDragAndDropManager.AddDropInfoHandler(this, onDropInfo);

            // Give us some images to work with 
            FillImgItems();

            // Set our ListBox to use the ObservableCollection as a source
            SourceBox.ItemsSource = imgItems;
        }

        private void FillImgItems()
        {
            // Add some ImageItems to our ListBox to drag + drop
            for (int y = 1; y < 4; y++)
            {
                for (int x = 1; x <= 3; x++)
                {
                    ImageItem ii = new ImageItem();
                    ii.ItemName = "Item " + y.ToString() + "-" + x.ToString();
                    ii.ImgSource = "Images/iph00" + x.ToString() + ".JPG";

                    imgItems.Add(ii);
                }
            }
        }

        private void onDragQuery(object sender, DragDropQueryEventArgs e)
        {
            // If we are dragging from Listbox
            if (e.Options.Source.GetType() == typeof(ListBox))
            {
                ListBox box = e.Options.Source as ListBox;
               
                if (e.Options.Status == DragStatus.DragQuery)
                {
                    // Our payload will be the item they picked, an ImageItem
                    e.Options.Payload = box.SelectedItem;

                    // Since we aren't working with an image, we need to use the item as content for a template to
                    //   show when we drag
                    ContentControl cue = new ContentControl();
                    cue.ContentTemplate = LayoutRoot.Resources["DragTemplate"] as DataTemplate;
                    cue.Content = box.SelectedItem;
                    e.Options.DragCue = cue;
                    e.Options.ArrowCue = RadDragAndDropManager.GenerateArrowCue();

                    e.QueryResult = true;
                }
            }
            else // if we are dragging from Canvas
            {
                Image sourceImage = e.Options.Source as Image;

                if (e.Options.Status == DragStatus.DragQuery)
                {
                    // Since we're in the canvas, the payload will be the image being moved
                    e.Options.Payload = sourceImage;

                    // The cue will be a copy of the image being moved
                    ContentControl cue = new ContentControl();                    
                    Image cueImage = new Image() { Source = sourceImage.Source, Width = sourceImage.Width, Height = sourceImage.Height, Stretch = Stretch.Fill, Opacity = .7 };
                    cue.Content = cueImage;
                    e.Options.DragCue = cue;
                    e.Options.ArrowCue = RadDragAndDropManager.GenerateArrowCue();

                    e.QueryResult = true;
                }
            }
            e.QueryResult = true;
        }

        private void onDropQuery(object sender, DragDropQueryEventArgs e)
        {
            // We check to make sure we have a payload for either case here
            if (e.Options.Payload.GetType() == typeof(ImageItem))
            {
                ImageItem lbi = e.Options.Payload as ImageItem;
                e.QueryResult = lbi != null;
            }
            else
            {
                Image payload = e.Options.Payload as Image;
                e.QueryResult = payload != null;
            }
        }

        private void onDragInfo(object sender, DragDropEventArgs e)
        {
            if (e.Options.Source.GetType() == typeof(ListBox))
            {
                ListBox box = e.Options.Source as ListBox;
                ImageItem payload = e.Options.Payload as ImageItem;

                if (e.Options.Status == DragStatus.DragComplete)
                {
                    // Make sure we are dropping to the Canvas so we can remove from imgItems collection
                    if (payload != null && e.Options.Destination.GetType() == typeof(Canvas))
                    {
                        imgItems.Remove(payload);
                    }
                }
            }
            else
            {
                Canvas sourceCanvas = e.Options.Source.Parent as Canvas;
                Canvas destinationCanvas = e.Options.Destination as Canvas;

                Image payload = e.Options.Payload as Image;

                if (e.Options.Status == DragStatus.DragComplete)
                {
                    // Can be used for multiple canvas setup, which would remove this from source and add to destination canvas
                    if (payload != null && sourceCanvas.Children.Contains(payload) && (sourceCanvas != destinationCanvas))
                    {
                        sourceCanvas.Children.Remove(payload);
                    }
                }
            }
        }

        private void onDropInfo(object sender, DragDropEventArgs e)
        {
            if (e.Options.Source.GetType() == typeof(ListBox))
            {
                ListBox box = e.Options.Source as ListBox;
                Canvas destCanvas = e.Options.Destination as Canvas;

                ImageItem payload = e.Options.Payload as ImageItem;

                if (e.Options.Status == DragStatus.DropPossible)
                {
                    destCanvas.Background = new SolidColorBrush(Colors.Yellow);
                }
                else
                {
                    destCanvas.Background = new SolidColorBrush(Colors.Gray);
                }

                if (e.Options.Status == DragStatus.DropComplete)
                {
                    Image im = new Image() { Height = 100, Width = 100, Stretch = Stretch.Fill };

                    BitmapImage bmi = new BitmapImage(new Uri(payload.ImgSource, UriKind.RelativeOrAbsolute));
                    im.Source = bmi as ImageSource;

                    // Save our ImageItem for later use!
                    im.Tag = payload;

                    destCanvas.Children.Add(im);

                    // Get our drag point as well as the current position of the Canvas to figure 
                    //   out the Canvas.Top and .Left properties for the newly added image
                    Point p = e.Options.CurrentDragPoint;
                    GeneralTransform gt = destCanvas.TransformToVisual(Application.Current.RootVisual as UIElement);
                    Point offset = gt.Transform(new Point(0, 0)); ;

                    im.SetValue(Canvas.TopProperty, p.Y - (offset.Y + im.Height / 2));
                    im.SetValue(Canvas.LeftProperty, p.X - (offset.X + im.Width / 2));
                    RadDragAndDropManager.SetAllowDrag(im, true);
                }
            }
            else
            {
                Canvas sourceCanvas = e.Options.Source.Parent as Canvas;
                Canvas destCanvas = e.Options.Destination as Canvas;
                Image payload = e.Options.Payload as Image;

                if (e.Options.Status == DragStatus.DropPossible)
                {
                    destCanvas.Background = new SolidColorBrush(Colors.Yellow);
                }
                else
                {
                    destCanvas.Background = new SolidColorBrush(Colors.Gray);
                }

                if (e.Options.Status == DragStatus.DropComplete)
                {
                    if (!destCanvas.Children.Contains(payload) && !(sourceCanvas == destCanvas))
                    {
                        destCanvas.Children.Add(payload);

                        payload.SetValue(Canvas.TopProperty, 0d);
                        payload.SetValue(Canvas.LeftProperty, 0d);
                    }

                    if (sourceCanvas.Children.Contains(payload))
                    {
                        Point p = e.Options.CurrentDragPoint;  // destination point
                        Point m = e.Options.MouseClickPoint;   // source point

                        Double tp = Convert.ToDouble(payload.GetValue(Canvas.TopProperty));
                        Double lp = Convert.ToDouble(payload.GetValue(Canvas.LeftProperty));

                        payload.SetValue(Canvas.TopProperty, Convert.ToDouble(p.Y - (m.Y - tp)));
                        payload.SetValue(Canvas.LeftProperty, Convert.ToDouble(p.X - (m.X - lp)));
                    }
                }
            }
        }
    }

    public class ImageItem : INotifyPropertyChanged
    {
        private string itemName;
        public string ItemName
        {
            get
            {
                return itemName;
            }
            set
            {
                if (itemName != value)
                {
                    itemName = value;                    
                }
            }
        }

        private string imgSource;
        public string ImgSource
        {
            get
            { 
                return imgSource;
            }
            set
            {
                if (imgSource != value)
                {
                    imgSource = value;
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
