/// <summary>
 /// A method to compare if two MenuItems are the same.
 /// </summary>
 /// <param name="otherItem">The other MenuItem to compare with.</param>
 /// <returns>Bool indicating if they are the same.</returns>
 public bool Equals(MenuItem otherItem)
 {
     if (this.Title == otherItem.Title && this.FilePath == otherItem.FilePath)
     {
         return true;
     }
     else
     {
         return false;
     }
 }
        /// <summary>
        /// Update the currentLocation object in order to setup the
        /// time slider for the images of the selected location.
        /// </summary>
        /// <param name="newLocation">New location value for currentLocation.</param>
        /// <param name="childToSelect">Child image for the location that should be visible.</param>
        private void UpdateCurrentLocation(MenuItem newLocation, MenuItem childToSelect)
        {
            this.currentLocation = newLocation;
            this.TimeSliderMax = this.currentLocation.Items.Count;

            // Set the TimeSlider to show the newly added child on the map
            bool foundChild = false;
            for (int i = 0; i < newLocation.Items.Count; i++)
            {
                if (newLocation.Items[i].Title == childToSelect.Title)
                {
                    this.TimeSliderValue = i + 1;
                    foundChild = true;
                    break;
                }
            }

            // Default value just in case.
            if (!foundChild)
            {
                this.TimeSliderValue = 1;
            }
        }
        /// <summary>
        /// This method converts all of the information from the remove layers
        /// window and returns it as a list of menuitems. This is how the
        /// remove layers window returns the results of the users actions.
        /// </summary>
        /// <returns>List of MenuItems including the user's checkbox selections.</returns>
        public List<MenuItem> GetMenuItems()
        {
            List<MenuItem> locationsToKeep = new List<MenuItem>();

            // Don't include the root, which is the "All" selection.
            List<RemoveLayersViewModel> locations = this.root.Children;

            foreach (RemoveLayersViewModel location in locations)
            {
                // Add the location to the list.
                MenuItem loc;
                if (location.IsChecked == true)
                {
                   loc = new MenuItem(location.Name, location.FilePath, location.TreeCanopyFilePath, true);
                }
                else
                {
                    loc = new MenuItem(location.Name, location.FilePath, location.TreeCanopyFilePath, false);
                }

                // Add each of the times for that location to that children of that location.
                foreach (RemoveLayersViewModel time in location.Children)
                {
                    MenuItem t;
                    if (time.IsChecked == true)
                    {
                        t = new MenuItem(time.Name, time.FilePath, time.TreeCanopyFilePath, true);
                    }
                    else
                    {
                        t = new MenuItem(time.Name, time.FilePath, time.TreeCanopyFilePath, false);
                    }

                    loc.Items.Add(t);
                }

                locationsToKeep.Add(loc);
            }

            return locationsToKeep;
        }
        /// <summary>
        /// Update the currentLocation object in order to setup the
        /// time slider for the images of the selected location.
        /// </summary>
        /// <param name="newLocation">New location value for currentLocation.</param>
        private void UpdateCurrentLocation(MenuItem newLocation)
        {
            if (newLocation == null)
            {
                return;
            }

            this.currentLocation = newLocation;
            this.TimeSliderMax = this.currentLocation.Items.Count;
            this.TimeSliderValue = 1;
        }
        /// <summary>
        /// "Remove Layers" button callback. 
        /// This pops up a window which allows the user to select which layers they wish to remove.
        /// The TreeView of layers is updated accordingly. 
        /// </summary>
        /// <param name="parameter">Layer to be removed</param>
        private void RemoveLayer(object parameter)
        {
            RemoveLayers win = new RemoveLayers(RemoveLayersViewModel.CreateViewModels(this.TreeViewItems));
            win.ShowDialog();

            List<MenuItem> itemsList = win.GetMenuItems();

            // For each parent
            for (int i = itemsList.Count - 1; i >= 0; i--)
            {
                // Remove all selected children
                for (int j = itemsList[i].Items.Count - 1; j >= 0; j--)
                {
                    if (itemsList[i].Items[j].Checked)
                    {
                        this.UnloadKML(itemsList[i].Items[j].FilePath);
                        this.UnloadKML(itemsList[i].Items[j].TreeCanopyFilePath);
                        itemsList[i].Items.Remove(itemsList[i].Items[j]);
                    }
                }

                // Remove the parent if necessary
                if (itemsList[i].Checked || itemsList[i].Items.Count == 0)
                {
                    // KML layers are loaded and unloaded at the child level
                    // so we do not need an UnloadKML here.
                    itemsList.Remove(itemsList[i]);
                }
            }

            this.TreeViewItems = new ObservableCollection<MenuItem>(itemsList);

            win.Close();

            // Update the current location.
            // First, check to see if the current location still exists.
            bool locationStillExists = false;
            foreach (MenuItem location in this.treeViewItems)
            {
                if (this.currentLocation.Title == location.Title)
                {
                    // The location still exists, so update it
                    // in case any DateTimes were removed from it.
                    this.UpdateCurrentLocation(location);
                    locationStillExists = true;
                    break;
                }
            }

            // Or, if the location does not exist, then default to the first one.
            if (!locationStillExists)
            {
                this.currentLocation = this.treeViewItems.FirstOrDefault();
            }

            List<Dataset> layers = new List<Dataset>();
            string json;
            this.CollectAllTreeItems(this.treeViewItems, layers);
            json = JsonConvert.SerializeObject(layers.ToArray());
            if (layers.Count == 0)
            {
                json = string.Empty;
            }

            System.IO.File.WriteAllText("../../Layers.json", json);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="MainViewModel" /> class.
        /// This is the constructor for the MainViewModel.
        /// When the view model initializes, it reads the map from the App.xaml resources.
        /// </summary>
        /// <param name="window">The window the mainviewmodel belongs to.</param>
        public MainViewModel(MainWindow window)
        {
            this.mainWindow = window;

            this.viewTreeAnalytics = false;
            this.Map = App.Current.Resources["IncidentMap"] as Map;
            this.TreeViewItems = new ObservableCollection<MenuItem>();

            // Read JSON file to get all existing layers
            List<Dataset> layers;
            string json;
            using (StreamReader r = new StreamReader("../../Layers.json"))
            {
                json = r.ReadToEnd();
                layers = JsonConvert.DeserializeObject<List<Dataset>>(json);
            }

            // Backup to manually set up layers in case Layers.json is empty
            if (layers != null)
            {
                // Create MenuItems for all locations
                List<MenuItem> locations = new List<MenuItem>();
                foreach (Dataset ds in layers)
                {
                    MenuItem currentLocationRootNode = null;
                    foreach (MenuItem item in locations)
                    {
                        if (item.Title == ds.Location)
                        {
                            currentLocationRootNode = item;
                        }
                    }

                    // If location has not been added already
                    if (currentLocationRootNode == null)
                    {
                        // Construct new root level node
                        MenuItem node = new MenuItem()
                        {
                            Title = ds.Location,
                            FilePath = ds.FilePath,
                            TreeCanopyFilePath = ds.TreeCanopyFilePath
                        };

                        // Add first subnode to new root level node
                        node.Items.Add(new MenuItem()
                        {
                            Title = ds.Time.ToString(),
                            FilePath = ds.FilePath,
                            TreeCanopyFilePath = ds.TreeCanopyFilePath
                        });
                        locations.Add(node);
                    }
                    else
                    {
                        // If location has been added already
                        // Add another subnode to exisiting root level node
                        currentLocationRootNode.Items.Add(new MenuItem()
                        {
                            Title = ds.Time.ToString(),
                            FilePath = ds.FilePath,
                            TreeCanopyFilePath = ds.TreeCanopyFilePath
                        });
                    }
                }

                // Add root level nodes to tree
                foreach (MenuItem item in locations)
                {
                    this.TreeViewItems.Add(item);
                }

                this.UpdateCurrentLocation(locations.First());
                foreach (MenuItem item in locations.First().Items)
                {
                    this.LoadKml(item.FilePath, true, true);
                }
            }

            this.datasetList = new List<Dataset>();
            this.AddLayerCommand = new DelegateCommand(this.AddLayer);
            this.RemoveLayerCommand = new DelegateCommand(this.RemoveLayer);
        }
        /// <summary>
        /// This method is called when the user clicks on an item in
        /// the layers treeview in the popout right side menu. It
        /// updates the currently selected image on the map as the
        /// one that the user clicked on.
        /// </summary>
        /// <param name="newlySelectedItem">The new images selected by 
        /// the user to show on the map.</param>
        /// <param name="updateLocation">Flag to determine if we should set this location as the current
        /// location active on the time bar.</param>
        public void UpdateSelectedItem(MenuItem newlySelectedItem, bool updateLocation = true)
        {
            List<MenuItem> treeViewItemList = this.TreeViewItems.ToList();

            // Iterate through each location.
            foreach (MenuItem location in treeViewItemList)
            {
                bool activeLocation = false;

                // First, check to see if the user clicked a location
                if (location.Equals(newlySelectedItem))
                {
                    // Failed attempt at panning on click
                    //Layer selectedLayer = this.Map.Layers[location.Items.First().FilePath];
                    //this.MapView.SetView(selectedLayer.FullExtent.GetCenter());

                    // Very Ghetto way to pan to the selected image.
                    if (this.ViewTreeAnalytics)
                    {
                        this.UnloadKML(location.Items.First().TreeCanopyFilePath);
                        this.LoadKml(location.Items.First().TreeCanopyFilePath, true, true);
                    }
                    else
                    {
                        this.UnloadKML(location.Items.First().FilePath);
                        this.LoadKml(location.Items.First().FilePath, true, true);
                    }

                    // If so, then select its first child
                    if (updateLocation)
                    {
                        this.UpdateCurrentLocation(location);
                    }

                    location.Items.First().Checked = true;
                    location.Checked = true;
                    activeLocation = true;
                    this.NotifiyPropertyChanged("TreeViewItems");
                }
                else
                {
                    // Else, iterate through this location's children to see if
                    // one of them was selected.
                    foreach (MenuItem time in location.Items)
                    {
                        // If this child was the selected item,
                        // then set it as the active image.
                        if (time.Equals(newlySelectedItem))
                        {
                            if (updateLocation)
                            {
                                this.UpdateCurrentLocation(location, time);
                            }

                            // Very Ghetto way to pan to the selected image.
                            if (this.ViewTreeAnalytics)
                            {
                                this.UnloadKML(time.TreeCanopyFilePath);
                                this.LoadKml(time.TreeCanopyFilePath, true, true);
                            }
                            else
                            {
                                this.UnloadKML(time.FilePath);
                                this.LoadKml(time.FilePath, true, true);
                            }

                            time.Checked = true;
                            location.Checked = true;
                            activeLocation = true;
                            this.NotifiyPropertyChanged("TreeViewItems");
                        }
                        else
                        {
                            time.Checked = false;
                        }
                    }
                }

                // If this location, nor any of its children
                // were selected, then make sure it is not highlighted.
                if (!activeLocation)
                {
                    location.Checked = false;
                }
            }
        }
        /// <summary>
        /// "Add Layer" button callback
        /// Pops up a window that gets the user to input the necessary information
        /// for adding a new layer and then adds the layer.
        /// </summary>
        /// <param name="parameter">The window being passed.</param>
        public void AddLayer(object parameter)
        {
            // Generate list of location names
            ObservableCollection<string> locations = new ObservableCollection<string>();
            foreach (MenuItem item in this.treeViewItems)
            {
                locations.Add(item.Title);
            }

            // Popup a window to get the layer information
            AddLayer addLayer = new AddLayer(locations);
            addLayer.Owner = (Window)parameter; // In the XAML we pass the window as the parameter
            addLayer.ShowDialog();

            // Get the data from the AddLayer window
            Dataset newLayer = addLayer.DatasetToAdd;
            addLayer.Close();

            // Read JSON file with existing layers
            List<Dataset> layers;
            string json;
            using (StreamReader r = new StreamReader("../../Layers.json"))
            {
                json = r.ReadToEnd();
                layers = JsonConvert.DeserializeObject<List<Dataset>>(json);
            }

            // Save new layer to flat JSON file
            if (layers == null)
            {
                layers = new List<Dataset>();
            }

            layers.Add(newLayer);
            json = JsonConvert.SerializeObject(layers.ToArray());
            System.IO.File.WriteAllText("../../Layers.json", json);

            if (!string.IsNullOrEmpty(newLayer.FilePath))
            {
                // TODO - somewhere around here execute the code to do the tree analysis on the new image
                // Presently, this will not require a change in the treeview, so the new image can go straight
                // to LoadKML()
                TreeLineDetection temp = new TreeLineDetection();
                Task.Run(() => temp.ConvertFolder((new FileInfo(newLayer.FilePath)).DirectoryName, this.mainWindow));

                // Save the new dataset
                this.datasetList.Add(newLayer);

                // See if the Location already exists
                bool locationExists = false;

                foreach (MenuItem location in this.TreeViewItems)
                {
                    // If so, then add the new layer as a child of that Location
                    if (location.Title == newLayer.Location)
                    {
                        MenuItem newChild = new MenuItem(newLayer.Time.ToString(), newLayer.FilePath, location.TreeCanopyFilePath);
                        location.Items.Add(newChild);

                        // Sort the children based on time
                        location.Items = new ObservableCollection<MenuItem>(location.Items.OrderBy(time => time.Title).ToList());

                        this.UpdateCurrentLocation(location, newChild);
                        locationExists = true;
                        break;
                    }
                }

                // If not, then we also need to add the Location to the treeview
                if (!locationExists)
                {
                    // Add it to the TreeView on the UI
                    MenuItem root = new MenuItem(newLayer.Location, newLayer.FilePath, newLayer.TreeCanopyFilePath);
                    root.Items.Add(new MenuItem(newLayer.Time.ToString(), newLayer.FilePath, newLayer.TreeCanopyFilePath));
                    this.TreeViewItems.Add(root);
                    this.UpdateCurrentLocation(root);
                }

                // Open the new layer
                this.LoadKml(newLayer.FilePath, newLayer.ZoomTo, false);
            }

            Debug.WriteLine("Location: " + newLayer.Location);
            Debug.WriteLine("Time: " + newLayer.Time);
            Debug.WriteLine("File Path: " + newLayer.FilePath);
        }