// Copyright (c) 2006-2008 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_CONTROLLER_H__
#define CHROME_BROWSER_CONTROLLER_H__

#include <vector>

#include "base/basictypes.h"
#include "base/hash_tables.h"
#include "chrome/views/button.h"
#include "chrome/views/controller.h"

class ButtonController;

///////////////////////////////////////////////////////////////////////////////
//
// CommandObserver interface
//
//   A component of the View portion of the MVC pattern implements the
//   CommandObserver interface to update itself when the state of its command
//   changes.
//
///////////////////////////////////////////////////////////////////////////////
class CommandObserver {
 public:
  // Update the View because this command's enabled state has changed.
  virtual void SetEnabled(bool enabled) = 0;
};

///////////////////////////////////////////////////////////////////////////////
//
// CommandHandler interface
//
//   An object implementing the CommandHandler interface is responsible for
//   actually executing specific commands.
//
//   This object is also responsible for producing contextual labels if needed.
//
///////////////////////////////////////////////////////////////////////////////
class CommandHandler {
 public:

  // This method is called to give the command handler a chance to specify
  // a contextual label for the provided command id. Returns true if a
  // contextual label has been assigned or false if the default label should be
  // used.
  virtual bool GetContextualLabel(int id, std::wstring* out) const {
    return false;
  }

  // Whether the specified command can be executed.
  virtual bool IsCommandEnabled(int id) const { return true; }

  // Execute a command, according to the command's state (currently binary!)
  virtual void ExecuteCommand(int id) = 0;
};

typedef std::vector<CommandObserver*> CommandObserverList;

// A piece of data about a command - whether or not it is enabled, and a list
// of objects that observe the enabled state of this command.
struct Command {
  bool enabled;
  CommandObserverList* observers;
};
typedef base::hash_map<int, Command*> CommandMap;


///////////////////////////////////////////////////////////////////////////////
//
// Controller class
//
//   This is the Controller portion of a MVC pattern. It handles dispatching
//   commands, maintaining enabled state, and updating the UI as that state
//   changes. The purpose of using MVC and a controller like this is to
//   maintain a clear separation between rendering, control logic and various
//   data sources so that code is more maintainable.
//
///////////////////////////////////////////////////////////////////////////////
class CommandController : public Controller {
 public:
  // The controller is constructed with an object implementing the
  // CommandHandler interface, to which the Controller defers execution
  // duties. This keeps the Controller fairly simple without requiring a
  // lot of reworking of the command handlers. If there are significant
  // groups of commands that require execution separated from this handler,
  // then the Command object can be extended to provide a handler field that
  // specifies a handler different to the default.
  CommandController(CommandHandler* handler);
  virtual ~CommandController();

  // Add a button to the list of managed buttons. The button is synced with
  // the provided command
  void AddManagedButton(views::Button* button, int command);

  // Controller
  virtual bool SupportsCommand(int id) const;
  virtual bool IsCommandEnabled(int id) const;
  virtual bool GetContextualLabel(int id, std::wstring* out) const;
  virtual void ExecuteCommand(int id);


  // Adds an observer to the state of a particular command. If the command does
  // not exist, it is created, initialized to false.
  void AddCommandObserver(int id, CommandObserver* observer);

  // Removes an observer to the state of a particular command.
  void RemoveCommandObserver(int id, CommandObserver* observer);

  // Notify all observers of a particular command that the command has been
  // enabled or disabled. If the command does not exist, it is created and
  // initialized to |state|. This function is very lightweight if the command
  // state has not changed.
  void UpdateCommandEnabled(int id, bool state);

 private:
  ///////////////////////////////////////////////////////////////////////////////
  //
  // ButtonController
  //
  // An adapter class to use views buttons with our controller
  //
  ///////////////////////////////////////////////////////////////////////////////
  class ButtonController : public views::BaseButton::ButtonListener,
                           public CommandObserver {

   public:

    ButtonController(views::Button* b,
                     CommandController* controller,
                     int command)
        : button_(b),
          controller_(controller) {
      controller_->AddCommandObserver(command, this);
      button_->SetListener(this, command);

      // The button's initial state should be the current command state.
      button_->SetEnabled(controller_->IsCommandEnabled(command));
    }

    virtual void SetEnabled(bool enabled) {
      button_->SetEnabled(enabled);
    }

    virtual void ButtonPressed(views::BaseButton* sender) {
      controller_->ExecuteCommand(sender->GetTag());
    }

   private:
    views::Button* button_;
    CommandController* controller_;
  };

  // Get a Command node for a given command ID, creating an entry if it doesn't
  // exist if desired.
  Command* GetCommand(int id, bool create);

  // This is the default handler for all command execution
  CommandHandler* handler_;

  // This is a map of command IDs to states and observer lists
  CommandMap commands_;

  // vector of ButtonController for managed buttons
  std::vector<ButtonController*> managed_button_controllers_;

  CommandController();
  DISALLOW_EVIL_CONSTRUCTORS(CommandController);
};

#endif // CHROME_BROWSER_CONTROLLER_H__