private void AddOrUpdateMapping(CrmSolution solution)
        {
            try
            {
                var path = Path.GetDirectoryName(ConnPane.SelectedProject.FullName);
                if (!SharedConfigFile.ConfigFileExists(ConnPane.SelectedProject))
                {
                    _logger.WriteToOutputWindow("Error Updating Mappings In Config File: Missing CRMDeveloperExtensions.config File", Logger.MessageType.Error);
                    return;
                }

                XmlDocument doc = new XmlDocument();
                doc.Load(path + "\\CRMDeveloperExtensions.config");

                //Update or delete existing mapping
                XmlNodeList solutionNodes = doc.GetElementsByTagName("Solution");
                if (solutionNodes.Count > 0)
                {
                    foreach (XmlNode node in solutionNodes)
                    {
                        bool changed = false;
                        XmlNode orgId = node["OrgId"];
                        if (orgId != null && orgId.InnerText.ToUpper() != ConnPane.SelectedConnection.OrgId.ToUpper()) continue;

                        XmlNode projectNameNode = node["ProjectName"];
                        if (projectNameNode != null && projectNameNode.InnerText.ToUpper() != solution.BoundProject.ToUpper())
                            continue;

                        if (string.IsNullOrEmpty(solution.BoundProject) || solution.SolutionId == Guid.Empty)
                        {
                            //Delete
                            var parentNode = node.ParentNode;
                            if (parentNode != null)
                            {
                                parentNode.RemoveChild(node);
                                changed = true;
                            }
                        }
                        else
                        {
                            //Update
                            XmlNode solutionIdNode = node["SolutionId"];
                            if (solutionIdNode != null)
                            {
                                string oldSolutionId = solutionIdNode.InnerText;
                                if (oldSolutionId != solution.SolutionId.ToString())
                                {
                                    solutionIdNode.InnerText = solution.SolutionId.ToString();
                                    changed = true;
                                }
                            }
                            XmlNode downloadManagedNode = node["DownloadManaged"];
                            if (downloadManagedNode != null)
                            {
                                string oldDownloadManaged = downloadManagedNode.InnerText;
                                string downloadManagedValue = (solution.DownloadManagedSolution) ? "true" : "false";
                                if (oldDownloadManaged != downloadManagedValue)
                                {
                                    downloadManagedNode.InnerText = downloadManagedValue;
                                    changed = true;
                                }
                            }
                        }

                        if (!changed) return;

                        if (SharedConfigFile.IsConfigReadOnly(path + "\\CRMDeveloperExtensions.config"))
                        {
                            FileInfo file = new FileInfo(path + "\\CRMDeveloperExtensions.config") { IsReadOnly = false };
                        }

                        doc.Save(path + "\\CRMDeveloperExtensions.config");
                        return;
                    }
                }

                //Create new mapping
                XmlNodeList projects = doc.GetElementsByTagName("Solutions");
                if (projects.Count <= 0)
                    return;

                XmlNode solutionNode = doc.CreateElement("Solution");
                XmlNode org = doc.CreateElement("OrgId");
                org.InnerText = ConnPane.SelectedConnection.OrgId;
                solutionNode.AppendChild(org);
                XmlNode projectNameNode2 = doc.CreateElement("ProjectName");
                projectNameNode2.InnerText = solution.BoundProject;
                solutionNode.AppendChild(projectNameNode2);
                XmlNode solutionId = doc.CreateElement("SolutionId");
                solutionId.InnerText = solution.SolutionId.ToString();
                solutionNode.AppendChild(solutionId);
                XmlNode downloadManaged = doc.CreateElement("DownloadManaged");
                downloadManaged.InnerText = (DownloadManaged.IsChecked == true) ? "true" : "false";
                solutionNode.AppendChild(downloadManaged);
                projects[0].AppendChild(solutionNode);

                if (SharedConfigFile.IsConfigReadOnly(path + "\\CRMDeveloperExtensions.config"))
                {
                    FileInfo file = new FileInfo(path + "\\CRMDeveloperExtensions.config") { IsReadOnly = false };
                }

                doc.Save(path + "\\CRMDeveloperExtensions.config");
            }
            catch (Exception ex)
            {
                _logger.WriteToOutputWindow("Error Updating Mappings In Config File: " + ex.Message + Environment.NewLine + ex.StackTrace, Logger.MessageType.Error);
            }
        }
        private string GetSolutionFromCrm(string connString, CrmSolution selectedSolution, bool managed)
        {
            try
            {
                CrmConnection connection = CrmConnection.Parse(connString);
                // Hardcode connection timeout to one-hour to support large solutions.
                connection.Timeout = new TimeSpan(1, 0, 0);

                using (_orgService = new OrganizationService(connection))
                {
                    ExportSolutionRequest request = new ExportSolutionRequest
                    {
                        Managed = managed,
                        SolutionName = selectedSolution.UniqueName
                    };

                    ExportSolutionResponse response = (ExportSolutionResponse)_orgService.Execute(request);

                    var tempFolder = Path.GetTempPath();
                    string fileName = Path.GetFileName(selectedSolution.UniqueName + "_" +
                        FormatVersionString(selectedSolution.Version) + ((managed) ? "_managed" : String.Empty) + ".zip");
                    var tempFile = Path.Combine(tempFolder, fileName);
                    if (File.Exists(tempFile))
                        File.Delete(tempFile);
                    File.WriteAllBytes(tempFile, response.ExportSolutionFile);

                    return tempFile;
                }
            }
            catch (FaultException<OrganizationServiceFault> crmEx)
            {
                _logger.WriteToOutputWindow("Error Retrieving Solution From CRM: " + crmEx.Message + Environment.NewLine + crmEx.StackTrace, Logger.MessageType.Error);
                return null;
            }
            catch (Exception ex)
            {
                _logger.WriteToOutputWindow("Error Retrieving Solution From CRM: " + ex.Message + Environment.NewLine + ex.StackTrace, Logger.MessageType.Error);
                return null;
            }
        }
        private void CreatePackage(CrmSolution selectedSolution, Version version, string savePath, Project project)
        {
            try
            {
                //https://msdn.microsoft.com/en-us/library/jj602987.aspx#arguments

                CommandWindow cw = _dte2.ToolWindows.CommandWindow;

                var props = _dte.Properties["CRM Developer Extensions", "Solution Packager"];
                string spPath = (string)props.Item("SolutionPackagerPath").Value;

                if (string.IsNullOrEmpty(spPath))
                {
                    MessageBox.Show("Set SDK bin folder path under Tools -> Options -> CRM Developer Extensions");
                    return;
                }

                if (!spPath.EndsWith("\\"))
                    spPath += "\\";

                string toolPath = @"""" + spPath + "SolutionPackager.exe" + @"""";

                if (!File.Exists(spPath + "SolutionPackager.exe"))
                {
                    MessageBox.Show("SolutionPackager.exe not found at: " + spPath);
                    return;
                }

                string filename = selectedSolution.UniqueName + "_" +
                                  FormatVersionString(version) + ".zip";

                string command = toolPath + " /action: Pack";
                command += " /zipfile:" + "\"" + savePath + "\\" + filename + "\"";
                command += " /folder: " + "\"" + Path.GetDirectoryName(ConnPane.SelectedProject.FullName) + "\"";
                
                // Use a mapping file if one exists in the root folder of the project and be named mapping.xml
                if (File.Exists(Path.GetDirectoryName(ConnPane.SelectedProject.FullName) + "\\mapping.xml"))
                {
                    command += " /map:" + "\"" + Path.GetDirectoryName(ConnPane.SelectedProject.FullName) + "\\mapping.xml\"";
                }

                cw.SendInput("shell " + command, true);

                AddNewSolutionToProject(savePath, project, filename);
            }
            catch (Exception ex)
            {
                _logger.WriteToOutputWindow("Error launching Solution Packager: " + Environment.NewLine + Environment.NewLine + ex.Message, Logger.MessageType.Error);
            }
        }
        private async Task<bool> ExtractPackage(string path, CrmSolution selectedSolution, Project project, bool? downloadManaged)
        {
            //https://msdn.microsoft.com/en-us/library/jj602987.aspx#arguments
            try
            {
                CommandWindow cw = _dte2.ToolWindows.CommandWindow;

                var props = _dte.Properties["CRM Developer Extensions", "Solution Packager"];
                string spPath = (string)props.Item("SolutionPackagerPath").Value;

                if (string.IsNullOrEmpty(spPath))
                {
                    MessageBox.Show("Set SDK bin folder path under Tools -> Options -> CRM Developer Extensions");
                    return false;
                }

                if (!spPath.EndsWith("\\"))
                    spPath += "\\";

                string toolPath = @"""" + spPath + "SolutionPackager.exe" + @"""";

                if (!File.Exists(spPath + "SolutionPackager.exe"))
                {
                    MessageBox.Show("SolutionPackager.exe not found at: " + spPath);
                    return false;
                }

                string tempDirectory = Path.GetDirectoryName(path);
                if (Directory.Exists(tempDirectory + "\\" + Path.GetFileNameWithoutExtension(path)))
                    Directory.Delete(tempDirectory + "\\" + Path.GetFileNameWithoutExtension(path), true);
                DirectoryInfo extractedFolder =
                    Directory.CreateDirectory(tempDirectory + "\\" + Path.GetFileNameWithoutExtension(path));

                string command = toolPath + " /action: Extract";
                command += " /zipfile:" + "\"" + path + "\"";
                command += " /folder: " + "\"" + extractedFolder.FullName + "\"";
                command += " /clobber";

                // Add a mapping file which should be in the root folder of the project and be named mapping.xml
                if (File.Exists(Path.GetDirectoryName(ConnPane.SelectedProject.FullName) + "\\mapping.xml"))
                {
                    command += " /map:" + "\"" + Path.GetDirectoryName(ConnPane.SelectedProject.FullName) + "\\mapping.xml\"";
                }

                // Write Solution Package output to a log file named SolutionPackager.log in the root folder of the project
                command += " /log:" + "\"" + Path.GetDirectoryName(ConnPane.SelectedProject.FullName) + "\\SolutionPackager.log\"";

                // Unpack managed solution as well.
                if (downloadManaged == true)
                {
                    command += " /packagetype:Both";
                }

                cw.SendInput("shell " + command, true);

                //Need this. Extend to allow bigger solutions to unpack
                System.Threading.Thread.Sleep(10000);

                bool solutionFileDelete = RemoveDeletedItems(extractedFolder.FullName, ConnPane.SelectedProject.ProjectItems);
                bool solutionFileAddChange = ProcessDownloadedSolution(extractedFolder, Path.GetDirectoryName(ConnPane.SelectedProject.FullName),
                    ConnPane.SelectedProject.ProjectItems);

                Directory.Delete(extractedFolder.FullName, true);

                //Solution change or file not present
                bool solutionChange = solutionFileDelete || solutionFileAddChange;           
                StoreSolutionFile(path, project, solutionChange);
                
                return solutionChange;
            }
            catch (Exception ex)
            {
                _logger.WriteToOutputWindow("Error launching Solution Packager: " + Environment.NewLine + Environment.NewLine + ex.Message, Logger.MessageType.Error);
                return false;
            }
        }
        private async Task<bool> GetSolutions(string connString)
        {
            _dte.StatusBar.Text = "Connecting to CRM and getting solutions...";
            _dte.StatusBar.Animate(true, vsStatusAnimation.vsStatusAnimationSync);
            LockMessage.Content = "Working...";
            LockOverlay.Visibility = Visibility.Visible;

            EntityCollection results = await Task.Run(() => GetSolutionsFromCrm(connString));
            if (results == null)
            {
                _dte.StatusBar.Clear();
                _dte.StatusBar.Animate(false, vsStatusAnimation.vsStatusAnimationSync);
                LockOverlay.Visibility = Visibility.Hidden;
                MessageBox.Show("Error Retrieving Solutions. See the Output Window for additional details.");
                return false;
            }

            _logger.WriteToOutputWindow("Retrieved Solutions From CRM", Logger.MessageType.Info);

            ObservableCollection<CrmSolution> solutions = new ObservableCollection<CrmSolution>();

            CrmSolution emptyItem = new CrmSolution
            {
                SolutionId = Guid.Empty,
                Name = String.Empty
            };
            solutions.Add(emptyItem);

            foreach (Entity entity in results.Entities)
            {
                CrmSolution solution = new CrmSolution
                {
                    SolutionId = entity.Id,
                    Name = entity.GetAttributeValue<string>("friendlyname"),
                    Prefix = entity.GetAttributeValue<AliasedValue>("publisher.customizationprefix").Value.ToString(),
                    UniqueName = entity.GetAttributeValue<string>("uniquename"),
                    Version = Version.Parse(entity.GetAttributeValue<string>("version"))
                };

                solutions.Add(solution);
            }

            //Empty on top
            var i =
                solutions.IndexOf(
                    solutions.FirstOrDefault(s => s.SolutionId == new Guid("00000000-0000-0000-0000-000000000000")));

            var item = solutions[i];
            solutions.RemoveAt(i);
            solutions.Insert(0, item);

            //Default second
            i =
                solutions.IndexOf(
                    solutions.FirstOrDefault(s => s.SolutionId == new Guid("FD140AAF-4DF4-11DD-BD17-0019B9312238")));
            item = solutions[i];
            solutions.RemoveAt(i);
            solutions.Insert(1, item);

            solutions = HandleMappings(solutions);
            SolutionToPackage.ItemsSource = solutions;
            if (solutions.Count(s => !string.IsNullOrEmpty(s.BoundProject)) > 0)
            {
                SolutionToPackage.SelectedItem = solutions.First(s => !string.IsNullOrEmpty(s.BoundProject));
                var selectedProject = ConnPane.SelectedProject;
                if (selectedProject != null)
                    SolutionToPackage.IsEnabled = !File.Exists(Path.GetDirectoryName(selectedProject.FullName) + "\\Other\\Solution.xml");
            }
            else
                SolutionToPackage.IsEnabled = true;

            CrmSolution crmSolution = solutions.FirstOrDefault(s => !string.IsNullOrEmpty(s.BoundProject));
            DownloadManaged.IsChecked = crmSolution != null && solutions.First(s => !string.IsNullOrEmpty(s.BoundProject)).DownloadManagedSolution;

            _dte.StatusBar.Clear();
            _dte.StatusBar.Animate(false, vsStatusAnimation.vsStatusAnimationSync);
            LockOverlay.Visibility = Visibility.Hidden;

            return true;
        }
        private async Task<bool> ExtractPackage(string path, CrmSolution selectedSolution, Project project, bool? downloadManaged)
        {
            //https://msdn.microsoft.com/en-us/library/jj602987.aspx#arguments
            try
            {
                CommandWindow cw = _dte2.ToolWindows.CommandWindow;

                var props = _dte.Properties["CRM Developer Extensions", "Solution Packager"];
                string spPath = (string)props.Item("SolutionPackagerPath").Value;

                if (string.IsNullOrEmpty(spPath))
                {
                    MessageBox.Show("Set SDK bin folder path under Tools -> Options -> CRM Developer Extensions");
                    return false;
                }

                if (!spPath.EndsWith("\\"))
                    spPath += "\\";

                string toolPath = @"""" + spPath + "SolutionPackager.exe" + @"""";

                if (!File.Exists(spPath + "SolutionPackager.exe"))
                {
                    MessageBox.Show("SolutionPackager.exe not found at: " + spPath);
                    return false;
                }

                string tempDirectory = Path.GetDirectoryName(path);
                if (Directory.Exists(tempDirectory + "\\" + Path.GetFileNameWithoutExtension(path)))
                    Directory.Delete(tempDirectory + "\\" + Path.GetFileNameWithoutExtension(path), true);
                DirectoryInfo extractedFolder =
                    Directory.CreateDirectory(tempDirectory + "\\" + Path.GetFileNameWithoutExtension(path));

                string command = toolPath + " /action: Extract";
                command += " /zipfile:" + "\"" + path + "\"";
                command += " /folder: " + "\"" + extractedFolder.FullName + "\"";
                command += " /clobber";

                cw.SendInput("shell " + command, true);

                //Need this
                System.Threading.Thread.Sleep(1000);

                bool solutionFileDelete = RemoveDeletedItems(extractedFolder.FullName, ConnPane.SelectedProject.ProjectItems);
                bool solutionFileAddChange = ProcessDownloadedSolution(extractedFolder, Path.GetDirectoryName(ConnPane.SelectedProject.FullName),
                    ConnPane.SelectedProject.ProjectItems);

                Directory.Delete(extractedFolder.FullName, true);

                //Solution change or file not present
                bool solutionChange = solutionFileDelete || solutionFileAddChange;
                StoreSolutionFile(path, project, solutionChange);

                //Download Managed
                if (downloadManaged != true)
                    return false;

                path = await Task.Run(() => GetSolutionFromCrm(ConnPane.SelectedConnection.ConnectionString, selectedSolution, true));

                if (string.IsNullOrEmpty(path))
                {
                    _dte.StatusBar.Clear();
                    LockOverlay.Visibility = Visibility.Hidden;
                    MessageBox.Show("Error Retrieving Solution. See the Output Window for additional details.");
                    return false;
                }

                return solutionChange;
            }
            catch (Exception ex)
            {
                _logger.WriteToOutputWindow("Error launching Solution Packager: " + Environment.NewLine + Environment.NewLine + ex.Message, Logger.MessageType.Error);
                return false;
            }
        }