using C1.Xaml.Excel;
using System;
using System.Globalization;
using System.IO;
using System.Threading.Tasks;
using Windows.ApplicationModel.Activation;
using Windows.Storage;
using Windows.System;
using Windows.UI;
using Windows.UI.Popups;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace ControlExplorer
{
    public partial class DemoExcel : UserControl, IWebAuthenticationContinuable
    {
        #region ** fields

        private OneDriveHelper _helper = new OneDriveHelper();
        private string _accessToken;

        #endregion

        #region ** initialization

        public DemoExcel()
        {
            InitializeComponent();
        }

        #endregion

        #region ** imlementation

        private void btnHelloWorld_Click(object sender, RoutedEventArgs e)
        {
            UploadBookToOneDrive("Hello World.xlsx", book =>
            {
                book.Sheets[0][0, 0].Value = "Hello World";
            });
        }

        private void btnStyles_Click(object sender, RoutedEventArgs e)
        {
            UploadBookToOneDrive("Styles.xlsx", book =>
            {
                // get the sheet that was created by default, give it a name
                var sheet = book.Sheets[0];

                // create styles for odd and even values
                var styleOdd = new XLStyle(book);
                styleOdd.Font = new XLFont("Tahoma", 9, false, true);
                styleOdd.ForeColor = Colors.Blue;

                var styleEven = new XLStyle(book);
                styleEven.Font = new XLFont("Tahoma", 9, true, false);
                styleEven.ForeColor = Colors.Red;
                styleEven.BackColor = Colors.Yellow;

                // step 3: write content and format into some cells
                for (int i = 0; i < 30; i++)
                {
                    XLCell cell = sheet[i, 0];
                    cell.Value = i + 1;
                    cell.Style = ((i + 1) % 2 == 0) ? styleEven : styleOdd;
                }
            });
        }

        private void btnFormulas_Click(object sender, RoutedEventArgs e)
        {
            UploadBookToOneDrive("Formulas.xlsx", book =>
            {
                // first sheet
                var sheet = book.Sheets[0];

                // column width in twips
                sheet.Columns[0].Width = 2000;
                sheet.Columns[1].Width = 2200;

                // string formulas
                string s = "String:";
                sheet[0, 0].Value = s;
                sheet[1, 0].Value = s;
                sheet[2, 0].Value = s;

                sheet[0, 1].Value = "apples";
                sheet[1, 1].Value = "and";
                sheet[2, 1].Value = "oranges";

                s = "String formula:";
                sheet[4, 0].Value = s;
                sheet[5, 0].Value = s;

                sheet[4, 1].Value = "apples and oranges";
                sheet[5, 1].Value = "apples an";
                sheet[4, 1].Formula = "CONCATENATE(B1,\" \",B2, \" \",B3)";
                sheet[5, 1].Formula = "LEFT(B5,9)";

                // simple formulas
                sheet[7, 0].Value = "Formula: 5!";
                sheet[7, 1].Value = 120;
                sheet[7, 1].Formula = "1*2*3*4*5";

                sheet[8, 0].Value = "Formula: 12/0";
                sheet[8, 1].Value = 0;
                sheet[8, 1].Formula = "12/0";

                sheet[9, 0].Value = "Formula: 1 = 1";
                sheet[9, 1].Value = true;
                sheet[9, 1].Formula = "1=1";

                sheet[10, 0].Value = "Formula: 1 = 2";
                sheet[10, 1].Value = false;
                sheet[10, 1].Formula = "1 = 2";

                // now function
                sheet[12, 0].Value = "Formula: Now()";
                sheet[12, 1].Value = DateTime.Now;
                sheet[12, 1].Formula = "Now()";

                var style = new XLStyle(book);
                var dtfi = CultureInfo.CurrentCulture.DateTimeFormat;
                style.Format = XLStyle.FormatDotNetToXL(dtfi.ShortDatePattern + " " + dtfi.ShortTimePattern);
                sheet[12, 1].Style = style;
            });
        }

        const string FILE_NAME = "c1ExcelTest.xlsx";
        const string HTML_PART1 = "<html><head></head><body><a href=\"data:application/vnd.ms-excel;base64,";
        const string HTML_PART2 = "\">Open Excel File</a></body></html>";

        private async void SaveBook(Action<C1XLBook> action)
        {
            try
            {
                var book = new C1XLBook();
                if (action != null)
                {
                    action(book);
                }

                // save Excel content in base64
                string excelBase64 = "";
                using (var memoryStream = new MemoryStream())
                {
                    await book.SaveAsync(memoryStream, FileFormat.OpenXml);
                    memoryStream.Flush();
                    excelBase64 = Convert.ToBase64String(memoryStream.ToArray());
                }

                // create HTML file with inline Excel content
                // and save it to the IsolatedStorage 
                var folder = ApplicationData.Current.TemporaryFolder;
                var file = await folder.GetFileAsync(FILE_NAME);
                if (file != null)
                {
                    await file.DeleteAsync(StorageDeleteOption.PermanentDelete);
                }
                file = await folder.CreateFileAsync(FILE_NAME);
                using (var writer = new StreamWriter(await file.OpenStreamForWriteAsync()))
                {
                    writer.Write(HTML_PART1);
                    writer.Write(excelBase64);
                    writer.Write(HTML_PART2);
                }

            }
            catch (Exception x)
            {
                var dialog = new MessageDialog(x.Message);
                dialog.ShowAsync();
            }
        }

        public async void UploadBookToOneDrive(string fileName, Action<C1XLBook> createBook)
        {
            if (await Authenticate())
            {
                var prog = StatusBar.GetForCurrentView().ProgressIndicator;
                try
                {
                    var picker = new OneDriveFolderPicker(_accessToken);
                    var folder = await picker.PickFolderAsync(this);

                    prog.Text = "Uploading file to OneDrive...";
                    await prog.ShowAsync();

                    var stream = new MemoryStream();
                    var book = new C1XLBook();
                    createBook(book);
                    await book.SaveAsync(stream, FileFormat.OpenXml);
                    stream.Flush();
                    stream.Seek(0, SeekOrigin.Begin);

                    var contentType = "application/vnd.ms-excel";
                    var file = await OneDriveHelper.UploadFileAsync(_accessToken, fileName, contentType, folder, stream.AsInputStream(), percentage =>
                    {
                        prog.ProgressValue = percentage;
                    });
                    // Open Web browser task to see the file
                    prog.Text = "Getting file link...";
                    prog.ProgressValue = null;
                    var link = await OneDriveHelper.GetFileInfoAsync(_accessToken, file.Id);
                    await prog.HideAsync();
                    await Launcher.LaunchUriAsync(new Uri(link.Link, UriKind.Absolute));
                }
                catch (OperationCanceledException) { return; }
                catch
                {
                    prog.HideAsync();
                    var dialog = new MessageDialog("There was an error trying to upload the file to OneDrive. Please try again.");
                    dialog.ShowAsync();
                }
            }
        }

        public void ContinueWebAuthentication(WebAuthenticationBrokerContinuationEventArgs args)
        {
            _helper.ContinueAuthentication(args);
        }

        private async Task<bool> Authenticate()
        {
            if (_accessToken == null)
            {
                _helper = new OneDriveHelper();
                try
                {
                    _accessToken = await _helper.GetAccessTokenAsync();
                    return true;
                }
                catch (OperationCanceledException) { }
                catch
                {
                    var dialog = new MessageDialog("You could not get an access token, please check your internet connection.");
                    dialog.ShowAsync();
                }
                return false;
            }
            else
            {
                return true;
            }
        }

        #endregion
    }
}
