using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.Media.Capture;
using Windows.Devices.Enumeration;
using Windows.Media.Devices;
using Windows.Media;
using Windows.Media.MediaProperties;
using System.Diagnostics;
using Windows.Storage.Streams;
using Quobject.SocketIoClientDotNet.Client;

using Windows.Storage.Pickers;
using Windows.Storage;
using Windows.ApplicationModel.Activation;
using Windows.ApplicationModel.Core;
using System.Threading.Tasks;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=391641

namespace LDClient
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page, IFileOpenPickerContinuable
    {
        public ContinuationManager ContinuationManager { get; private set; }
        private MediaCapture _mediaCaptureManager;
        private InMemoryRandomAccessStream myRecordingStream;
        private bool _userRequestedRaw;
        private bool _rawAudioSupported;

        private Socket socket;
        private CoreApplicationView view;
        private string photoPath;

        public MainPage()
        {
            this.InitializeComponent();
           
            this.InitializeAudioRecording();
            this.NavigationCacheMode = NavigationCacheMode.Required;

            socket = IO.Socket("http://162.246.156.14:1337");
            socket.On(Socket.EVENT_CONNECT, () =>
            {
                Debug.WriteLine("Socket connected");
                socket.Emit("hi", "testing");
            });
            socket.On("alarmOff", (data) =>
            {
                txtDebugStatus.Text = "Alarm turned off remotely";
            });
        }

        /// <summary>
        /// Invoked when this page is about to be displayed in a Frame.
        /// </summary>
        /// <param name="e">Event data that describes how this page was reached.
        /// This parameter is typically used to configure the page.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            //do nothing, one page only
        }

        private async void InitializeAudioRecording()
        {
            Debug.WriteLine("Initializing audio recording settings...");
            _mediaCaptureManager = new MediaCapture();
            var settings = new MediaCaptureInitializationSettings();
            settings.StreamingCaptureMode = StreamingCaptureMode.Audio;
            settings.MediaCategory = MediaCategory.Other;
            settings.AudioProcessing = (_rawAudioSupported && _userRequestedRaw) ? AudioProcessing.Raw : AudioProcessing.Default;
            await _mediaCaptureManager.InitializeAsync(settings);
            Debug.WriteLine("Device initialised successfully");
            
            _mediaCaptureManager.RecordLimitationExceeded += new RecordLimitationExceededEventHandler(RecordLimitationExceeded);
            _mediaCaptureManager.Failed += new MediaCaptureFailedEventHandler(Failed);
        }

        private void Failed(MediaCapture sender, MediaCaptureFailedEventArgs errorEventArgs)
        {
            Debug.WriteLine("FAILED: Failed to capture audio");
        }

        private void RecordLimitationExceeded(MediaCapture sender)
        {
            Debug.WriteLine("RECORD LIMITATION EXCEEDED: Failed to capture audio");
        }

        private async void btnRecord_PointerReleased(object sender, PointerRoutedEventArgs e)
        {
            try
            {
                Debug.WriteLine("Stopping recording");
                await _mediaCaptureManager.StopRecordAsync();
                Debug.WriteLine("Stop recording successful");

                await myRecordingStream.FlushAsync();
                myRecordingStream.Seek(0);

                byte[] bytes = new byte[myRecordingStream.Size];
                await myRecordingStream.ReadAsync(bytes.AsBuffer(), (uint)myRecordingStream.Size, InputStreamOptions.None);

                socket.Emit("voiceMessage", Convert.ToBase64String(bytes));
                txtDebugStatus.Text = "Voice message sent!";
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Failed to record after released, did not send anything.");
                txtDebugStatus.Text = "Oops, please try again!";
            }
        }

        private async void btnRecord_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                Debug.WriteLine("Starting record");
                txtDebugStatus.Text = "Recording...!";

                MediaEncodingProfile recordProfile = MediaEncodingProfile.CreateWav(AudioEncodingQuality.Auto);
                myRecordingStream = new InMemoryRandomAccessStream();
                await _mediaCaptureManager.StartRecordToStreamAsync(recordProfile, myRecordingStream);
                Debug.WriteLine("Start Record successful");
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Failed to start audio capture");
                txtDebugStatus.Text = "Oops, please try again!";
            }
        }

        public void ContinueFileOpenPicker(Windows.ApplicationModel.Activation.FileOpenPickerContinuationEventArgs args)
        {
            if (args.Files.Count > 0)
            {
                txtDebugStatus.Text = "Picked photo: " + args.Files[0].Name;
            }
            else
            {
                txtDebugStatus.Text = "Photo select cancelled.";
            }
        }

        private void btnPhoto_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                view = CoreApplication.GetCurrentView();

                FileOpenPicker picker = new FileOpenPicker();
                picker.FileTypeFilter.Add(".png");
                picker.FileTypeFilter.Add(".jpg");
                picker.FileTypeFilter.Add(".jpeg");
                picker.ViewMode = Windows.Storage.Pickers.PickerViewMode.Thumbnail;
                picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
                view.Activated += viewActivated;
                picker.PickSingleFileAndContinue();
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Error trying to select photo: " + ex.Message);
                txtDebugStatus.Text = "Oops, please try again!";
            }
        }

        private async void viewActivated(CoreApplicationView sender, IActivatedEventArgs args1)
        {
            try
            {
                FileOpenPickerContinuationEventArgs args = args1 as FileOpenPickerContinuationEventArgs;
                photoPath = args.Files[0].Path;

                if (args != null)
                {
                    if (args.Files.Count == 0) return;

                    view.Activated -= viewActivated;
                    var uri = new System.Uri(@photoPath, UriKind.Absolute);
                    var file = await Windows.Storage.StorageFile.GetFileFromPathAsync(photoPath);
                    var bytes = new Byte[0];
                    using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read))
                    {
                        var reader = new DataReader(fileStream.GetInputStreamAt(0));
                        bytes = new Byte[fileStream.Size];
                        await reader.LoadAsync((uint)fileStream.Size);
                        reader.ReadBytes(bytes);
                    }

                    string imageInStringFormat = Convert.ToBase64String(bytes);
                    socket.Emit("updatePhoto", imageInStringFormat);
                    txtDebugStatus.Text = "Photo sent!";
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Error trying to update photo: " + ex.Message);
            }
        }

        private void btnAlarm_Click(object sender, RoutedEventArgs e)
        {
            socket.Emit("alarmOn", "");
        }
    }
}
