/*
 *  Copyright 2017 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.
 */

#import "RTCNativeI420Buffer+Private.h"

#include <cstdint>

#include "api/video/i420_buffer.h"
#include "rtc_base/checks.h"

#if !defined(NDEBUG) && defined(WEBRTC_IOS)
#import <UIKit/UIKit.h>
#include "third_party/libyuv/include/libyuv.h"
#endif

@implementation RTC_OBJC_TYPE (RTCI420Buffer)

- (instancetype)initWithWidth:(int)width height:(int)height {
  self = [super init];
  if (self) {
    _i420Buffer = webrtc::I420Buffer::Create(width, height);
  }
  return self;
}

- (instancetype)initWithWidth:(int)width
                       height:(int)height
                        dataY:(const uint8_t *)dataY
                        dataU:(const uint8_t *)dataU
                        dataV:(const uint8_t *)dataV {
  self = [super init];
  if (self) {
    _i420Buffer = webrtc::I420Buffer::Copy(width,
                                           height,
                                           dataY,
                                           width,
                                           dataU,
                                           (width + 1) / 2,
                                           dataV,
                                           (width + 1) / 2);
  }
  return self;
}

- (instancetype)initWithWidth:(int)width
                       height:(int)height
                      strideY:(int)strideY
                      strideU:(int)strideU
                      strideV:(int)strideV {
  self = [super init];
  if (self) {
    _i420Buffer =
        webrtc::I420Buffer::Create(width, height, strideY, strideU, strideV);
  }
  return self;
}

- (instancetype)initWithFrameBuffer:
    (webrtc::scoped_refptr<webrtc::I420BufferInterface>)i420Buffer {
  self = [super init];
  if (self) {
    _i420Buffer = i420Buffer;
  }
  return self;
}

- (int)width {
  return _i420Buffer->width();
}

- (int)height {
  return _i420Buffer->height();
}

- (int)strideY {
  return _i420Buffer->StrideY();
}

- (int)strideU {
  return _i420Buffer->StrideU();
}

- (int)strideV {
  return _i420Buffer->StrideV();
}

- (int)chromaWidth {
  return _i420Buffer->ChromaWidth();
}

- (int)chromaHeight {
  return _i420Buffer->ChromaHeight();
}

- (const uint8_t *)dataY {
  return _i420Buffer->DataY();
}

- (const uint8_t *)dataU {
  return _i420Buffer->DataU();
}

- (const uint8_t *)dataV {
  return _i420Buffer->DataV();
}

- (id<RTC_OBJC_TYPE(RTCVideoFrameBuffer)>)cropAndScaleWith:(int)offsetX
                                                   offsetY:(int)offsetY
                                                 cropWidth:(int)cropWidth
                                                cropHeight:(int)cropHeight
                                                scaleWidth:(int)scaleWidth
                                               scaleHeight:(int)scaleHeight {
  webrtc::scoped_refptr<webrtc::VideoFrameBuffer> scaled_buffer =
      _i420Buffer->CropAndScale(
          offsetX, offsetY, cropWidth, cropHeight, scaleWidth, scaleHeight);
  RTC_DCHECK_EQ(scaled_buffer->type(), webrtc::VideoFrameBuffer::Type::kI420);
  // Calling ToI420() doesn't do any conversions.
  webrtc::scoped_refptr<webrtc::I420BufferInterface> buffer =
      scaled_buffer->ToI420();
  RTC_OBJC_TYPE(RTCI420Buffer) *result =
      [[RTC_OBJC_TYPE(RTCI420Buffer) alloc] initWithFrameBuffer:buffer];
  return result;
}

- (id<RTC_OBJC_TYPE(RTCI420Buffer)>)toI420 {
  return self;
}

#pragma mark - Private

- (webrtc::scoped_refptr<webrtc::I420BufferInterface>)nativeI420Buffer {
  return _i420Buffer;
}

#pragma mark - Debugging

#if !defined(NDEBUG) && defined(WEBRTC_IOS)
- (id)debugQuickLookObject {
  UIGraphicsBeginImageContext(
      CGSizeMake(_i420Buffer->width(), _i420Buffer->height()));
  CGContextRef c = UIGraphicsGetCurrentContext();
  uint8_t *ctxData = (uint8_t *)CGBitmapContextGetData(c);

  libyuv::I420ToARGB(_i420Buffer->DataY(),
                     _i420Buffer->StrideY(),
                     _i420Buffer->DataU(),
                     _i420Buffer->StrideU(),
                     _i420Buffer->DataV(),
                     _i420Buffer->StrideV(),
                     ctxData,
                     CGBitmapContextGetBytesPerRow(c),
                     CGBitmapContextGetWidth(c),
                     CGBitmapContextGetHeight(c));

  UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();

  return image;
}
#endif

@end
