// ABBYY® Mobile Capture © 2019 ABBYY Production LLC.
// ABBYY is a registered trademark or a trademark of ABBYY Software Ltd.

using MobileCapture.Forms.Common;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace MobileCapture.Sample
{
    public interface IImageViewer
    {
        ImageSource Image { get; }
    }

    class ImageViewer : IImageViewer
    {
        public string ImagePath;
        public ImageSource Image => ImageSource.FromFile(ImagePath);
    }

    public class OptionsViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public UISettings UISettings { get; private set; }
        public CameraSettings CameraSettings { get; private set; }
        public ImageCaptureSettings ImageCaptureSettings { get; private set; }
        public IImageCaptureResult ImageCaptureResult;

        public Command StartImageCaptureCommand { get; private set; }
        public Command OpenPdfCommand { get; private set; }
        public ObservableCollection<IImageViewer> Pages { get; private set; }

        private bool hasPdfResult;
        public bool HasPdfResult
        {
            get => hasPdfResult;
            set
            {
                hasPdfResult = value;
                OnPropertyChanged(nameof(HasPdfResult));
            }
        }

        private bool hasImagesResult;
        public bool HasImagesResult
        {
            get => hasImagesResult;
            set
            {
                hasImagesResult = value;
                OnPropertyChanged(nameof(HasImagesResult));
            }
        }

        private string PdfPath;

        public OptionsViewModel()
        {
            Pages = new ObservableCollection<IImageViewer>();
            UISettings = new UISettings();
            ImageCaptureSettings = new ImageCaptureSettings();
            CameraSettings = new CameraSettings();
            StartImageCaptureCommand = new Command(async () =>
            {
                await StartImageCaptureAsync();
            });
            OpenPdfCommand = new Command(async () => {
                await ExportToPdfAsync();
            });
        }

        private async Task StartImageCaptureAsync()
        {
            Pages.Clear();
            var capture = DependencyService.Get<ICapture>();
            HasImagesResult = false;
            HasPdfResult = HasImagesResult;
            try
            {
                ImageCaptureResult = await capture.StartImageCaptureAsync(
                    UISettings, CameraSettings, ImageCaptureSettings
                );
                if (ImageCaptureResult != null)
                {
                    Pages = new ObservableCollection<IImageViewer>(ImageCaptureResult.Pages.Select((page) =>
                    {
                        return new ImageViewer() { ImagePath = page.ImagePath };
                    }));
                    HasImagesResult = Pages.Count > 0;
                    HasPdfResult = HasImagesResult;
                    OnPropertyChanged(nameof(Pages));
                }
            }
            catch (TaskCanceledException e)
            {
                await Application.Current.MainPage.DisplayAlert("Canceled", e.Message, "Cancel");
            }
            catch (Exception e)
            {
                await Application.Current.MainPage.DisplayAlert("Error occurred", e.Message, "Cancel");
            }
        }

        private async Task ExportToPdfAsync()
        {
            try
            {
                var pdfViewer = DependencyService.Get<IPdfViewer>();
                if (PdfPath == null)
                {
                    PdfPath = pdfViewer.PdfPath;
                }
                await ImageCaptureResult.ExportToPdfAsync(PdfPath);
                pdfViewer.Show(PdfPath);
            }
            catch (Exception e)
            {
                await Application.Current.MainPage.DisplayAlert("Error occurred", e.Message, "Cancel");
            }
        }

        /* UI Elements */

        public List<string> OrientationNames => Enum.GetNames(typeof(UISettings.SupportedOrientation)).ToList();

        public string SelectedOrientation
        {
            get => UISettings.Orientation.ToString();
            set
            {
                UISettings.Orientation = (UISettings.SupportedOrientation)
                    Enum.Parse(typeof(UISettings.SupportedOrientation), value);
                OnPropertyChanged(nameof(SelectedOrientation));
            }
        }

        public List<string> ResolutionNames => Enum.GetNames(typeof(CameraSettings.Resolution)).ToList();

        public string SelectedResolution
        {
            get => CameraSettings.SelectedResolution.ToString();
            set
            {
                CameraSettings.SelectedResolution = (CameraSettings.Resolution)
                    Enum.Parse(typeof(CameraSettings.Resolution), value);
                OnPropertyChanged(nameof(SelectedResolution));
            }
        }

        public List<string> CompressionTypes => Enum.GetNames(typeof(ImageCaptureSettings.CompressionType)).ToList();

        public string SelectedCompression
        {
            get => ImageCaptureSettings.PageCompressionType.ToString();
            set
            {
                ImageCaptureSettings.PageCompressionType = (ImageCaptureSettings.CompressionType)
                    Enum.Parse(typeof(ImageCaptureSettings.CompressionType), value);
                OnPropertyChanged(nameof(SelectedCompression));
            }
        }

        public List<string> CompressionLevels => Enum.GetNames(typeof(ImageCaptureSettings.CompressionLevel)).ToList();

        public string SelectedCompressionLevel
        {
            get => ImageCaptureSettings.PageCompressionLevel.ToString();
            set
            {
                ImageCaptureSettings.PageCompressionLevel = (ImageCaptureSettings.CompressionLevel)
                    Enum.Parse(typeof(ImageCaptureSettings.CompressionLevel), value);
                OnPropertyChanged(nameof(SelectedCompressionLevel));
            }
        }

        public bool IsFlashlightButtonVisible
        {
            get => UISettings.IsFlashlightButtonVisible;
            set
            {
                UISettings.IsFlashlightButtonVisible = value;
                OnPropertyChanged(nameof(IsFlashlightButtonVisible));
            }
        }

        public bool IsCaptureButtonVisible
        {
            get => UISettings.IsCaptureButtonVisible;
            set
            {
                UISettings.IsCaptureButtonVisible = value;
                OnPropertyChanged(nameof(IsCaptureButtonVisible));
            }
        }

        public bool IsGalleryButtonVisible
        {
            get => UISettings.IsGalleryButtonVisible;
            set
            {
                UISettings.IsGalleryButtonVisible = value;
                OnPropertyChanged(nameof(IsGalleryButtonVisible));
            }
        }

        public bool ShouldShowPreview
        {
            get => ImageCaptureSettings.ShouldShowPreview;
            set
            {
                ImageCaptureSettings.ShouldShowPreview = value;
                OnPropertyChanged(nameof(ShouldShowPreview));
            }
        }

        public string RequiredPageCount
        {
            get => ImageCaptureSettings.RequiredPageCount.ToString();
            set
            {
                int.TryParse(value, out int intValue);
                ImageCaptureSettings.RequiredPageCount = intValue;
                OnPropertyChanged(nameof(RequiredPageCount));
            }
        }

        public string ImageFromGalleryMaxSize
        {
            get => ImageCaptureSettings.ImageFromGalleryMaxSize.ToString();
            set
            {
                int.TryParse(value, out int intValue);
                ImageCaptureSettings.ImageFromGalleryMaxSize = intValue;
                OnPropertyChanged(nameof(ImageFromGalleryMaxSize));
            }
        }

        public float MinDocToViewRatio
        {
            get => ImageCaptureSettings.MinDocToViewRatio;
            set
            {
                ImageCaptureSettings.MinDocToViewRatio = value;
                OnPropertyChanged(nameof(MinDocToViewRatio));
            }
        }

        public float AspectRatioMin
        {
            get => ImageCaptureSettings.AspectRatioMin;
            set
            {
                if (value > 0 && value < 1)
                {
                    value = 1;
                }
                ImageCaptureSettings.AspectRatioMin = value;
                if (ImageCaptureSettings.AspectRatioMax < ImageCaptureSettings.AspectRatioMin)
                {
                    AspectRatioMax = ImageCaptureSettings.AspectRatioMin;
                }
                OnPropertyChanged(nameof(AspectRatioMin));
            }
        }

        public float AspectRatioMax
        {
            get => ImageCaptureSettings.AspectRatioMax;
            set
            {
                if (value > 0 && value < 1)
                {
                    value = 1;
                }
                ImageCaptureSettings.AspectRatioMax = value;
                if (ImageCaptureSettings.AspectRatioMax < ImageCaptureSettings.AspectRatioMin)
                {
                    AspectRatioMin = ImageCaptureSettings.AspectRatioMax;
                }
                OnPropertyChanged(nameof(AspectRatioMax));
            }
        }

        public List<string> DocumentSizes => new List<string>
        {
            "Any",
            "A4",
            "BusinessCard",
            "Letter",
            "100 100"
        };

        public List<ImageCaptureSettings.DocumentSize> DocumentSizeValues => new List<ImageCaptureSettings.DocumentSize>
        {
            ImageCaptureSettings.DocumentSize.Any,
            ImageCaptureSettings.DocumentSize.A4,
            ImageCaptureSettings.DocumentSize.BusinessCard,
            ImageCaptureSettings.DocumentSize.Letter,
            new ImageCaptureSettings.DocumentSize(100, 100)
        };

        private int _selectedDocumentSizeIndex;
        public int SelectedDocumentSizeIndex
        {
            get => _selectedDocumentSizeIndex;
            set
            {
                _selectedDocumentSizeIndex = value;
                ImageCaptureSettings.PageSize = DocumentSizeValues[value];
                OnPropertyChanged(nameof(SelectedDocumentSizeIndex));
            }
        }

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
