/*
 *  Copyright (c) 2016 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 "webrtc/modules/desktop_capture/desktop_frame_generator.h"

#include <stdint.h>
#include <string.h>

#include <memory>

#include "webrtc/base/random.h"
#include "webrtc/base/timeutils.h"
#include "webrtc/modules/desktop_capture/rgba_color.h"

namespace webrtc {

namespace {

// Sets |updated_region| to |frame|. If |enlarge_updated_region| is
// true, this function will randomly enlarge each DesktopRect in
// |updated_region|. But the enlarged DesktopRegion won't excceed the
// frame->size(). If |add_random_updated_region| is true, several random
// rectangles will also be included in |frame|.
void SetUpdatedRegion(DesktopFrame* frame,
                      const DesktopRegion& updated_region,
                      bool enlarge_updated_region,
                      int enlarge_range,
                      bool add_random_updated_region) {
  const DesktopRect screen_rect = DesktopRect::MakeSize(frame->size());
  Random random(rtc::TimeMicros());
  frame->mutable_updated_region()->Clear();
  for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd();
       it.Advance()) {
    DesktopRect rect = it.rect();
    if (enlarge_updated_region && enlarge_range > 0) {
      rect.Extend(random.Rand(enlarge_range), random.Rand(enlarge_range),
                  random.Rand(enlarge_range), random.Rand(enlarge_range));
      rect.IntersectWith(screen_rect);
    }
    frame->mutable_updated_region()->AddRect(rect);
  }

  if (add_random_updated_region) {
    for (int i = random.Rand(10); i >= 0; i--) {
      // At least a 1 x 1 updated region.
      const int left = random.Rand(0, frame->size().width() - 2);
      const int top = random.Rand(0, frame->size().height() - 2);
      const int right = random.Rand(left + 1, frame->size().width());
      const int bottom = random.Rand(top + 1, frame->size().height());
      frame->mutable_updated_region()->AddRect(
          DesktopRect::MakeLTRB(left, top, right, bottom));
    }
  }
}

// Paints pixels in |rect| of |frame| to |color|.
void PaintRect(DesktopFrame* frame, DesktopRect rect, RgbaColor rgba_color) {
  static_assert(DesktopFrame::kBytesPerPixel == sizeof(uint32_t),
                "kBytesPerPixel should be 4.");
  RTC_DCHECK(frame->size().width() >= rect.right() &&
             frame->size().height() >= rect.bottom());
  uint32_t color = rgba_color.ToUInt32();
  uint8_t* row = frame->GetFrameDataAtPos(rect.top_left());
  for (int i = 0; i < rect.height(); i++) {
    uint32_t* column = reinterpret_cast<uint32_t*>(row);
    for (int j = 0; j < rect.width(); j++) {
      column[j] = color;
    }
    row += frame->stride();
  }
}

// Paints pixels in |region| of |frame| to |color|.
void PaintRegion(DesktopFrame* frame,
                 DesktopRegion* region,
                 RgbaColor rgba_color) {
  region->IntersectWith(DesktopRect::MakeSize(frame->size()));
  for (DesktopRegion::Iterator it(*region); !it.IsAtEnd(); it.Advance()) {
    PaintRect(frame, it.rect(), rgba_color);
  }
}

}  // namespace

DesktopFrameGenerator::DesktopFrameGenerator() {}
DesktopFrameGenerator::~DesktopFrameGenerator() {}

DesktopFramePainter::DesktopFramePainter() {}
DesktopFramePainter::~DesktopFramePainter() {}

PainterDesktopFrameGenerator::PainterDesktopFrameGenerator()
    : size_(1024, 768),
      return_frame_(true),
      provide_updated_region_hints_(false),
      enlarge_updated_region_(false),
      enlarge_range_(20),
      add_random_updated_region_(false),
      painter_(nullptr) {}
PainterDesktopFrameGenerator::~PainterDesktopFrameGenerator() {}

std::unique_ptr<DesktopFrame> PainterDesktopFrameGenerator::GetNextFrame(
    SharedMemoryFactory* factory) {
  if (!return_frame_) {
    return nullptr;
  }

  std::unique_ptr<DesktopFrame> frame = std::unique_ptr<DesktopFrame>(
      factory ? SharedMemoryDesktopFrame::Create(size_, factory).release()
              : new BasicDesktopFrame(size_));
  if (painter_) {
    DesktopRegion updated_region;
    if (!painter_->Paint(frame.get(), &updated_region)) {
      return nullptr;
    }

    if (provide_updated_region_hints_) {
      SetUpdatedRegion(frame.get(), updated_region, enlarge_updated_region_,
                       enlarge_range_, add_random_updated_region_);
    } else {
      frame->mutable_updated_region()->SetRect(
          DesktopRect::MakeSize(frame->size()));
    }
  }

  return frame;
}

DesktopSize* PainterDesktopFrameGenerator::size() {
  return &size_;
}

void PainterDesktopFrameGenerator::set_return_frame(bool return_frame) {
  return_frame_ = return_frame;
}

void PainterDesktopFrameGenerator::set_provide_updated_region_hints(
    bool provide_updated_region_hints) {
  provide_updated_region_hints_ = provide_updated_region_hints;
}

void PainterDesktopFrameGenerator::set_enlarge_updated_region(
    bool enlarge_updated_region) {
  enlarge_updated_region_ = enlarge_updated_region;
}

void PainterDesktopFrameGenerator::set_enlarge_range(int enlarge_range) {
  enlarge_range_ = enlarge_range;
}

void PainterDesktopFrameGenerator::set_add_random_updated_region(
    bool add_random_updated_region) {
  add_random_updated_region_ = add_random_updated_region;
}

void PainterDesktopFrameGenerator::set_desktop_frame_painter(
    DesktopFramePainter* painter) {
  painter_ = painter;
}

BlackWhiteDesktopFramePainter::BlackWhiteDesktopFramePainter() {}
BlackWhiteDesktopFramePainter::~BlackWhiteDesktopFramePainter() {}

DesktopRegion* BlackWhiteDesktopFramePainter::updated_region() {
  return &updated_region_;
}

bool BlackWhiteDesktopFramePainter::Paint(DesktopFrame* frame,
                                          DesktopRegion* updated_region) {
  RTC_DCHECK(updated_region->is_empty());
  memset(frame->data(), 0, frame->stride() * frame->size().height());
  PaintRegion(frame, &updated_region_, RgbaColor(0xFFFFFFFF));
  updated_region_.Swap(updated_region);
  return true;
}

}  // namespace webrtc
