// Copyright 2016 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#include "core/fpdfdoc/cpdf_iconfit.h"

#include <algorithm>
#include <utility>

#include "core/fpdfapi/parser/cpdf_array.h"
#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fxcrt/fx_string.h"

namespace {

constexpr float kDefaultPosition = 0.5f;

}  // namespace

CPDF_IconFit::CPDF_IconFit(RetainPtr<const CPDF_Dictionary> dict)
    : dict_(std::move(dict)) {}

CPDF_IconFit::CPDF_IconFit(const CPDF_IconFit& that) = default;

CPDF_IconFit::~CPDF_IconFit() = default;

CPDF_IconFit::ScaleMethod CPDF_IconFit::GetScaleMethod() const {
  if (!dict_) {
    return ScaleMethod::kAlways;
  }

  ByteString csSW = dict_->GetByteStringFor("SW", "A");
  if (csSW == "B") {
    return ScaleMethod::kBigger;
  }
  if (csSW == "S") {
    return ScaleMethod::kSmaller;
  }
  if (csSW == "N") {
    return ScaleMethod::kNever;
  }
  return ScaleMethod::kAlways;
}

bool CPDF_IconFit::IsProportionalScale() const {
  return !dict_ || dict_->GetByteStringFor("S", "P") != "A";
}

CFX_PointF CPDF_IconFit::GetIconBottomLeftPosition() const {
  float fLeft = kDefaultPosition;
  float fBottom = kDefaultPosition;
  if (!dict_) {
    return {fLeft, fBottom};
  }

  RetainPtr<const CPDF_Array> pA = dict_->GetArrayFor("A");
  if (!pA) {
    return {fLeft, fBottom};
  }

  size_t dwCount = pA->size();
  if (dwCount > 0) {
    fLeft = pA->GetFloatAt(0);
  }
  if (dwCount > 1) {
    fBottom = pA->GetFloatAt(1);
  }
  return {fLeft, fBottom};
}

bool CPDF_IconFit::GetFittingBounds() const {
  return dict_ && dict_->GetBooleanFor("FB", false);
}

CFX_PointF CPDF_IconFit::GetIconPosition() const {
  if (!dict_) {
    return CFX_PointF();
  }

  RetainPtr<const CPDF_Array> pA = dict_->GetArrayFor("A");
  if (!pA) {
    return CFX_PointF();
  }

  size_t dwCount = pA->size();
  return {dwCount > 0 ? pA->GetFloatAt(0) : 0.0f,
          dwCount > 1 ? pA->GetFloatAt(1) : 0.0f};
}

CFX_VectorF CPDF_IconFit::GetScale(const CFX_SizeF& image_size,
                                   const CFX_FloatRect& rcPlate) const {
  float fHScale = 1.0f;
  float fVScale = 1.0f;
  const float fPlateWidth = rcPlate.Width();
  const float fPlateHeight = rcPlate.Height();
  const float fImageWidth = image_size.width;
  const float fImageHeight = image_size.height;
  switch (GetScaleMethod()) {
    case CPDF_IconFit::ScaleMethod::kAlways:
      fHScale = fPlateWidth / std::max(fImageWidth, 1.0f);
      fVScale = fPlateHeight / std::max(fImageHeight, 1.0f);
      break;
    case CPDF_IconFit::ScaleMethod::kBigger:
      if (fPlateWidth < fImageWidth) {
        fHScale = fPlateWidth / std::max(fImageWidth, 1.0f);
      }
      if (fPlateHeight < fImageHeight) {
        fVScale = fPlateHeight / std::max(fImageHeight, 1.0f);
      }
      break;
    case CPDF_IconFit::ScaleMethod::kSmaller:
      if (fPlateWidth > fImageWidth) {
        fHScale = fPlateWidth / std::max(fImageWidth, 1.0f);
      }
      if (fPlateHeight > fImageHeight) {
        fVScale = fPlateHeight / std::max(fImageHeight, 1.0f);
      }
      break;
    case CPDF_IconFit::ScaleMethod::kNever:
      break;
  }

  if (IsProportionalScale()) {
    float min_scale = std::min(fHScale, fVScale);
    fHScale = min_scale;
    fVScale = min_scale;
  }
  return {fHScale, fVScale};
}

CFX_VectorF CPDF_IconFit::GetImageOffset(const CFX_SizeF& image_size,
                                         const CFX_VectorF& scale,
                                         const CFX_FloatRect& rcPlate) const {
  const CFX_PointF icon_position = GetIconPosition();
  const float fImageFactWidth = image_size.width * scale.x;
  const float fImageFactHeight = image_size.height * scale.y;
  return {(rcPlate.Width() - fImageFactWidth) * icon_position.x,
          (rcPlate.Height() - fImageFactHeight) * icon_position.y};
}
