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 C1.Silverlight;
using C1.Silverlight.Uploader;
using System.ComponentModel;
using System.Windows.Media.Imaging;
using System.Windows.Browser;
using System.IO;
using SamplesCommon;

namespace UploadFiles
{
    public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();

            // address
            txtAddress.Text = Extensions.GetAbsoluteUri("").ToString();

            // communication method
            cboCommunication.Items.Add("Web Service");
            cboCommunication.Items.Add("Post/multipart");

            // reques per files combo
            cboRequests.Items.Add(new FilesPerRequestWrapper(FilesPerRequest.AllFilesInOneRequest));
            cboRequests.Items.Add(new FilesPerRequestWrapper(FilesPerRequest.OneFilePerRequest));
            cboRequests.Items.Add(new FilesPerRequestWrapper(FilesPerRequest.SplitFilesIntoMultipleRequests));

            UpdateVisuals();
        }

        // -------------------------------------------------------------------------------------
        #region ** event handling

        private void cboCommunication_SelectedItemChanged(object sender, PropertyChangedEventArgs<object> e)
        {
            UpdateVisuals();
        }

        private void cboRequests_SelectedItemChanged(object sender, PropertyChangedEventArgs<object> e)
        {
            UpdateVisuals();
        }

        private void C1FilePicker_SelectedFilesChanged(object sender, EventArgs e)
        {
            selectedFiles.ItemsSource = filePicker.SelectedFiles;
        }

        private void Upload_Click(object sender, RoutedEventArgs e)
        {
            FilesPerRequest fr = (cboRequests.SelectedItem as FilesPerRequestWrapper).Internal;

            // check pre-condition
            if (!IsValidFilePickerSelection())
            {
                return;
            }

            // Create uploader..
            C1Uploader uploader = CreateUploader(txtAddress.Text, fr);
            if (uploader == null)
            {
                ShowError("Cannot create the uploader");
                return;
            }

            // set custom parameters
            uploader.MaximumUploadSize = ((long) numMaxUploadSize.Value) * 1024;
            uploader.AddFiles(filePicker.SelectedFiles);
            uploader.Parameters["parameter"] = "this is a CUSTOM parameter sent from the client to the server";

            // disable the UI
            rectDisabled.Visibility = Visibility.Visible;

            // handle events
            uploader.UploadProgressChanged += new EventHandler<C1.Silverlight.Uploader.UploadProgressChangedEventArgs>(uploader_UploadProgressChanged);
            uploader.UploadCompleted += new EventHandler<UploadCompletedEventArgs>(uploader_UploadCompleted);
            try
            {
                // start upload
                uploader.BeginUploadFiles();
            }
            catch (Exception exc)
            {
                ShowError(exc.Message);
                rectDisabled.Visibility = Visibility.Collapsed;
            }
        }

        void uploader_UploadCompleted(object sender, UploadCompletedEventArgs e)
        {
            rectDisabled.Visibility = Visibility.Collapsed;
            if (e.Success)
            {
                uploadedFiles.Items.Clear();
                foreach (var file in ProcessResponse(e.Response))
                {
                    uploadedFiles.Items.Add(CreateLink(file));
                }
            }
            else 
            {
                ShowError(e.Error.Message);
            }
        }

        void uploader_UploadProgressChanged(object sender, C1.Silverlight.Uploader.UploadProgressChangedEventArgs e)
        {
            txtUploadPct.Text = String.Format("{0} %", e.ProgressPercentage);
        }

        #endregion

        // -------------------------------------------------------------------------------------
        #region ** private stuff

        private void UpdateVisuals()
        {
            if ((cboRequests.SelectedItem == null) || (cboCommunication.SelectedItem == null))
                return;

            FilesPerRequest filesPerRequest = ((FilesPerRequestWrapper)cboRequests.SelectedItem).Internal;

            string handler;
            string comm = IsWebService ? "web service call" : "multipart post";
            string collection = IsWebService ? "Files parameter" : "Request.Files collection";
            string text = string.Empty;

            server_OneFilePerRequest_WebService.Visibility = Visibility.Collapsed;
            server_OneFilePerRequest_MultiPartHost.Visibility = Visibility.Collapsed;
            server_AllFilesInOneRequest_WebService.Visibility = Visibility.Collapsed;
            server_AllFilesInOneRequest_MultiPartHost.Visibility = Visibility.Collapsed;
            server_SplitFilesIntoMultipleRequests_WebService.Visibility = Visibility.Collapsed;
            server_SplitFilesIntoMultipleRequests_MultiPartHost.Visibility = Visibility.Collapsed;

            UIElement face;

            switch (filesPerRequest)
            {
                case FilesPerRequest.OneFilePerRequest:
                    handler = IsWebService ? "the webmethod called UploadFile" : "Handler.ashx";
                    text = "A {0} will be made for each file.\n\n" +
                           "In the server, {1} will receive only one file at a time.";
                    face = IsWebService ? server_OneFilePerRequest_WebService : server_OneFilePerRequest_MultiPartHost;
                    break;

                case FilesPerRequest.AllFilesInOneRequest:
                    handler = IsWebService ? "the webmethod called UploadFiles" : "Handler.ashx";
                    text = "All the files will be uploaded in the same {0}.\n\n" +
                           "In the server, {1} will receive all the files in the {2}.";
                    face = IsWebService ? server_AllFilesInOneRequest_WebService : server_AllFilesInOneRequest_MultiPartHost;
                    break;

                case FilesPerRequest.SplitFilesIntoMultipleRequests:
                default:
                    handler = IsWebService ? "the webmethod called UploadFile" : "MergeHandler.ashx";
                    text = "The files will be splitted into small parts (bounded by its size in KB, using the MaximumUploadSize property) {0}.\n\n" +
                           "In the server, {1} will process each part as needed.\n";
                    face = IsWebService ? server_SplitFilesIntoMultipleRequests_WebService : server_SplitFilesIntoMultipleRequests_MultiPartHost;
                    break;
            }
            
            face.Visibility = Visibility.Visible;

            txtDescription.Text = string.Format(text, comm, handler, collection);
        }

        private bool IsWebService
        {
            get
            {
                return (cboCommunication.SelectedItem.ToString() == "Web Service");
            }
        }

        /// <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(string rootUri, FilesPerRequest filesPerRequest)
        {
            if (IsWebService)
            {
                C1UploaderWebService wsUploader = new C1UploaderWebService(filesPerRequest);
                wsUploader.Settings.Address = Extensions.GetAbsoluteUri("WebService.asmx");
                wsUploader.Settings.Namespace = "http://www.componentone.com/";
                wsUploader.Parameters["hola"] = "test";
                return wsUploader;
            }
            else
            {
                C1UploaderPost mpUploader = new C1UploaderPost(filesPerRequest);
                mpUploader.Settings.Address = GetHandlerAddress(rootUri, filesPerRequest);
                return mpUploader;
            }
        }

        /// <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(string rootUri, FilesPerRequest filesPerRequest)
        {
            return Extensions.GetAbsoluteUri(filesPerRequest == FilesPerRequest.SplitFilesIntoMultipleRequests ? "MergeHandler.ashx" : "Handler.ashx");
        }

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

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

            // check that the files really are images
            try
            {
                foreach (FileInfo fdi in filePicker.SelectedFiles)
                {
                    BitmapImage img = new BitmapImage();
                    img.SetSource(fdi.OpenRead());
                }
            }
            catch (Exception)
            {
                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;
        }

        /// <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();
        }


        private static HyperlinkButton CreateLink(string link)
        {
            string[] imageExtension = { ".jpg", ".png", ".gif" };
            Grid grid = new Grid();
            grid.RowDefinitions.Add(new RowDefinition()
            {
                Height = new GridLength(40)
            });
            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,
                TextDecorations = TextDecorations.Underline,
            };
            t.SetValue(Grid.RowProperty, 1);
            grid.Children.Add(b);
            grid.Children.Add(t);
            return new HyperlinkButton()
            {
                NavigateUri = new Uri(link),
                Content = new Border()
                {
                    Child = grid,
                    Padding = new Thickness(4)
                },
                TargetName = "_blank",
                Padding = new Thickness(4)
            };
        }

        #endregion
    }

    // -------------------------------------------------------------------------------------
    #region ** FilesPerRequest enum wrapper for combo

    public class FilesPerRequestWrapper
    {
        public FilesPerRequest Internal {get; set;}

        public FilesPerRequestWrapper(FilesPerRequest fr) 
        {
            Internal = fr;
        }


        public override string ToString()
        {
            switch (Internal)
            {
                case FilesPerRequest.OneFilePerRequest:
                    return "One file per request";
                    
                case FilesPerRequest.AllFilesInOneRequest:
                    return "All files in one request";
                    
                case FilesPerRequest.SplitFilesIntoMultipleRequests:
                default:
                    return "Split files into multiple request";
            }
        }
    }

    #endregion
}
