// Copyright (c) 2011 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_REMOTING_SETUP_FLOW_H_
#define CHROME_BROWSER_REMOTING_SETUP_FLOW_H_

#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/ui/webui/html_dialog_ui.h"
#include "chrome/common/remoting/chromoting_host_info.h"
#include "content/browser/webui/web_ui.h"

class ListValue;
class ServiceProcessControl;

namespace remoting {

class SetupFlow;

// SetupFlowStep represents a single step for SetupFlow, e.g. login or
// host registration. When a step is finished, GetNextStep() is called
// to get the step that must follow.
class SetupFlowStep {
 public:
  typedef Callback0::Type DoneCallback;

  SetupFlowStep();
  virtual ~SetupFlowStep();

  // Start the step. Ownership of |done_callback| is given to the
  // function. |done_callback| is called when the step is finished,
  // The callback must be called on the same thread as Start().
  virtual void Start(SetupFlow* flow, DoneCallback* done_callback) = 0;

  // Called to handle |message| received from UI. |args| may be set to
  // NULL.
  virtual void HandleMessage(const std::string& message, const Value* arg) = 0;

  // Called if user closes the dialog.
  virtual void Cancel() = 0;

  // Returns SetupFlowStep object that corresponds to the next
  // step. Must never return NULL.
  virtual SetupFlowStep* GetNextStep() = 0;

 private:
  DISALLOW_COPY_AND_ASSIGN(SetupFlowStep);
};

// SetupFlowStepBase implements base functions common for all
// SetupFlowStep implementations.
class SetupFlowStepBase : public SetupFlowStep {
 public:
  SetupFlowStepBase();
  ~SetupFlowStepBase();

  // SetupFlowStep implementation.
  virtual void Start(SetupFlow* flow, DoneCallback* done_callback);
  virtual SetupFlowStep* GetNextStep();

 protected:
  SetupFlow* flow() { return flow_; }

  void ExecuteJavascriptInIFrame(const std::wstring& iframe_xpath,
                                 const std::wstring& js);

  // Finish current step. Calls |done_callback| specified in Start().
  // GetNextStep() will return the specified |next_step|.
  void FinishStep(SetupFlowStep* next_step);

  // Called from Start(). Child classes must override this method
  // instead of Start().
  virtual void DoStart() = 0;

 private:
  SetupFlow* flow_;
  scoped_ptr<DoneCallback> done_callback_;
  bool done_;

  // Next step stored between Done() and GetNextStep();
  SetupFlowStep* next_step_;

  DISALLOW_COPY_AND_ASSIGN(SetupFlowStepBase);
};

// Base class for error steps. It shows the error message returned by
// GetErrorMessage() and Retry button.
class SetupFlowErrorStepBase : public SetupFlowStepBase {
 public:
  SetupFlowErrorStepBase();
  virtual ~SetupFlowErrorStepBase();

  // SetupFlowStep implementation.
  virtual void HandleMessage(const std::string& message, const Value* arg);
  virtual void Cancel();

 protected:
  virtual void DoStart();

  // Returns error message that is shown to the user.
  virtual string16 GetErrorMessage() = 0;

  // Called when user clicks Retry button. Normally this methoud just
  // calls FinishStep() with an appropriate next step.
  virtual void Retry() = 0;

 private:
  DISALLOW_COPY_AND_ASSIGN(SetupFlowErrorStepBase);
};

// The last step in the setup flow. This step never finishes, user is
// expected to close dialog after that.
class SetupFlowDoneStep : public SetupFlowStepBase {
 public:
  SetupFlowDoneStep();
  explicit SetupFlowDoneStep(const string16& message);
  virtual ~SetupFlowDoneStep();

  // SetupFlowStep implementation.
  virtual void HandleMessage(const std::string& message, const Value* arg);
  virtual void Cancel();

 protected:
  virtual void DoStart();

 private:
  string16 message_;

  DISALLOW_COPY_AND_ASSIGN(SetupFlowDoneStep);
};

// SetupFlowContext stores data that needs to be passed between
// different setup flow steps.
struct SetupFlowContext {
  SetupFlowContext();
  ~SetupFlowContext();

  std::string login;
  std::string remoting_token;
  std::string talk_token;

  ChromotingHostInfo host_info;
};

// This class is responsible for showing a remoting setup dialog and
// perform operations to fill the content of the dialog and handle
// user actions in the dialog.
//
// Each page in the setup flow may send message to the current
// step. In order to do that it must use send a RemotingSetup message
// and specify message name as the first value in the argument
// list. For example the following code sends Retry message to the
// current step:
//
//     chrome.send("RemotingSetup", ["Retry"])
//
// Assitional message parameters may be provided via send value in the
// arguments list, e.g.:
//
//     chrome.send("RemotingSetup", ["SubmitAuth", auth_data])
//
// In this case auth_data would be passed in
// SetupFlowStep::HandleMessage().
class SetupFlow : public WebUIMessageHandler,
                  public HtmlDialogUIDelegate {
 public:
  virtual ~SetupFlow();

  static SetupFlow* OpenSetupDialog(Profile* profile);

  WebUI* web_ui() { return web_ui_; }
  Profile* profile() { return profile_; }
  SetupFlowContext* context() { return &context_; }

 private:
  explicit SetupFlow(const std::string& args, Profile* profile,
                     SetupFlowStep* first_step);

  // HtmlDialogUIDelegate implementation.
  virtual GURL GetDialogContentURL() const;
  virtual void GetWebUIMessageHandlers(
      std::vector<WebUIMessageHandler*>* handlers) const;
  virtual void GetDialogSize(gfx::Size* size) const;
  virtual std::string GetDialogArgs() const;
  virtual void OnDialogClosed(const std::string& json_retval);
  virtual void OnCloseContents(TabContents* source, bool* out_close_dialog);
  virtual std::wstring GetDialogTitle() const;
  virtual bool IsDialogModal() const;
  virtual bool ShouldShowDialogTitle() const;

  // WebUIMessageHandler implementation.
  virtual WebUIMessageHandler* Attach(WebUI* web_ui);
  virtual void RegisterMessages();

  // Message handlers for the messages we receive from UI.
  void HandleSubmitAuth(const ListValue* args);
  void HandleUIMessage(const ListValue* args);

  void StartCurrentStep();
  void OnStepDone();

  // Pointer to the Web UI. This is provided by RemotingSetupMessageHandler
  // when attached.
  WebUI* web_ui_;

  // The args to pass to the initial page.
  std::string dialog_start_args_;
  Profile* profile_;

  SetupFlowContext context_;

  scoped_ptr<SetupFlowStep> current_step_;

  DISALLOW_COPY_AND_ASSIGN(SetupFlow);
};

}  // namespace remoting

#endif  // CHROME_BROWSER_REMOTING_SETUP_FLOW_H_