/// <summary>
        /// This function is the callback used to execute the command when the menu item is clicked.
        /// See the constructor to see how the menu item is associated with this function using
        /// OleMenuCommandService service and MenuCommand class.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event args.</param>
        private async void MenuItemCallback(object sender, EventArgs e)
        {
            try
            {
                var componentModel = (IComponentModel)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(SComponentModel));
                var workspace      = componentModel.GetService <VisualStudioWorkspace>();

                var selectedItem = this.GetSelectedSolutionExplorerItem();
                Microsoft.CodeAnalysis.Document doc = null;

                if (selectedItem != null && selectedItem.Name != null && !selectedItem.Name.EndsWith(".cs"))
                {
                    VsShellUtilities.ShowMessageBox(this.package, "Generate DTO action can only be invoked on CSharp files.", "Error",
                                                    OLEMSGICON.OLEMSGICON_WARNING,
                                                    OLEMSGBUTTON.OLEMSGBUTTON_OK,
                                                    OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);

                    return;
                }

                if (selectedItem?.Document != null)
                {
                    doc = workspace.CurrentSolution.GetDocumentByFilePath(selectedItem.Document.FullName);
                }
                else if (selectedItem != null)
                {
                    var file        = selectedItem.Name;
                    var projectName = selectedItem.ContainingProject.Name;

                    var docs = workspace.CurrentSolution.Projects
                               .Where(p => p.Name == projectName)
                               .SelectMany(p => p.Documents)
                               .Where(d => d.Name == file)
                               .ToList();

                    if (docs.Count == 0)
                    {
                        VsShellUtilities.ShowMessageBox(this.package, "Shitty exception - cannot get current selected solution item :/// . Try opening desired document, and then activating this command.", "Error",
                                                        OLEMSGICON.OLEMSGICON_WARNING,
                                                        OLEMSGBUTTON.OLEMSGBUTTON_OK,
                                                        OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                    }

                    if (docs.Count > 1)
                    {
                        VsShellUtilities.ShowMessageBox(this.package, "Multiple documents with same name exist - cannot get current selected solution item. Try opening desired document, and then activating this command.", "Error",
                                                        OLEMSGICON.OLEMSGICON_WARNING,
                                                        OLEMSGBUTTON.OLEMSGBUTTON_OK,
                                                        OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                    }

                    doc = docs.FirstOrDefault();
                }
                else
                {
                    VsShellUtilities.ShowMessageBox(this.package, "Shitty exception - cannot get current selected solution item :/// . Try opening desired document, and then activating this command.", "Error",
                                                    OLEMSGICON.OLEMSGICON_WARNING,
                                                    OLEMSGBUTTON.OLEMSGBUTTON_OK,
                                                    OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);

                    return;
                }
                var possibleProjects = doc.GetPossibleProjects();

                var vmBasic = BasicOptionsViewModel.Create(possibleProjects, doc.Name.Replace(".cs", ""), doc.Project.Solution.GetMostLikelyDtoLocation());
                var shouldProceed = new BasicOptionsWindow {
                    DataContext = vmBasic
                }.ShowModal();

                if (shouldProceed != true)
                {
                    return;
                }

                var existingDoc = doc.Project.Solution.GetDocumentByLocation(vmBasic.DtoLocation, vmBasic.DtoName);
                if (existingDoc != null)
                {
                    var result = VsShellUtilities.ShowMessageBox(this.package, "There is already a DTO class in the specified location. Press OK if you would like to regenerate it, or cancel to choose different name.", "Warninig - regenerate DTO?",
                                                                 OLEMSGICON.OLEMSGICON_WARNING,
                                                                 OLEMSGBUTTON.OLEMSGBUTTON_OKCANCEL,
                                                                 OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);

                    if (result != 1)
                    {
                        return;
                    }
                }

                var vm = await PropertySelectorViewModel.Create(doc, vmBasic.DtoName, vmBasic.DtoLocation, existingDto : existingDoc);

                var isConfirmed = new PropertySelectorWindow()
                {
                    DataContext = vm
                }.ShowModal();

                if (isConfirmed == true)
                {
                    var modifiedSolution = await doc.Project.Solution.WriteDto(vm.DtoLocation, vm.EntityModel.ConvertToMetadata(), vm.GenerateMapper, vm.AddDataContract);

                    var ok = workspace.TryApplyChanges(modifiedSolution);

                    if (!ok)
                    {
                        VsShellUtilities.ShowMessageBox(this.package, "Unable to generate DTO. Please try again (could not apply changes).", "Error", OLEMSGICON.OLEMSGICON_WARNING, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                    }
                }
            }
            catch (Exception ex)
            {
                try
                {
                    VsShellUtilities.ShowMessageBox(this.package, ex.Message, "An exception has occurred. Please c/p stack trace to project website (https://github.com/yohney/dto-generator), with brief description of the problem.",
                                                    OLEMSGICON.OLEMSGICON_WARNING,
                                                    OLEMSGBUTTON.OLEMSGBUTTON_OK,
                                                    OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);

                    var tmpFile = Path.GetTempFileName();

                    string stackTrace = "";

                    Exception tmp = ex;
                    while (tmp != null)
                    {
                        stackTrace += tmp.StackTrace;
                        stackTrace += "\n----------------------------\n\n";
                        tmp         = ex.InnerException;
                    }


                    File.WriteAllText(tmpFile, stackTrace);

                    VsShellUtilities.OpenBrowser("file:///" + tmpFile);
                }
                catch (Exception innerEx)
                {
                    VsShellUtilities.ShowMessageBox(this.package, innerEx.Message, "An exception has occurred. Unable to write stack trace to TEMP directory.",
                                                    OLEMSGICON.OLEMSGICON_WARNING,
                                                    OLEMSGBUTTON.OLEMSGBUTTON_OK,
                                                    OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                }
            }
        }