/*
 *  Copyright (c) 2014 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/win/screen_capture_utils.h"

#include <shellscalingapi.h>
#include <windows.h>

#include <cstddef>
#include <optional>
#include <string>
#include <vector>

#include "modules/desktop_capture/desktop_capture_types.h"
#include "modules/desktop_capture/desktop_capturer.h"
#include "modules/desktop_capture/desktop_geometry.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/string_utils.h"
#include "rtc_base/win32.h"

namespace webrtc {

bool HasActiveDisplay() {
  DesktopCapturer::SourceList screens;

  return GetScreenList(&screens) && !screens.empty();
}

bool GetScreenList(DesktopCapturer::SourceList* screens,
                   std::vector<std::string>* device_names /* = nullptr */) {
  RTC_DCHECK(screens->empty());
  RTC_DCHECK(!device_names || device_names->empty());

  BOOL enum_result = TRUE;
  for (int device_index = 0;; ++device_index) {
    DISPLAY_DEVICEW device;
    device.cb = sizeof(device);
    enum_result = EnumDisplayDevicesW(NULL, device_index, &device, 0);

    // `enum_result` is 0 if we have enumerated all devices.
    if (!enum_result) {
      break;
    }

    // We only care about active displays.
    if (!(device.StateFlags & DISPLAY_DEVICE_ACTIVE)) {
      continue;
    }

    screens->push_back({device_index, std::string()});
    if (device_names) {
      device_names->push_back(ToUtf8(device.DeviceName));
    }
  }
  return true;
}

bool GetHmonitorFromDeviceIndex(const DesktopCapturer::SourceId device_index,
                                HMONITOR* hmonitor) {
  // A device index of `kFullDesktopScreenId` or -1 represents all screens, an
  // HMONITOR of 0 indicates the same.
  if (device_index == kFullDesktopScreenId) {
    *hmonitor = 0;
    return true;
  }

  DesktopRect screen_rect = GetScreenRect(device_index, std::nullopt);
  if (screen_rect.is_empty()) {
    return false;
  }

  RECT rect = {screen_rect.left(), screen_rect.top(), screen_rect.right(),
               screen_rect.bottom()};

  HMONITOR monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONULL);
  if (monitor == NULL) {
    RTC_LOG(LS_WARNING) << "No HMONITOR found for supplied device index.";
    return false;
  }

  *hmonitor = monitor;
  return true;
}

bool IsMonitorValid(const HMONITOR monitor) {
  // An HMONITOR of 0 refers to a virtual monitor that spans all physical
  // monitors.
  if (monitor == 0) {
    // There is a bug in a Windows OS API that causes a crash when capturing if
    // there are no active displays. We must ensure there is an active display
    // before returning true.
    if (!HasActiveDisplay())
      return false;

    return true;
  }

  MONITORINFO monitor_info;
  monitor_info.cbSize = sizeof(MONITORINFO);
  return GetMonitorInfoA(monitor, &monitor_info);
}

DesktopRect GetMonitorRect(const HMONITOR monitor) {
  MONITORINFO monitor_info;
  monitor_info.cbSize = sizeof(MONITORINFO);
  if (!GetMonitorInfoA(monitor, &monitor_info)) {
    return DesktopRect();
  }

  return DesktopRect::MakeLTRB(
      monitor_info.rcMonitor.left, monitor_info.rcMonitor.top,
      monitor_info.rcMonitor.right, monitor_info.rcMonitor.bottom);
}

bool IsScreenValid(const DesktopCapturer::SourceId screen,
                   std::wstring* device_key) {
  if (screen == kFullDesktopScreenId) {
    *device_key = L"";
    return true;
  }

  DISPLAY_DEVICEW device;
  device.cb = sizeof(device);
  BOOL enum_result = EnumDisplayDevicesW(NULL, screen, &device, 0);
  if (enum_result) {
    *device_key = device.DeviceKey;
  }

  return !!enum_result;
}

DesktopRect GetFullscreenRect() {
  return DesktopRect::MakeXYWH(GetSystemMetrics(SM_XVIRTUALSCREEN),
                               GetSystemMetrics(SM_YVIRTUALSCREEN),
                               GetSystemMetrics(SM_CXVIRTUALSCREEN),
                               GetSystemMetrics(SM_CYVIRTUALSCREEN));
}

DesktopVector GetDpiForMonitor(HMONITOR monitor) {
  UINT dpi_x, dpi_y;
  // MDT_EFFECTIVE_DPI includes the scale factor as well as the system DPI.
  HRESULT hr = ::GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y);
  if (SUCCEEDED(hr)) {
    return {static_cast<INT>(dpi_x), static_cast<INT>(dpi_y)};
  }
  RTC_LOG_GLE_EX(LS_WARNING, hr) << "GetDpiForMonitor() failed";

  // If we can't get the per-monitor DPI, then return the system DPI.
  HDC hdc = GetDC(nullptr);
  if (hdc) {
    DesktopVector dpi{GetDeviceCaps(hdc, LOGPIXELSX),
                      GetDeviceCaps(hdc, LOGPIXELSY)};
    ReleaseDC(nullptr, hdc);
    return dpi;
  }

  // If everything fails, then return the default DPI for Windows.
  return {96, 96};
}

DesktopRect GetScreenRect(const DesktopCapturer::SourceId screen,
                          const std::optional<std::wstring>& device_key) {
  if (screen == kFullDesktopScreenId) {
    return GetFullscreenRect();
  }

  DISPLAY_DEVICEW device;
  device.cb = sizeof(device);
  BOOL result = EnumDisplayDevicesW(NULL, screen, &device, 0);
  if (!result) {
    return DesktopRect();
  }

  // Verifies the device index still maps to the same display device, to make
  // sure we are capturing the same device when devices are added or removed.
  // DeviceKey is documented as reserved, but it actually contains the registry
  // key for the device and is unique for each monitor, while DeviceID is not.
  if (device_key.has_value() && *device_key != device.DeviceKey) {
    return DesktopRect();
  }

  DEVMODEW device_mode;
  device_mode.dmSize = sizeof(device_mode);
  device_mode.dmDriverExtra = 0;
  result = EnumDisplaySettingsExW(device.DeviceName, ENUM_CURRENT_SETTINGS,
                                  &device_mode, 0);
  if (!result) {
    return DesktopRect();
  }

  return DesktopRect::MakeXYWH(
      device_mode.dmPosition.x, device_mode.dmPosition.y,
      device_mode.dmPelsWidth, device_mode.dmPelsHeight);
}

}  // namespace webrtc
