using System;
using System.Collections.Generic;
using System.Linq;
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 C1.Silverlight;
using C1.Silverlight.Uploader;
using System.IO;
using System.Windows.Media.Imaging;

namespace C1Uploader_Demo
{
    public partial class MainPage : UserControl
    {
        #region Constructor

        public MainPage()
        {
            InitializeComponent();
        }

        #endregion

        #region Properties

        private long _maximumUploadSize = 1024;
        private C1Uploader _uploader;
        public long MaximumUploadSize_KB
        {
            get { return _maximumUploadSize; }
            set { _maximumUploadSize = value; }
        }

        private FilesPerRequest _mode = FilesPerRequest.SplitFilesIntoMultipleRequests;
        public FilesPerRequest FilesPerRequest
        {
            get { return _mode; }
            set { _mode = value; }
        }

        private UploadStrategy _strategy = UploadStrategy.MultipartPost;
        public UploadStrategy Strategy
        {
            get { return _strategy; }
            set { _strategy = value; }
        }

        #endregion

        private void btnFileUpload_Click(object sender, RoutedEventArgs e)
        {
            // check pre-condition
            if (!IsValidFilePickerSelection())
            {
                return;
            }

            // Create uploader..
            _uploader = CreateUploader(FilesPerRequest);
            if (_uploader == null)
            {
                ShowError("Cannot create the uploader");
                return;
            }

            // disable the UI
            filebox1.IsEnabled = false;
            btnFileUpload.IsEnabled = false;
            btnReset.IsEnabled = false;
            btnAbort.IsEnabled = true;

            // set custom parameters
            _uploader.MaximumUploadSize = (_maximumUploadSize == -1 ? -1 : _maximumUploadSize * 1024);
            _uploader.AddFiles(filebox1.SelectedFiles);
            _uploader.Parameters["parameter"] = "this is a CUSTOM parameter sent from the client to the server";

            // handle events
            _uploader.UploadCompleted += new EventHandler<UploadCompletedEventArgs>(uploader_UploadCompleted);
            _uploader.UploadProgressChanged += new EventHandler<UploadProgressChangedEventArgs>(uploader_UploadProgressChanged);
            try
            {
                // start upload
                _uploader.BeginUploadFiles();
            }
            catch (Exception exc)
            {
                ShowError(exc.Message);
                ResetButtons();
            }
        }

        private bool IsValidFilePickerSelection()
        {
            // check that there are files in the selection
            if (!filebox1.HasSelectedFiles)
            {
                ShowError("Please, select at least one file to upload");
                return false;
            }

            // check that the files really are images
            try
            {
                foreach (FileInfo fdi in filebox1.SelectedFiles)
                {
                    BitmapImage img = new BitmapImage();
                    img.SetSource(fdi.OpenRead());
                }
            }
            catch (Exception x)
            {
                ShowError("Sorry, at least one of these files doesn't look like an image...\n\nAlthough the C1Uploader supports any kind of files, we are only allowing images in this sample.");
                return false;
            }

            return true;
        }

        private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
        {
            filebox1.Filter = "All|*.*|Images|*.jpg;*.png;*.gif";
            filebox1.FilterIndex = 2;
            filebox1.Multiselect = true;
        }

        private void btnReset_Click(object sender, RoutedEventArgs e)
        {
            filebox1.ClearSelection();
            linksPanel.Children.Clear();
            ResetButtons();
        }

        private void btnAbort_Click(object sender, RoutedEventArgs e)
        {
            _uploader.Cancel();
            linksPanel.Children.Clear();
            ResetButtons();
        }


        private void ResetButtons()
        {
            filebox1.IsEnabled = true;
            btnFileUpload.IsEnabled = true;
            btnReset.IsEnabled = true;
            btnAbort.IsEnabled = false;
        }

        private void ShowError(string msg)
        {
            C1MessageBox.Show(msg, "File Uploader Error", C1MessageBoxButton.OK, C1MessageBoxIcon.Error);
        }

        #region Handle Uploader Events

        /// <summary>
        /// Handle the ProgressChanged event
        /// </summary>
        /// <param name="sender">the C1FileUploader</param>
        /// <param name="e">events</param>
        void uploader_UploadProgressChanged(object sender, C1.Silverlight.Uploader.UploadProgressChangedEventArgs e)
        {
            linksPanel.Children.Clear();
            progressGrid.ColumnDefinitions[0].Width = new GridLength(e.ProgressPercentage, GridUnitType.Star);
            progressGrid.ColumnDefinitions[1].Width = new GridLength(100 - e.ProgressPercentage, GridUnitType.Star);
            progressGrid.Visibility = Visibility.Visible;
            lblPercentage.Text = e.ProgressPercentage + "%";
        }

        /// <summary>
        /// Invoked when the upload method was completed
        /// </summary>
        /// <param name="sender">C1FileUploade</param>
        /// <param name="e">Result of the upload</param>
        void uploader_UploadCompleted(object sender, UploadCompletedEventArgs e)
        {
            // clean UI
            ResetButtons();
            linksPanel.Children.Clear();
            progressGrid.Visibility = Visibility.Collapsed;

            if (e.Success)
            {
                foreach (string link in ProcessResponse(e.Response))
                {
                    linksPanel.Children.Add(CreateLink(link));
                }
            }
            else
            {
               ShowError(e.Error.Message);
            }
        }

        private static HyperlinkButton CreateLink(string link)
        {
            string[] imageExtension = { ".jpg", ".png", ".gif" };
            Grid grid = new Grid();
            grid.RowDefinitions.Add(new RowDefinition()
            {
                Height = new GridLength(80)
            });
            grid.RowDefinitions.Add(new RowDefinition()
            {
                Height = GridLength.Auto
            });
            Uri imageUri = (string.Join("|", imageExtension).Contains(Path.GetExtension(link)) ? new Uri(link) : Extensions.GetAbsoluteUri("Resources/default.png"));
            Border b = new Border()
            {
                Padding = new Thickness(0, 0, 0, 4),
                Child = new Image()
                {
                    Source = new BitmapImage(imageUri),
                    Stretch = Stretch.Uniform
                }
            };
            b.SetValue(Grid.RowProperty, 0);
            TextBlock t = new TextBlock()
            {
                Text = Path.GetFileName(link),
                HorizontalAlignment = HorizontalAlignment.Center,
                FontSize = 10,
                FontFamily = new FontFamily("Tahoma"),
                TextWrapping = TextWrapping.Wrap
            };
            t.SetValue(Grid.RowProperty, 1);
            grid.Children.Add(b);
            grid.Children.Add(t);
            return new HyperlinkButton()
            {
                NavigateUri = new Uri(link),
                //TextDecorations = TextDecorations.Underline,
                Content = new Border()
                {
                    Child = grid,
                    Padding = new Thickness(4)
                },
                TargetName = "_blank",
                Padding = new Thickness(4)
            };
        }

        /// <summary>
        /// Process the server response
        /// The current handlers return the full url of the uploaded file, so we can browse it.
        /// We need to split the response in order to get the url per each file.
        /// </summary>
        /// <param name="response">The response returned from the server</param>
        /// <returns>The response returned per each uploaded file</returns>
        private string[] ProcessResponse(object response)
        {
            List<string> result = new List<string>();
            if (response is string[])
            {
                foreach (string responseString in response as string[])
                {
                    foreach (var link in responseString.Split(new char[] { '|' }))
                    {
                        if (!result.Contains(link))
                        {
                            result.Add(link);
                        }
                    }
                }
            }
            return result.ToArray();
        }

        #endregion

        #region Create Uploader

        /// <summary>
        /// Creates a <see cref="C1Uploader"/>.
        /// </summary>
        /// <param name="rootUri"><see cref="Uri"/> of the server that will handle the service requests.</param>
        /// <param name="filesPerRequest">Strategy used to package files into requests.</param>
        /// <returns>The new <see cref="C1Uploader"/>.</returns>
        private C1Uploader CreateUploader(FilesPerRequest filesPerRequest)
        {
            switch (Strategy)
            {
                // the file will be handled in the server by an ASP.NET Handler through the Request.Files collection
                case UploadStrategy.MultipartPost:
                    C1UploaderPost mpUploader = new C1UploaderPost(filesPerRequest);
                    mpUploader.Settings.Address = GetHandlerAddress(filesPerRequest);
                    return mpUploader;


                // the file will be handled in the server by a WebService
                case UploadStrategy.WebServices:
                    C1UploaderWebService wsUploader = new C1UploaderWebService(filesPerRequest);
                    wsUploader.Settings.Address = Extensions.GetAbsoluteUri("WebService.asmx");
                    wsUploader.Settings.Namespace = "http://www.componentone.com/";
                    return wsUploader;
            }

            return null;
        }

        /// <summary>
        /// Returns the server handler address.
        /// The handler is different for the Slice strategy and the other ones
        /// </summary>
        /// <param name="rootUri">Root URI of the server</param>
        /// <param name="filesPerRequest">Strategy used to package the files into upload requests.</param>
        /// <returns>The full URI of the handler for the specified <paramref name="filesPerRequest"/> value.</returns>
        private static Uri GetHandlerAddress(FilesPerRequest filesPerRequest)
        {
            return Extensions.GetAbsoluteUri(filesPerRequest == FilesPerRequest.SplitFilesIntoMultipleRequests ? "MergeHandler.ashx" : "Handler.ashx");
        }

        #endregion
    }

    /// <summary>
    /// Upload strategy
    /// </summary>
    public enum UploadStrategy
    {
        /// <summary>
        /// Multpart/post format. Standard upload method used for web browsers.
        /// </summary>
        MultipartPost,
        /// <summary>
        /// A webservice will handle the file upload in the server.
        /// </summary>
        WebServices
    }
}
