using System;

using Windows.ApplicationModel.Background;

using Windows.Devices.Bluetooth;

using Windows.Devices.Bluetooth.Rfcomm;

using Windows.Devices.Enumeration;

using Windows.Foundation;

using Windows.Storage;

using Windows.UI.Core;

using Windows.UI.Xaml;



namespace Zebra_RFID_Mobile

{

    public class ReaderWatcher

    {

        private DeviceWatcher deviceWatcher = null;

        private TypedEventHandler<DeviceWatcher, DeviceInformation> handlerAdded = null;

        //private TypedEventHandler<DeviceWatcher, DeviceInformationUpdate> handlerUpdated = null;

        private TypedEventHandler<DeviceWatcher, DeviceInformationUpdate> handlerRemoved = null;

        //private TypedEventHandler<DeviceWatcher, Object> handlerEnumCompleted = null;

        private TypedEventHandler<DeviceWatcher, Object> handlerStopped = null;

        private MainPage rootPage;

        private string backgroundTaskName = "BackgroundTaskNameDeviceConnectivity";

        //private string backgroundBatteryTaskName = "BackgroundTaskNameDeviceBattery";

        private IBackgroundTaskRegistration backgroundTaskRegistration = null;

        // A pointer to the ApplicationTrigger so we can signal it later

        ApplicationTrigger triggerApplication = null;



        public ReaderWatcher()

        {



        }



        public void StartWatcher()

        {

            rootPage = MainPage.Current;

            ReaderConnect readerobj = ReaderConnect.getInstance(); ;

            // Get the device selector chosen by the UI then add additional constraints for devices that 

            // can be paired or are already paired.

            {

                // Kind will be determined by the selector

                deviceWatcher = DeviceInformation.CreateWatcher(

                    BluetoothDevice.GetDeviceSelectorFromPairingState(true),

                    null // don't request additional properties for this sample

                    );

            }



            // Hook up handlers for the watcher events before starting the watcher



            handlerAdded = new TypedEventHandler<DeviceWatcher, DeviceInformation>(async (watcher, deviceInfo) =>

            {

                // Since we have the collection databound to a UI element, we need to update the collection on the UI thread.

                await rootPage.Dispatcher.RunAsync(CoreDispatcherPriority.Low, async () =>

                {

                    bool bfound = false;

                    if (readerobj.items != null)

                    {

                        foreach (readerinfo deviceInfoDisp in readerobj.items)

                        {

                            if (deviceInfoDisp.ID == deviceInfo.Id)

                            {

                                bfound = true;

                                break;

                            }

                        }

                    }

                    if (!bfound)

                    {

                        await readerobj.AddReader(deviceInfo);

                        BluetoothDevice bluetoothDevice = await BluetoothDevice.FromIdAsync(deviceInfo.Id);

                        //if (!MainPage.isApplicationWindowActive && ReaderConfig.connectionConfig.readerAvailable)

                        //    ToastHelper.PopToast(bluetoothDevice.Name, "Available");

                        if (MainPage.isApplicationWindowActive && ReaderConfig.connectionConfig.readerAvailable)

                            readerobj.showStatus(bluetoothDevice.Name, "Available");

                    }



                });

            });

            deviceWatcher.Added += handlerAdded;



            //handlerUpdated = new TypedEventHandler<DeviceWatcher, DeviceInformationUpdate>(async (watcher, deviceInfoUpdate) =>

            //{

            //    // Since we have the collection databound to a UI element, we need to update the collection on the UI thread.

            //    await rootPage.Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>

            //    {

            //        // Find the corresponding updated DeviceInformation in the collection and pass the update object

            //        // to the Update method of the existing DeviceInformation. This automatically updates the object

            //        // for us.

            //        foreach (readerinfo deviceInfoDisp in readerobj.items)

            //        {

            //            if (deviceInfoDisp.ID == deviceInfoUpdate.Id)

            //            {

            //                break;

            //            }

            //        }

            //    });

            //});

            //deviceWatcher.Updated += handlerUpdated;



            handlerRemoved = new TypedEventHandler<DeviceWatcher, DeviceInformationUpdate>(async (watcher, deviceInfoUpdate) =>

            {

                // Since we have the collection databound to a UI element, we need to update the collection on the UI thread.

                await rootPage.Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>

                {

                    // Find the corresponding DeviceInformation in the collection and remove it

                    if (readerobj.items != null)

                    {

                        foreach (readerinfo deviceInfoDisp in readerobj.items)

                        {

                            if (deviceInfoDisp.ID == deviceInfoUpdate.Id)

                            {

                                readerobj.items.Remove(deviceInfoDisp);

                                //if (!MainPage.isApplicationWindowActive && ReaderConfig.connectionConfig.readerAvailable)

                                //    ToastHelper.PopToast(deviceInfoDisp.DisplayName, "Disappeared");

                                if (MainPage.isApplicationWindowActive && ReaderConfig.connectionConfig.readerAvailable)

                                    readerobj.showStatus(deviceInfoDisp.DisplayName, "Disappeared");

                                break;

                            }

                        }

                    }

                });

            });

            deviceWatcher.Removed += handlerRemoved;



            //handlerEnumCompleted = new TypedEventHandler<DeviceWatcher, Object>(async (watcher, obj) =>

            //{

            //    await rootPage.Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>

            //    {



            //    });

            //});

            //deviceWatcher.EnumerationCompleted += handlerEnumCompleted;



            handlerStopped = new TypedEventHandler<DeviceWatcher, Object>(async (watcher, obj) =>

            {

                await rootPage.Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>

                {



                });

            });

            deviceWatcher.Stopped += handlerStopped;



            deviceWatcher.Start();



            DeviceWatcherEventKind[] triggerEventKinds = { DeviceWatcherEventKind.Add, DeviceWatcherEventKind.Remove, DeviceWatcherEventKind.Update };

            DeviceWatcher deviceWatcherTriggerReg = null;

            // Request additional properties

            string[] requestedProperties = new string[] { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected" };



            // Use AQS string selector from dynamic call to a device api's GetDeviceSelector call

            // Kind will be determined by the selector

            deviceWatcherTriggerReg = DeviceInformation.CreateWatcher(

                 BluetoothDevice.GetDeviceSelectorFromPairingState(true),

                requestedProperties

                );

            DeviceWatcherTrigger deviceWatcherTrigger = deviceWatcherTriggerReg.GetBackgroundTrigger(triggerEventKinds);

            // Register this trigger for our background task

            RegisterBackgroundTask(deviceWatcherTrigger);

        }



        public void StopWatcher()

        {

            if (null != deviceWatcher)

            {

                // First unhook all event handlers except the stopped handler. This ensures our

                // event handlers don't get called after stop, as stop won't block for any "in flight" 

                // event handler calls.  We leave the stopped handler as it's guaranteed to only be called

                // once and we'll use it to know when the query is completely stopped. 

                deviceWatcher.Added -= handlerAdded;

                //deviceWatcher.Updated -= handlerUpdated;

                deviceWatcher.Removed -= handlerRemoved;

                //deviceWatcher.EnumerationCompleted -= handlerEnumCompleted;



                if (DeviceWatcherStatus.Started == deviceWatcher.Status ||

                    DeviceWatcherStatus.EnumerationCompleted == deviceWatcher.Status)

                {

                    deviceWatcher.Stop();

                }

            }



        }



        //public async void registerReaderConnectionNotification(string id)

        //{

        //    var taskRegistered = false;

        //    var TaskName = "ReaderConnectionNotification";

        //    triggerConnection = await DeviceConnectionChangeTrigger.FromIdAsync(id);





        //    foreach (var task in BackgroundTaskRegistration.AllTasks)

        //    {

        //        if (task.Value.Name == TaskName)

        //        {

        //            //taskRegistered = true;

        //            task.Value.Unregister(true);

        //            break;

        //        }

        //    }

        //    if (!taskRegistered)

        //    {

        //        // Applications registering for background trigger must request for permission.

        //        BackgroundAccessStatus backgroundAccessStatus = await BackgroundExecutionManager.RequestAccessAsync();



        //        var builder = new BackgroundTaskBuilder();

        //        builder.Name = TaskName;

        //        builder.TaskEntryPoint = "Tasks.ReaderConnectionNotify";

        //        builder.SetTrigger(triggerConnection);

        //        try

        //        {

        //            BackgroundTaskRegistration taskRegistration = builder.Register();

        //            // Even though the trigger is registered successfully, it might be blocked. Notify the user if that is the case.

        //            if ((backgroundAccessStatus == BackgroundAccessStatus.AlwaysAllowed) || (backgroundAccessStatus == BackgroundAccessStatus.AllowedSubjectToSystemPolicy))

        //            {

        //                rootPage.NotifyUser("Background watcher registered.", NotifyType.StatusMessage);

        //            }

        //            else

        //            {

        //                rootPage.NotifyUser("Background tasks may be disabled for this app", NotifyType.ErrorMessage);

        //            }

        //        }

        //        catch (Exception)

        //        {

        //            rootPage.NotifyUser("Background task not registered",

        //                    NotifyType.ErrorMessage);

        //        }

        //    }

        //}



        private void RegisterBackgroundTask(DeviceWatcherTrigger deviceWatcherTrigger)

        {

            BackgroundTaskBuilder taskBuilder;

            var taskRegistered = false;

            // First see if we already have this background task registered. If so, unregister

            // it before we register it with the new trigger.



            foreach (var task in BackgroundTaskRegistration.AllTasks)

            {

                if (backgroundTaskName == task.Value.Name)

                {

                    taskRegistered = true;

                    //UnregisterBackgroundTask(task.Value);

                }

            }

            if (!taskRegistered)

            {

                taskBuilder = new BackgroundTaskBuilder();

                taskBuilder.Name = backgroundTaskName;

                taskBuilder.TaskEntryPoint = "Tasks.BackgroundDeviceWatcher";

                taskBuilder.SetTrigger(deviceWatcherTrigger);



                backgroundTaskRegistration = taskBuilder.Register();

                backgroundTaskRegistration.Completed += new BackgroundTaskCompletedEventHandler(OnTaskCompleted);

            }



            //foreach (var task in BackgroundTaskRegistration.AllTasks)

            //{

            //    if (backgroundBatteryTaskName == task.Value.Name)

            //    {

            //        //taskRegistered = true;

            //        UnregisterBackgroundTask(task.Value);

            //    }

            //}

            ////if (!taskRegistered)

            //{

            //    // register for application trigger

            //    triggerApplication = new ApplicationTrigger();

            //    var builder = new BackgroundTaskBuilder();

            //    builder.Name = backgroundBatteryTaskName;

            //    builder.TaskEntryPoint = "Tasks.BackgroundDeviceWatcher";

            //    builder.SetTrigger(triggerApplication);

            //    backgroundTaskRegistration = builder.Register();

            //}

        }



        private async void OnTaskCompleted(BackgroundTaskRegistration task, BackgroundTaskCompletedEventArgs args)

        {

            await rootPage.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>

            {

                rootPage.NotifyUser("Background task completed", NotifyType.StatusMessage);

            });

        }



        private void UnregisterBackgroundTask(IBackgroundTaskRegistration taskReg)

        {

            taskReg.Unregister(true);

        }



        public void UnregisterBackgroundTasks()

        {

            foreach (var task in BackgroundTaskRegistration.AllTasks)

            {

                //if (backgroundBatteryTaskName == task.Value.Name)

                //{

                //    UnregisterBackgroundTask(task.Value);

                //}

                if (backgroundTaskName == task.Value.Name)

                {

                    UnregisterBackgroundTask(task.Value);

                }

            }



        }



    }



}

