using System;
using Extensibility;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.CommandBars;
using System.Resources;
using System.Reflection;
using System.Globalization;

namespace CommandTypes
{
  /// <summary>The object for implementing an Add-in.</summary>
  /// <seealso class='IDTExtensibility2' />
  public class Connect : Object, IDTExtensibility2, IDTCommandTarget
  {
    /// <summary>Implements the constructor for the Add-in object. Place your initialization code within this method.</summary>
    public Connect()
    {
    }

    /// <summary>Implements the OnConnection method of the IDTExtensibility2 interface. Receives notification that the Add-in is being loaded.</summary>
    /// <param term='application'>Root object of the host application.</param>
    /// <param term='connectMode'>Describes how the Add-in is being loaded.</param>
    /// <param term='addInInst'>Object representing this Add-in.</param>
    /// <seealso class='IDTExtensibility2' />
    public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
    {
      _applicationObject = (DTE2)application;
      _addInInstance = (AddIn)addInInst;
      if (connectMode == ext_ConnectMode.ext_cm_UISetup)
      {
        object[] contextGUIDS = new object[] { };
        Commands2 commands = (Commands2)_applicationObject.Commands;
        string toolsMenuName;

        try
        {
          //If you would like to move the command to a different menu, change the word "Tools" to the 
          //  English version of the menu. This code will take the culture, append on the name of the menu
          //  then add the command to that menu. You can find a list of all the top-level menus in the file
          //  CommandBar.resx.
          ResourceManager resourceManager = new ResourceManager("CommandTypes.CommandBar", Assembly.GetExecutingAssembly());
          CultureInfo cultureInfo = new System.Globalization.CultureInfo(_applicationObject.LocaleID);
          string resourceName = String.Concat(cultureInfo.TwoLetterISOLanguageName, "Tools");
          toolsMenuName = resourceManager.GetString(resourceName);
        }
        catch
        {
          //We tried to find a localized version of the word Tools, but one was not found.
          //  Default to the en-US word, which may work for the current culture.
          toolsMenuName = "Tools";
        }

        //Place the command on the tools menu.
        //Find the MenuBar command bar, which is the top-level command bar holding all the main menu items:
        CommandBar menuBarCommandBar = ((CommandBars)_applicationObject.CommandBars)["MenuBar"];

        //Find the Tools command bar on the MenuBar command bar:
        CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName];
        CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl;

        //This try/catch block can be duplicated if you wish to add multiple commands to be handled by your Add-in,
        //  just make sure you also update the QueryStatus/Exec method to include the new command names.
        try
        {
          //Add a command to the Commands collection:
          Command command = commands.AddNamedCommand2(_addInInstance, "CommandTypesButton", "CommandTypes", "Executes the command for CommandTypes", false, 1, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);

          //Add a control for the command to the tools menu:
          if ((command != null) && (toolsPopup != null))
          {
            command.AddControl(toolsPopup.CommandBar, 1);
          }
        }
        catch
        {
          //If we are here, then the exception is probably because a command with that name
          //  already exists. If so there is no need to recreate the command and we can 
          //  safely ignore the exception.
        }

        //This try/catch block can be duplicated if you wish to add multiple commands to be handled by your Add-in,
        //  just make sure you also update the QueryStatus/Exec method to include the new command names.
        try
        {
          //Add a command to the Commands collection:
          Command command = commands.AddNamedCommand2(_addInInstance, "CommandTypesDropDownCombo", "CommandTypesDropDownCombo", "Executes the command for CommandTypes", false, 1, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeDropDownCombo);

          //Add a control for the command to the tools menu:
          if ((command != null) && (toolsPopup != null))
          {
            command.AddControl(toolsPopup.CommandBar, 1);
          }
        }
        catch
        {
          //If we are here, then the exception is probably because a command with that name
          //  already exists. If so there is no need to recreate the command and we can 
          //  safely ignore the exception.
        }

        //This try/catch block can be duplicated if you wish to add multiple commands to be handled by your Add-in,
        //  just make sure you also update the QueryStatus/Exec method to include the new command names.
        try
        {
          //Add a command to the Commands collection:
          Command command = commands.AddNamedCommand2(_addInInstance, "CommandTypesMRUCombo", "CommandTypesMRUCombo", "Executes the command for CommandTypes", false, 1, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeMRUCombo);

          //Add a control for the command to the tools menu:
          if ((command != null) && (toolsPopup != null))
          {
            command.AddControl(toolsPopup.CommandBar, 1);
          }
        }
        catch
        {
          //If we are here, then the exception is probably because a command with that name
          //  already exists. If so there is no need to recreate the command and we can 
          //  safely ignore the exception.
        }

        //This try/catch block can be duplicated if you wish to add multiple commands to be handled by your Add-in,
        //  just make sure you also update the QueryStatus/Exec method to include the new command names.
        try
        {
          //Add a command to the Commands collection:
          Command command = commands.AddNamedCommand2(_addInInstance, "CommandTypesMRUButton", "CommandTypesMRUButton", "Executes the command for CommandTypes", false, 1, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, (vsCommandControlType)8192 /*vsCommandControlType.vsCommandControlTypeMRUButton*/);

          //Add a control for the command to the tools menu:
          if ((command != null) && (toolsPopup != null))
          {
            command.AddControl(toolsPopup.CommandBar, 1);
          }
        }
        catch
        {
          //If we are here, then the exception is probably because a command with that name
          //  already exists. If so there is no need to recreate the command and we can 
          //  safely ignore the exception.
        }
      }
    }

    /// <summary>Implements the OnDisconnection method of the IDTExtensibility2 interface. Receives notification that the Add-in is being unloaded.</summary>
    /// <param term='disconnectMode'>Describes how the Add-in is being unloaded.</param>
    /// <param term='custom'>Array of parameters that are host application specific.</param>
    /// <seealso class='IDTExtensibility2' />
    public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
    {
    }

    /// <summary>Implements the OnAddInsUpdate method of the IDTExtensibility2 interface. Receives notification when the collection of Add-ins has changed.</summary>
    /// <param term='custom'>Array of parameters that are host application specific.</param>
    /// <seealso class='IDTExtensibility2' />		
    public void OnAddInsUpdate(ref Array custom)
    {
    }

    /// <summary>Implements the OnStartupComplete method of the IDTExtensibility2 interface. Receives notification that the host application has completed loading.</summary>
    /// <param term='custom'>Array of parameters that are host application specific.</param>
    /// <seealso class='IDTExtensibility2' />
    public void OnStartupComplete(ref Array custom)
    {
    }

    /// <summary>Implements the OnBeginShutdown method of the IDTExtensibility2 interface. Receives notification that the host application is being unloaded.</summary>
    /// <param term='custom'>Array of parameters that are host application specific.</param>
    /// <seealso class='IDTExtensibility2' />
    public void OnBeginShutdown(ref Array custom)
    {
    }

    string[] MRUButtonItemNames = new string[] { "Button Item 1", "Button Item 2", "Button Item 3", "Button Item 4" };
    string mruButtonRootCommandName = "CommandTypes.Connect.CommandTypesMRUButton";

    /// <summary>Implements the QueryStatus method of the IDTCommandTarget interface. This is called when the command's availability is updated</summary>
    /// <param term='commandName'>The name of the command to determine state for.</param>
    /// <param term='neededText'>Text that is needed for the command.</param>
    /// <param term='status'>The state of the command in the user interface.</param>
    /// <param term='commandText'>Text requested by the neededText parameter.</param>
    /// <seealso class='Exec' />
    public void QueryStatus(string commandName, vsCommandStatusTextWanted neededText, ref vsCommandStatus status, ref object commandText)
    {
      if (neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
      {
        int index = 0;
        if (commandName == "CommandTypes.Connect.CommandTypesButton")
        {
          //Return standard command UI status, no extra work to do for a button
          status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
          return;
        }
        else if (commandName == "CommandTypes.Connect.CommandTypesDropDownCombo")
        {
          //Return standard command UI status, no extra work to do for a drop down combo
          status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
          return;
        }
        else if (commandName == "CommandTypes.Connect.CommandTypesMRUCombo")
        {
          //Return standard command UI status, no extra work to do for a mru combo
          status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
          return;
        }
        else if (commandName == mruButtonRootCommandName)
        {
          //Return standard command UI status for the first item on a MRU button
          status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
          index = 0;
          return;
        }
        else if (commandName.StartsWith(mruButtonRootCommandName))
        {
          //Return standard command UI status, first we need to find the MRU button item, then return the status
          index = int.Parse(commandName.Substring(mruButtonRootCommandName.Length + 1));
          if (index > 3)
          {
            //We do not support this MRU item
            status = vsCommandStatus.vsCommandStatusUnsupported;
            return;
          }
          else
          {
            //Return status for the button
            status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
            commandText = MRUButtonItemNames[index];
            return;
          }
        }
      }
      else if (neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedName)
      {
        if (commandName == mruButtonRootCommandName)
        {
          //Return the text for the first MRU button
          commandText = MRUButtonItemNames[0];
          status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
          return;
        }
        else if (commandName.StartsWith(mruButtonRootCommandName))
        {
          //Return the text for the indexed MRU button
          int index = int.Parse(commandName.Substring(mruButtonRootCommandName.Length + 1));
          if (index > 3)
          {
            status = vsCommandStatus.vsCommandStatusUnsupported;
            return;
          }
          else
          {
            status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
            commandText = MRUButtonItemNames[index];
            return;
          }
        }
      }
    }

    /// <summary>Implements the Exec method of the IDTCommandTarget interface. This is called when the command is invoked.</summary>
    /// <param term='commandName'>The name of the command to execute.</param>
    /// <param term='executeOption'>Describes how the command should be run.</param>
    /// <param term='varIn'>Parameters passed from the caller to the command handler.</param>
    /// <param term='varOut'>Parameters passed from the command handler to the caller.</param>
    /// <param term='handled'>Informs the caller if the command was handled or not.</param>
    /// <seealso class='Exec' />
    public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
    {
      handled = false;
      if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
      {
        if (commandName == "CommandTypes.Connect.CommandTypesButton")
        {
          //The button was clicked
          System.Windows.Forms.MessageBox.Show("CommandTypesButton");
          handled = true;
          return;
        }
        else if (commandName == "CommandTypes.Connect.CommandTypesDropDownCombo")
        {
          //The command bar drop down combo is being executed, see if we should execute or return data to the caller
          if ((varIn != null) && (varIn is string))
          {
            //Command was being executed
            string selectedText = varIn as string;
            System.Windows.Forms.MessageBox.Show("DropDownCombo: " + selectedText);
          }
          else
          {
            //Command data was asked for
            varOut = "Item1";
          }
          handled = true;
          return;
        }
        else if (commandName == "CommandTypes.Connect.CommandTypesDropDownCombo_1")
        {
          //The list of items to fill the combo box with is being asked for
          varOut = new string[] { "Item 1", "Item 2", "Item 3", "Item 4" };
          handled = true;
          return;
        }
        else if (commandName == "CommandTypes.Connect.CommandTypesMRUCombo")
        {
          //The MRU combo box command was executed
          string selectedText = varIn as string;
          System.Windows.Forms.MessageBox.Show("MRUCombo: " + selectedText);
          handled = true;
          return;
        }
        else if (commandName.StartsWith(mruButtonRootCommandName))
        {
          //A MRU button was run, get the text of the run item.
          string selectedItem = "";
          if (commandName == mruButtonRootCommandName)
          {
            selectedItem = MRUButtonItemNames[0];
          }
          else if (commandName.StartsWith(mruButtonRootCommandName))
          {
            int index = int.Parse(commandName.Substring(mruButtonRootCommandName.Length + 1));
            selectedItem = MRUButtonItemNames[index];
          }
          System.Windows.Forms.MessageBox.Show(selectedItem);
          handled = true;
          return;
        }
      }
    }
    private DTE2 _applicationObject;
    private AddIn _addInInstance;
  }
}