// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_EXTENSIONS_API_COMMANDS_COMMAND_SERVICE_H_
#define CHROME_BROWSER_EXTENSIONS_API_COMMANDS_COMMAND_SERVICE_H_
#pragma once

#include <string>

#include "base/basictypes.h"
#include "chrome/browser/profiles/profile_keyed_service.h"
#include "chrome/common/extensions/command.h"
#include "chrome/common/extensions/extension.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_source.h"

class PrefService;
class Profile;

namespace base {
  class DictionaryValue;
}

namespace ui {
  class Accelerator;
}

namespace extensions {

// This service keeps track of preferences related to extension commands
// (assigning initial keybindings on install and removing them on deletion
// and answers questions related to which commands are active.
class CommandService : public ProfileKeyedService,
                       public content::NotificationObserver {
 public:
  // An enum specifying whether to fetch all extension commands or only active
  // ones.
  enum QueryType {
    ALL,
    ACTIVE_ONLY,
  };

  // Register prefs for keybinding.
  static void RegisterUserPrefs(PrefService* user_prefs);

  // Constructs a CommandService object for the given profile.
  explicit CommandService(Profile* profile);
  virtual ~CommandService();

  // Gets the keybinding (if any) for the browser action of an extension given
  // its |extension_id|. The function consults the master list to see if
  // the keybinding is active. Returns false if the extension has no browser
  // action. Returns false if the keybinding is not active and |type| requested
  // is ACTIVE_ONLY. |command| contains the command found and |active| (if not
  // NULL) contains whether |command| is active.
  bool GetBrowserActionCommand(const std::string& extension_id,
                               QueryType type,
                               extensions::Command* command,
                               bool* active);

  // Gets the keybinding (if any) for the page action of an extension given
  // its |extension_id|. The function consults the master list to see if
  // the keybinding is active. Returns false if the extension has no page
  // action. Returns false if the keybinding is not active and |type| requested
  // is ACTIVE_ONLY. |command| contains the command found and |active| (if not
  // NULL) contains whether |command| is active.
  bool GetPageActionCommand(const std::string& extension_id,
                            QueryType type,
                            extensions::Command* command,
                            bool* active);

  // Gets the active keybinding (if any) for the named commands of an extension
  // given its |extension_id|. The function consults the master list to see if
  // the keybinding is active. Returns an empty map if the extension has no
  // named commands or no active named commands when |type| requested is
  // ACTIVE_ONLY.
  bool GetNamedCommands(const std::string& extension_id,
                        QueryType type,
                        extensions::CommandMap* command_map);

  // Records a keybinding |accelerator| as active for an extension with id
  // |extension_id| and command with the name |command_name|. If
  // |allow_overrides| is false, the keybinding must be free for the change to
  // be recorded (as determined by the master list in |user_prefs|). If
  // |allow_overwrites| is true, any previously recorded keybinding for this
  // |accelerator| will be overwritten. Returns true if the change was
  // successfully recorded.
  bool AddKeybindingPref(const ui::Accelerator& accelerator,
                         std::string extension_id,
                         std::string command_name,
                         bool allow_overrides);

  // Update the keybinding prefs (for a command with a matching |extension_id|
  // and |command_name|) to |keystroke|. If the command had another key assigned
  // that key assignment will be removed.
  void UpdateKeybindingPrefs(const std::string& extension_id,
                             const std::string& command_name,
                             const std::string& keystroke);

  // Finds the shortcut assigned to a command with the name |command_name|
  // within an extension with id |extension_id|. Returns an empty Accelerator
  // object (with keycode VKEY_UNKNOWN) if no shortcut is assigned or the
  // command is not found.
  ui::Accelerator FindShortcutForCommand(const std::string& extension_id,
                                         const std::string& command);

  // Overridden from content::NotificationObserver.
  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) OVERRIDE;

 private:
  // Assigns initial keybinding for a given |extension|'s page action, browser
  // action and named commands. In each case, if the suggested keybinding is
  // free, it will be taken by this extension. If not, that keybinding request
  // is ignored. |user_pref| is the PrefService used to record the new
  // keybinding assignment.
  void AssignInitialKeybindings(const extensions::Extension* extension);

  // Removes all keybindings for a given extension by its |extension_id|.
  // |command_name| is optional and if specified, causes only the command with
  // the name |command_name| to be removed.
  void RemoveKeybindingPrefs(const std::string& extension_id,
                             const std::string& command_name);

  bool GetExtensionActionCommand(const std::string& extension_id,
                                 QueryType type,
                                 extensions::Command* command,
                                 bool* active,
                                 bool browser_action);

  // The content notification registrar for listening to extension events.
  content::NotificationRegistrar registrar_;

  // A weak pointer to the profile we are associated with. Not owned by us.
  Profile* profile_;

  DISALLOW_COPY_AND_ASSIGN(CommandService);
};

}  //  namespace extensions

#endif  // CHROME_BROWSER_EXTENSIONS_API_COMMANDS_COMMAND_SERVICE_H_