/*
 * libjingle
 * Copyright 2012 Google Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "talk/media/base/capturemanager.h"

#include <algorithm>

#include "talk/media/base/videocapturer.h"
#include "talk/media/base/videoprocessor.h"
#include "talk/media/base/videorenderer.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"

namespace cricket {

// CaptureManager helper class.
class VideoCapturerState {
 public:
  static const VideoFormatPod kDefaultCaptureFormat;

  static VideoCapturerState* Create(VideoCapturer* video_capturer);
  ~VideoCapturerState() {}

  void AddCaptureResolution(const VideoFormat& desired_format);
  bool RemoveCaptureResolution(const VideoFormat& format);
  VideoFormat GetHighestFormat(VideoCapturer* video_capturer) const;

  int IncCaptureStartRef();
  int DecCaptureStartRef();
  CaptureRenderAdapter* adapter() {
    DCHECK(thread_checker_.CalledOnValidThread());
    return adapter_.get();
  }
  VideoCapturer* GetVideoCapturer() {
    DCHECK(thread_checker_.CalledOnValidThread());
    return adapter()->video_capturer();
  }

  int start_count() const {
    DCHECK(thread_checker_.CalledOnValidThread());
    return start_count_;
  }

 private:
  struct CaptureResolutionInfo {
    VideoFormat video_format;
    int format_ref_count;
  };
  typedef std::vector<CaptureResolutionInfo> CaptureFormats;

  explicit VideoCapturerState(CaptureRenderAdapter* adapter);

  rtc::ThreadChecker thread_checker_;
  rtc::scoped_ptr<CaptureRenderAdapter> adapter_;

  int start_count_;
  CaptureFormats capture_formats_;
};

const VideoFormatPod VideoCapturerState::kDefaultCaptureFormat = {
  640, 360, FPS_TO_INTERVAL(30), FOURCC_ANY
};

VideoCapturerState::VideoCapturerState(CaptureRenderAdapter* adapter)
    : adapter_(adapter), start_count_(1) {}

// static
VideoCapturerState* VideoCapturerState::Create(VideoCapturer* video_capturer) {
  CaptureRenderAdapter* adapter = CaptureRenderAdapter::Create(video_capturer);
  if (!adapter) {
    return NULL;
  }
  return new VideoCapturerState(adapter);
}

void VideoCapturerState::AddCaptureResolution(
    const VideoFormat& desired_format) {
  DCHECK(thread_checker_.CalledOnValidThread());
  for (CaptureFormats::iterator iter = capture_formats_.begin();
       iter != capture_formats_.end(); ++iter) {
    if (desired_format == iter->video_format) {
      ++(iter->format_ref_count);
      return;
    }
  }
  CaptureResolutionInfo capture_resolution = { desired_format, 1 };
  capture_formats_.push_back(capture_resolution);
}

bool VideoCapturerState::RemoveCaptureResolution(const VideoFormat& format) {
  DCHECK(thread_checker_.CalledOnValidThread());
  for (CaptureFormats::iterator iter = capture_formats_.begin();
       iter != capture_formats_.end(); ++iter) {
    if (format == iter->video_format) {
      --(iter->format_ref_count);
      if (iter->format_ref_count == 0) {
        capture_formats_.erase(iter);
      }
      return true;
    }
  }
  return false;
}

VideoFormat VideoCapturerState::GetHighestFormat(
    VideoCapturer* video_capturer) const {
  DCHECK(thread_checker_.CalledOnValidThread());
  VideoFormat highest_format(0, 0, VideoFormat::FpsToInterval(1), FOURCC_ANY);
  if (capture_formats_.empty()) {
    VideoFormat default_format(kDefaultCaptureFormat);
    return default_format;
  }
  for (CaptureFormats::const_iterator iter = capture_formats_.begin();
       iter != capture_formats_.end(); ++iter) {
    if (iter->video_format.width > highest_format.width) {
      highest_format.width = iter->video_format.width;
    }
    if (iter->video_format.height > highest_format.height) {
      highest_format.height = iter->video_format.height;
    }
    if (iter->video_format.interval < highest_format.interval) {
      highest_format.interval = iter->video_format.interval;
    }
  }
  return highest_format;
}

int VideoCapturerState::IncCaptureStartRef() {
  DCHECK(thread_checker_.CalledOnValidThread());
  return ++start_count_;
}

int VideoCapturerState::DecCaptureStartRef() {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (start_count_ > 0) {
    // Start count may be 0 if a capturer was added but never started.
    --start_count_;
  }
  return start_count_;
}

CaptureManager::CaptureManager() {
  // Allowing construction of manager in any thread as long as subsequent calls
  // are all from the same thread.
  thread_checker_.DetachFromThread();
}

CaptureManager::~CaptureManager() {
  DCHECK(thread_checker_.CalledOnValidThread());

  // Since we don't own any of the capturers, all capturers should have been
  // cleaned up before we get here. In fact, in the normal shutdown sequence,
  // all capturers *will* be shut down by now, so trying to stop them here
  // will crash. If we're still tracking any, it's a dangling pointer.
  // TODO(hbos): DCHECK instead of CHECK until we figure out why capture_states_
  // is not always empty here.
  DCHECK(capture_states_.empty());
}

bool CaptureManager::StartVideoCapture(VideoCapturer* video_capturer,
                                       const VideoFormat& desired_format) {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (desired_format.width == 0 || desired_format.height == 0) {
    return false;
  }
  if (!video_capturer) {
    return false;
  }
  VideoCapturerState* capture_state = GetCaptureState(video_capturer);
  if (capture_state) {
    const int ref_count = capture_state->IncCaptureStartRef();
    if (ref_count < 1) {
      ASSERT(false);
    }
    // VideoCapturer has already been started. Don't start listening to
    // callbacks since that has already been done.
    capture_state->AddCaptureResolution(desired_format);
    return true;
  }
  if (!RegisterVideoCapturer(video_capturer)) {
    return false;
  }
  capture_state = GetCaptureState(video_capturer);
  ASSERT(capture_state != NULL);
  capture_state->AddCaptureResolution(desired_format);
  if (!StartWithBestCaptureFormat(capture_state, video_capturer)) {
    UnregisterVideoCapturer(capture_state);
    return false;
  }
  return true;
}

bool CaptureManager::StopVideoCapture(VideoCapturer* video_capturer,
                                      const VideoFormat& format) {
  DCHECK(thread_checker_.CalledOnValidThread());
  VideoCapturerState* capture_state = GetCaptureState(video_capturer);
  if (!capture_state) {
    return false;
  }
  if (!capture_state->RemoveCaptureResolution(format)) {
    return false;
  }

  if (capture_state->DecCaptureStartRef() == 0) {
    // Unregistering cannot fail as capture_state is not NULL.
    UnregisterVideoCapturer(capture_state);
  }
  return true;
}

bool CaptureManager::RestartVideoCapture(
    VideoCapturer* video_capturer,
    const VideoFormat& previous_format,
    const VideoFormat& desired_format,
    CaptureManager::RestartOptions options) {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (!IsCapturerRegistered(video_capturer)) {
    LOG(LS_ERROR) << "RestartVideoCapture: video_capturer is not registered.";
    return false;
  }
  // Start the new format first. This keeps the capturer running.
  if (!StartVideoCapture(video_capturer, desired_format)) {
    LOG(LS_ERROR) << "RestartVideoCapture: unable to start video capture with "
        "desired_format=" << desired_format.ToString();
    return false;
  }
  // Stop the old format.
  if (!StopVideoCapture(video_capturer, previous_format)) {
    LOG(LS_ERROR) << "RestartVideoCapture: unable to stop video capture with "
        "previous_format=" << previous_format.ToString();
    // Undo the start request we just performed.
    StopVideoCapture(video_capturer, desired_format);
    return false;
  }

  switch (options) {
    case kForceRestart: {
      VideoCapturerState* capture_state = GetCaptureState(video_capturer);
      ASSERT(capture_state && capture_state->start_count() > 0);
      // Try a restart using the new best resolution.
      VideoFormat highest_asked_format =
          capture_state->GetHighestFormat(video_capturer);
      VideoFormat capture_format;
      if (video_capturer->GetBestCaptureFormat(highest_asked_format,
                                               &capture_format)) {
        if (!video_capturer->Restart(capture_format)) {
          LOG(LS_ERROR) << "RestartVideoCapture: Restart failed.";
        }
      } else {
        LOG(LS_WARNING)
            << "RestartVideoCapture: Couldn't find a best capture format for "
            << highest_asked_format.ToString();
      }
      break;
    }
    case kRequestRestart:
      // TODO(ryanpetrie): Support restart requests. Should this
      // to-be-implemented logic be used for {Start,Stop}VideoCapture as well?
      break;
    default:
      LOG(LS_ERROR) << "Unknown/unimplemented RestartOption";
      break;
  }
  return true;
}

bool CaptureManager::AddVideoRenderer(VideoCapturer* video_capturer,
                                      VideoRenderer* video_renderer) {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (!video_capturer || !video_renderer) {
    return false;
  }
  CaptureRenderAdapter* adapter = GetAdapter(video_capturer);
  if (!adapter) {
    return false;
  }
  return adapter->AddRenderer(video_renderer);
}

bool CaptureManager::RemoveVideoRenderer(VideoCapturer* video_capturer,
                                         VideoRenderer* video_renderer) {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (!video_capturer || !video_renderer) {
    return false;
  }
  CaptureRenderAdapter* adapter = GetAdapter(video_capturer);
  if (!adapter) {
    return false;
  }
  return adapter->RemoveRenderer(video_renderer);
}

bool CaptureManager::AddVideoProcessor(VideoCapturer* video_capturer,
                                       VideoProcessor* video_processor) {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (!video_capturer || !video_processor) {
    return false;
  }
  if (!IsCapturerRegistered(video_capturer)) {
    return false;
  }
  video_capturer->AddVideoProcessor(video_processor);
  return true;
}

bool CaptureManager::RemoveVideoProcessor(VideoCapturer* video_capturer,
                                          VideoProcessor* video_processor) {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (!video_capturer || !video_processor) {
    return false;
  }
  if (!IsCapturerRegistered(video_capturer)) {
    return false;
  }
  return video_capturer->RemoveVideoProcessor(video_processor);
}

bool CaptureManager::IsCapturerRegistered(VideoCapturer* video_capturer) const {
  DCHECK(thread_checker_.CalledOnValidThread());
  return GetCaptureState(video_capturer) != NULL;
}

bool CaptureManager::RegisterVideoCapturer(VideoCapturer* video_capturer) {
  DCHECK(thread_checker_.CalledOnValidThread());
  VideoCapturerState* capture_state =
      VideoCapturerState::Create(video_capturer);
  if (!capture_state) {
    return false;
  }
  capture_states_[video_capturer] = capture_state;
  SignalCapturerStateChange.repeat(video_capturer->SignalStateChange);
  return true;
}

void CaptureManager::UnregisterVideoCapturer(
    VideoCapturerState* capture_state) {
  DCHECK(thread_checker_.CalledOnValidThread());
  VideoCapturer* video_capturer = capture_state->GetVideoCapturer();
  capture_states_.erase(video_capturer);
  delete capture_state;

  // When unregistering a VideoCapturer, the CaptureManager needs to unregister
  // from all state change callbacks from the VideoCapturer. E.g. to avoid
  // problems with multiple callbacks if registering the same VideoCapturer
  // multiple times. The VideoCapturer will update the capturer state. However,
  // this is done through Post-calls which means it may happen at any time. If
  // the CaptureManager no longer is listening to the VideoCapturer it will not
  // receive those callbacks. Here it is made sure that the the callback is
  // indeed sent by letting the ChannelManager do the signaling. The downside is
  // that the callback may happen before the VideoCapturer is stopped. However,
  // for the CaptureManager it doesn't matter as it will no longer receive any
  // frames from the VideoCapturer.
  SignalCapturerStateChange.stop(video_capturer->SignalStateChange);
  video_capturer->Stop();
  SignalCapturerStateChange(video_capturer, CS_STOPPED);
}

bool CaptureManager::StartWithBestCaptureFormat(
    VideoCapturerState* capture_state, VideoCapturer* video_capturer) {
  DCHECK(thread_checker_.CalledOnValidThread());
  VideoFormat highest_asked_format =
      capture_state->GetHighestFormat(video_capturer);
  VideoFormat capture_format;
  if (!video_capturer->GetBestCaptureFormat(highest_asked_format,
                                            &capture_format)) {
    LOG(LS_WARNING) << "Unsupported format:"
                    << " width=" << highest_asked_format.width
                    << " height=" << highest_asked_format.height
                    << ". Supported formats are:";
    const std::vector<VideoFormat>* formats =
        video_capturer->GetSupportedFormats();
    ASSERT(formats != NULL);
    for (std::vector<VideoFormat>::const_iterator i = formats->begin();
         i != formats->end(); ++i) {
      const VideoFormat& format = *i;
      LOG(LS_WARNING) << "  " << GetFourccName(format.fourcc)
                      << ":" << format.width << "x" << format.height << "x"
                      << format.framerate();
    }
    return false;
  }
  return video_capturer->StartCapturing(capture_format);
}

VideoCapturerState* CaptureManager::GetCaptureState(
    VideoCapturer* video_capturer) const {
  DCHECK(thread_checker_.CalledOnValidThread());
  CaptureStates::const_iterator iter = capture_states_.find(video_capturer);
  if (iter == capture_states_.end()) {
    return NULL;
  }
  return iter->second;
}

CaptureRenderAdapter* CaptureManager::GetAdapter(
    VideoCapturer* video_capturer) const {
  DCHECK(thread_checker_.CalledOnValidThread());
  VideoCapturerState* capture_state = GetCaptureState(video_capturer);
  if (!capture_state) {
    return NULL;
  }
  return capture_state->adapter();
}

}  // namespace cricket
