public bool removeTaskFromSchedule(SmartTask task) // Returns: T/F on whether or not the remove was successful
        {
            LinkedList <SmartTask> taskList;
            DateTime date = task.when.Date;

            // Add new task - inset into LinkedList
            if (taskSchedule.TryGetValue(date, out taskList))
            {
                taskList.Remove(task);

                // Check if that was the only task for that date - if so, remove the list
                if (taskList.Count == 0)
                {
                    if (!taskSchedule.Remove(date))
                    {
                        Debug.WriteLine($"Error removing empty schedule at date {date}");
                    }
                }

                return(true);
            }
            else
            {
                Debug.WriteLine($"Remove Task Error: Task list not found for date {date}");
                return(false);
            }
        }
        public SmartSchedule(ApplicationDataContainer container, string scheduleID)
        {
            // Load an existing schedule from application data storage given its ID string
            taskSchedule    = new Dictionary <DateTime, LinkedList <SmartTask> >();
            startupSettings = container;
            try
            {
                // Retrieve the data from application memory (note: open existing)
                scheduleData = startupSettings.CreateContainer(scheduleID, ApplicationDataCreateDisposition.Existing);
            }
            catch (Exception e)
            {
                Debug.WriteLine($"Error {e.Message}: Schedule at {scheduleID} does not exist in local storage!");
                return;
            }
            // Fill in data from the container
            calID          = (uint)scheduleData.Values["calID"];
            numTasks       = (uint)scheduleData.Values["numTasks"];
            Title          = (string)scheduleData.Values["title"];
            color          = DataStorageTransformations.SolidColorBrush_FromStorageString((string)scheduleData.Values["color"]);
            dateCreated    = DataStorageTransformations.DateTime_FromStorageString((string)scheduleData.Values["dateCreated"]);
            tasksContainer = scheduleData.CreateContainer("tasks", ApplicationDataCreateDisposition.Existing);

            // Store and load tasks from memory!
            string taskKeys = (string)scheduleData.Values["storageKeys"];

            if (taskKeys.Length > 0)
            {
                // Only try to add tasks if a key exists
                storageKeys  = taskKeys.Split('`').ToList <string>();
                taskSchedule = new Dictionary <DateTime, LinkedList <SmartTask> >();
                foreach (string key in storageKeys.ToList())
                {
                    if (key.Length > 0)
                    {
                        SmartTask newTask = new SmartTask(tasksContainer, key);
                        if (newTask.title != null)
                        {
                            this.AddTask(newTask, false);
                        }
                    }
                }
            }
            else
            {
                storageKeys = new List <string>(); // Stored as one continuous string separated by spaces in memory
            }
        }
        public bool DeleteTask(SmartTask task) // Deletes a task from app memory then removes it from the SmartSchedule data structure
        {
            bool   status     = true;          // Return value for whether or not it succeeded
            string taskID     = task.StorageID();
            string scheduleID = this.StorageID();

            Debug.WriteLine($"(UNFINISHED) Deleting task: {taskID} from schedule {scheduleID}");

            // Retrieve the data from application memory (note: open existing)
            scheduleData = startupSettings.CreateContainer(scheduleID, ApplicationDataCreateDisposition.Existing);

            // Remove task key from storage keys
            if (storageKeys.Contains(taskID))
            {
                storageKeys.Remove(taskID);
            }
            else
            {
                Debug.WriteLine($"Unexpected error: {taskID} not found in storage keys!");
                status = false;
            }
            scheduleData.Values.Remove("storageKeys");
            scheduleData.Values["storageKeys"] = storageKeysString;

            // Remove task from app storage
            try
            {
                tasksContainer.DeleteContainer(taskID);
            }
            catch (Exception e)
            {
                Debug.WriteLine($"Error in task delete from SmartSchedule: Task container {taskID} was not found.\nException message: {e.Message}");
            }

            // Remove task from SmartSchedule - return value represents whether or not the remove was successful
            status = removeTaskFromSchedule(task) && status;

            // Update the UI to reflect a new task added to the schedule
            //PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(main_LV_schedule.ItemsSource)));

            return(status);
        }
        // Creates and returns the SmartTask object in the respected schedule, but DOES NOT ADD IT TO THE SCHEDULE
        public SmartTask CreateTask(uint eventID, DateTimeOffset date, int hour, int minute, int durHour, int durMinute, TaskType taskType, RepeatType repeatType, string title, string description, YN required, string url)
        {
            // Create SmartTask object out of the text fields
            SmartTask newTask = new SmartTask(eventID, this);

            // Get full DateTime from composite boxes
            DateTime when = new DateTime(date.Year, date.Month, date.Day, hour, minute, 0);

            // Get duration
            newTask.taskType      = taskType;
            newTask.repeatType    = repeatType;
            newTask.when          = when;
            newTask.title         = title;
            newTask.description   = description;
            newTask.required      = required;
            newTask.timeRemaining = newTask.duration = new TimeSpan(durHour, durMinute, 0);
            newTask.url           = url;

            // Creates the SmartTask item
            return(newTask);
        }
        private void PB_UpdateSelectedTask(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine($"Updating task: {(SmartTask)((Button)sender).DataContext}");

            // Get XAML items from Grid
            Grid elements = (Grid)((Button)sender).Parent;

            // Retrieve each field from the edit menu
            try
            {
                DateTimeOffset date        = (DateTimeOffset)((CalendarDatePicker)elements.FindName("CDP_edit_date")).Date;
                int            hour        = (int)((TimePicker)elements.FindName("TP_edit_time")).SelectedTime.Value.Hours;
                int            minute      = (int)((TimePicker)elements.FindName("TP_edit_time")).SelectedTime.Value.Minutes;
                int            durHour     = (int)((ComboBox)elements.FindName("TB_edit_durHours")).SelectedItem;
                int            durMinute   = (int)((ComboBox)elements.FindName("TB_edit_durMins")).SelectedItem;
                TaskType       taskType    = (TaskType)((ComboBox)elements.FindName("CB_edit_taskType")).SelectedItem;
                RepeatType     repeatType  = (RepeatType)((ComboBox)elements.FindName("CB_edit_repeat")).SelectedItem;
                string         title       = ((TextBox)elements.FindName("TB_edit_title")).Text;
                string         description = ((TextBox)elements.FindName("TB_edit_description")).Text;
                YN             required    = (YN)((ComboBox)elements.FindName("CB_edit_required")).SelectedItem;
                string         url         = ((TextBox)elements.FindName("TB_edit_url")).Text;

                // Create a new task from the schedule
                SmartTask newTask = schedule.CreateTask(nextEventID++, date, hour, minute, durHour, durMinute, taskType, repeatType, title, description, required, url);

                // Remove the existing task
                ((SmartTask)((Button)sender).DataContext).DeleteTask();

                // Add the updated task back to the schedule
                schedule.AddTask(newTask);
            }
            catch (Exception err)
            {
                Debug.WriteLine($"Exception thrown in task update: {err.Message}");
            }

            RefreshScheduleView();
        }
        private void PB_AddToSchedule_Click(object sender, RoutedEventArgs e)
        {
            bool filled = true;

            // Check to see if required fields are filled in:

            // Title
            if (TB_NewTitle.Text.Length == 0)
            {
                filled = false;
                TB_AsteriskTitle.Text = "*";
            }
            else
            {
                TB_AsteriskTitle.Text = "";
            }

            // Date
            if (!CDP_NewItemDate.Date.HasValue)
            {
                filled = false;
                TB_AsteriskDate.Text = "*";
            }
            else
            {
                TB_AsteriskDate.Text = "";
            }

            // Task type
            if (CB_TypePicker.SelectedItem == null)
            {
                filled = false;
                TB_AsteriskType.Text = "*";
            }
            else
            {
                TB_AsteriskType.Text = "";
            }

            // Duration is not required for a FullDay event
            if ((TaskType)CB_TypePicker.SelectedItem != TaskType.FullDay && CB_DurHoursPicker == null)
            {
                filled = false;
                TB_AsteriskDuration.Text = "*";
            }
            else
            {
                TB_AsteriskDuration.Text = "";
            }

            // Duration is not required for a FullDay event
            if ((TaskType)CB_TypePicker.SelectedItem != TaskType.FullDay && CB_DurMinsPicker == null)
            {
                filled = false;
                TB_AsteriskDuration.Text = "*";
            }
            else
            {
                TB_AsteriskDuration.Text = "";
            }

            // Time
            if ((TaskType)CB_TypePicker.SelectedItem != TaskType.FullDay && !TP_NewItemTime.SelectedTime.HasValue)
            {
                filled = false;
                TB_AsteriskTime.Text = "*";
            }
            else
            {
                TB_AsteriskTime.Text = "";
            }

            // Required?
            if (CB_RequiredPicker.SelectedValue == null)
            {
                filled = false;
                TB_AsteriskRequired.Text = "*";
            }
            else
            {
                TB_AsteriskRequired.Text = "";
            }

            // Repeat
            if (CB_RepeatPicker.SelectedValue == null)
            {
                filled = false;
                TB_AsteriskRepeat.Text = "*";
            }
            else
            {
                TB_AsteriskRepeat.Text = "";
            }


            if (!filled)
            {
                TB_RequiredFields.Text = "The marked(*) fields are required.";
                return;
            }
            // Remove failed text markers from UI
            TB_RequiredFields.Text = "";

            // Create SmartTask object out of the text fields

            // Get full DateTime from composite boxes
            DateTimeOffset date   = CDP_NewItemDate.Date.Value;
            int            hour   = TP_NewItemTime.SelectedTime.Value.Hours;
            int            minute = TP_NewItemTime.SelectedTime.Value.Minutes;
            DateTime       when   = new DateTime(date.Year, date.Month, date.Day, hour, minute, 0);

            // Get duration
            int        durHour    = (int)CB_DurHoursPicker.SelectedItem;
            int        durMinute  = (int)CB_DurMinsPicker.SelectedItem;
            TaskType   taskType   = (TaskType)CB_TypePicker.SelectedValue;
            RepeatType repeatType = (RepeatType)CB_RepeatPicker.SelectedValue;
            YN         required   = (YN)CB_RequiredPicker.SelectedValue;

            // Create a new task from the schedule
            SmartTask newTask = schedule.CreateTask(nextEventID++, date, hour, minute, durHour, durMinute, taskType, repeatType, TB_NewTitle.Text, TB_NewDescription.Text, required, TB_NewURL.Text);

            // Add to global schedule variable
            schedule.AddTask(newTask);

            if (selectedDate.Date == when.Date)
            {
                //Update the ListView viewer when adding a new task to the current date
                RefreshScheduleView();
            }
        }
        public void AddTask(SmartTask task, bool newToStore = true)
        {
            LinkedList <SmartTask> taskList;
            DateTime date = task.when.Date;

            task.calendar = this;

            // Add new task - inset into LinkedList
            if (taskSchedule.TryGetValue(date, out taskList))
            {
                // Schedule already exists for this day -> add event
                // Find value in list that it should be inserted after

                // Check edge case: first and last
                if (task.when < taskList.First.Value.when)
                {
                    // Insert first
                    taskList.AddFirst(task);
                }
                else if (task.when >= taskList.Last.Value.when)
                {
                    // Insert last
                    taskList.AddLast(task);
                }
                else
                {
                    // Somewhere in the middle
                    var tasks = taskList.GetEnumerator();
                    LinkedListNode <SmartTask> prev = taskList.First;
                    LinkedListNode <SmartTask> next = taskList.First;
                    //  Loop until times of prev < task < next
                    do
                    {
                        prev = next;
                        if (next == null)
                        {
                            // You've reached the end of the list!
                            break;
                        }
                        next = next.Next;
                    } while (!(prev.Value.when < task.when && task.when < next.Value.when));
                    taskList.AddAfter(prev, task);
                }
            }
            else
            {
                // This day does not yet exist in our schedule -> create it
                taskList = new LinkedList <SmartTask>();
                taskList.AddFirst(task);
                taskSchedule.Add(date, taskList);
            }
            numTasks++;


            // Store task in application data storage
            if (newToStore)
            {
                // Update the storage keys string
                string storageKey = task.StorageID();
                storageKeys.Add(storageKey);
                scheduleData.Values["storageKeys"] = storageKeysString;
                task.StoreTaskData(tasksContainer);
            }
        }