// Copyright 2015 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.

#include "ppapi/proxy/camera_device_resource.h"

#include "ppapi/proxy/camera_capabilities_resource.h"
#include "ppapi/proxy/plugin_resource_tracker.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/shared_impl/var.h"

namespace ppapi {
namespace proxy {

CameraDeviceResource::CameraDeviceResource(Connection connection,
                                           PP_Instance instance)
    : PluginResource(connection, instance),
      open_state_(OpenState::BEFORE_OPEN) {
  SendCreate(RENDERER, PpapiHostMsg_CameraDevice_Create());
}

CameraDeviceResource::~CameraDeviceResource() {
}

int32_t CameraDeviceResource::Open(
    PP_Var device_id,
    const scoped_refptr<TrackedCallback>& callback) {
  if (open_state_ != OpenState::BEFORE_OPEN)
    return PP_ERROR_FAILED;

  if (TrackedCallback::IsPending(open_callback_))
    return PP_ERROR_INPROGRESS;

  scoped_refptr<StringVar> source_string_var(StringVar::FromPPVar(device_id));
  if (!source_string_var || source_string_var->value().empty())
    return PP_ERROR_BADARGUMENT;

  open_callback_ = callback;

  Call<PpapiPluginMsg_CameraDevice_OpenReply>(
      RENDERER, PpapiHostMsg_CameraDevice_Open(source_string_var->value()),
      base::Bind(&CameraDeviceResource::OnPluginMsgOpenReply,
                 base::Unretained(this)));
  return PP_OK_COMPLETIONPENDING;
}

void CameraDeviceResource::Close() {
  if (open_state_ == OpenState::CLOSED)
    return;

  if (TrackedCallback::IsPending(open_callback_)) {
    open_callback_->PostAbort();
    open_callback_ = nullptr;
  }

  if (TrackedCallback::IsPending(get_capabilities_callback_)) {
    get_capabilities_callback_->PostAbort();
    get_capabilities_callback_ = nullptr;
  }

  Post(RENDERER, PpapiHostMsg_CameraDevice_Close());

  open_state_ = OpenState::CLOSED;
}

int32_t CameraDeviceResource::GetCameraCapabilities(
    PP_Resource* capabilities,
    const scoped_refptr<TrackedCallback>& callback) {
  if (!is_opened())
    return PP_ERROR_FAILED;

  if (TrackedCallback::IsPending(get_capabilities_callback_))
    return PP_ERROR_INPROGRESS;

  if (camera_capabilities_.get()) {
    *capabilities = camera_capabilities_->GetReference();
    return PP_OK;
  }

  get_capabilities_callback_ = callback;
  Call<PpapiPluginMsg_CameraDevice_GetSupportedVideoCaptureFormatsReply>(
      RENDERER, PpapiHostMsg_CameraDevice_GetSupportedVideoCaptureFormats(),
      base::Bind(&CameraDeviceResource::OnPluginMsgGetVideoCaptureFormatsReply,
                 base::Unretained(this), capabilities));

  return PP_OK_COMPLETIONPENDING;
}

void CameraDeviceResource::OnPluginMsgOpenReply(
    const ResourceMessageReplyParams& params) {
  // The callback may have been aborted by Close().
  if (TrackedCallback::IsPending(open_callback_)) {
    if (open_state_ == OpenState::BEFORE_OPEN && params.result() == PP_OK)
      open_state_ = OpenState::OPENED;

    open_callback_->Run(params.result());
  }
}

void CameraDeviceResource::OnPluginMsgGetVideoCaptureFormatsReply(
    PP_Resource* capabilities_output,
    const ResourceMessageReplyParams& params,
    const std::vector<PP_VideoCaptureFormat>& formats) {
  if (!TrackedCallback::IsPending(get_capabilities_callback_))
    return;

  // Return camera capabilities.
  int32_t result = params.result();
  scoped_refptr<TrackedCallback> callback;
  callback.swap(get_capabilities_callback_);
  if (result == PP_OK) {
    camera_capabilities_ =
        new CameraCapabilitiesResource(pp_instance(), formats);
    *capabilities_output = camera_capabilities_->GetReference();
  }
  callback->Run(result == PP_OK ? PP_OK : PP_ERROR_FAILED);
}

}  // namespace proxy
}  // namespace ppapi
