/*
 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "modules/desktop_capture/mouse_cursor_monitor.h"

#include <assert.h>

#include <memory>

#include <ApplicationServices/ApplicationServices.h>
#include <Cocoa/Cocoa.h>
#include <CoreFoundation/CoreFoundation.h>

#include "api/scoped_refptr.h"
#include "modules/desktop_capture/desktop_capture_options.h"
#include "modules/desktop_capture/desktop_capture_types.h"
#include "modules/desktop_capture/desktop_frame.h"
#include "modules/desktop_capture/mac/desktop_configuration.h"
#include "modules/desktop_capture/mac/desktop_configuration_monitor.h"
#include "modules/desktop_capture/mac/full_screen_chrome_window_detector.h"
#include "modules/desktop_capture/mac/window_list_utils.h"
#include "modules/desktop_capture/mouse_cursor.h"
#include "rtc_base/mac_utils.h"

namespace webrtc {

namespace {
CGImageRef CreateScaledCGImage(CGImageRef image, int width, int height) {
  // Create context, keeping original image properties.
  CGColorSpaceRef colorspace = CGImageGetColorSpace(image);
  CGContextRef context = CGBitmapContextCreate(nullptr,
                                               width,
                                               height,
                                               CGImageGetBitsPerComponent(image),
                                               width * DesktopFrame::kBytesPerPixel,
                                               colorspace,
                                               CGImageGetBitmapInfo(image));

  if (!context) return nil;

  // Draw image to context, resizing it.
  CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
  // Extract resulting image from context.
  CGImageRef imgRef = CGBitmapContextCreateImage(context);
  CGContextRelease(context);

  return imgRef;
}
}  // namespace

class MouseCursorMonitorMac : public MouseCursorMonitor {
 public:
  MouseCursorMonitorMac(const DesktopCaptureOptions& options,
                        CGWindowID window_id,
                        ScreenId screen_id);
  ~MouseCursorMonitorMac() override;

  void Init(Callback* callback, Mode mode) override;
  void Capture() override;

 private:
  static void DisplaysReconfiguredCallback(CGDirectDisplayID display,
                                           CGDisplayChangeSummaryFlags flags,
                                           void *user_parameter);
  void DisplaysReconfigured(CGDirectDisplayID display,
                            CGDisplayChangeSummaryFlags flags);

  void CaptureImage(float scale);

  rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_;
  CGWindowID window_id_;
  ScreenId screen_id_;
  Callback* callback_;
  Mode mode_;
  __strong NSImage* last_cursor_;
  rtc::scoped_refptr<FullScreenChromeWindowDetector>
      full_screen_chrome_window_detector_;
};

MouseCursorMonitorMac::MouseCursorMonitorMac(
    const DesktopCaptureOptions& options,
    CGWindowID window_id,
    ScreenId screen_id)
    : configuration_monitor_(options.configuration_monitor()),
      window_id_(window_id),
      screen_id_(screen_id),
      callback_(NULL),
      mode_(SHAPE_AND_POSITION),
      full_screen_chrome_window_detector_(
          options.full_screen_chrome_window_detector()) {
  assert(window_id == kCGNullWindowID || screen_id == kInvalidScreenId);
}

MouseCursorMonitorMac::~MouseCursorMonitorMac() {}

void MouseCursorMonitorMac::Init(Callback* callback, Mode mode) {
  assert(!callback_);
  assert(callback);

  callback_ = callback;
  mode_ = mode;
}

void MouseCursorMonitorMac::Capture() {
  assert(callback_);

  CGEventRef event = CGEventCreate(NULL);
  CGPoint gc_position = CGEventGetLocation(event);
  CFRelease(event);

  DesktopVector position(gc_position.x, gc_position.y);

  MacDesktopConfiguration configuration =
      configuration_monitor_->desktop_configuration();
  float scale = GetScaleFactorAtPosition(configuration, position);

  CaptureImage(scale);

  if (mode_ != SHAPE_AND_POSITION)
    return;

  // Always report cursor position in DIP pixel.
  callback_->OnMouseCursorPosition(
      position.subtract(configuration.bounds.top_left()));
}

void MouseCursorMonitorMac::CaptureImage(float scale) {
  NSCursor* nscursor = [NSCursor currentSystemCursor];

  NSImage* nsimage = [nscursor image];
  if (nsimage == nil || !nsimage.isValid) {
    return;
  }
  NSSize nssize = [nsimage size];  // DIP size

  // No need to caputre cursor image if it's unchanged since last capture.
  if ([[nsimage TIFFRepresentation] isEqual:[last_cursor_ TIFFRepresentation]]) return;
  last_cursor_ = nsimage;

  DesktopSize size(round(nssize.width * scale),
                   round(nssize.height * scale));  // Pixel size
  NSPoint nshotspot = [nscursor hotSpot];
  DesktopVector hotspot(
      std::max(0,
               std::min(size.width(), static_cast<int>(nshotspot.x * scale))),
      std::max(0,
               std::min(size.height(), static_cast<int>(nshotspot.y * scale))));
  CGImageRef cg_image =
      [nsimage CGImageForProposedRect:NULL context:nil hints:nil];
  if (!cg_image)
    return;

  // Before 10.12, OSX may report 1X cursor on Retina screen. (See
  // crbug.com/632995.) After 10.12, OSX may report 2X cursor on non-Retina
  // screen. (See crbug.com/671436.) So scaling the cursor if needed.
  CGImageRef scaled_cg_image = nil;
  if (CGImageGetWidth(cg_image) != static_cast<size_t>(size.width())) {
    scaled_cg_image = CreateScaledCGImage(cg_image, size.width(), size.height());
    if (scaled_cg_image != nil) {
      cg_image = scaled_cg_image;
    }
  }
  if (CGImageGetBitsPerPixel(cg_image) != DesktopFrame::kBytesPerPixel * 8 ||
      CGImageGetWidth(cg_image) != static_cast<size_t>(size.width()) ||
      CGImageGetBitsPerComponent(cg_image) != 8) {
    if (scaled_cg_image != nil) CGImageRelease(scaled_cg_image);
    return;
  }

  CGDataProviderRef provider = CGImageGetDataProvider(cg_image);
  CFDataRef image_data_ref = CGDataProviderCopyData(provider);
  if (image_data_ref == NULL) {
    if (scaled_cg_image != nil) CGImageRelease(scaled_cg_image);
    return;
  }

  const uint8_t* src_data =
      reinterpret_cast<const uint8_t*>(CFDataGetBytePtr(image_data_ref));

  // Create a MouseCursor that describes the cursor and pass it to
  // the client.
  std::unique_ptr<DesktopFrame> image(
      new BasicDesktopFrame(DesktopSize(size.width(), size.height())));

  int src_stride = CGImageGetBytesPerRow(cg_image);
  image->CopyPixelsFrom(src_data, src_stride, DesktopRect::MakeSize(size));

  CFRelease(image_data_ref);
  if (scaled_cg_image != nil) CGImageRelease(scaled_cg_image);

  std::unique_ptr<MouseCursor> cursor(
      new MouseCursor(image.release(), hotspot));

  callback_->OnMouseCursor(cursor.release());
}

MouseCursorMonitor* MouseCursorMonitor::CreateForWindow(
    const DesktopCaptureOptions& options, WindowId window) {
  return new MouseCursorMonitorMac(options, window, kInvalidScreenId);
}

MouseCursorMonitor* MouseCursorMonitor::CreateForScreen(
    const DesktopCaptureOptions& options,
    ScreenId screen) {
  return new MouseCursorMonitorMac(options, kCGNullWindowID, screen);
}

std::unique_ptr<MouseCursorMonitor> MouseCursorMonitor::Create(
    const DesktopCaptureOptions& options) {
  return std::unique_ptr<MouseCursorMonitor>(
      CreateForScreen(options, kFullDesktopScreenId));
}

}  // namespace webrtc
