// Copyright 2021 PDFium Authors. All rights reserved.
// 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 "fpdfsdk/pwl/cpwl_sbbutton.h"

#include <utility>
#include <vector>

#include "core/fxge/cfx_renderdevice.h"
#include "third_party/base/stl_util.h"

CPWL_SBButton::CPWL_SBButton(
    const CreateParams& cp,
    std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData,
    Type eButtonType)
    : CPWL_Wnd(cp, std::move(pAttachedData)), m_eSBButtonType(eButtonType) {
  GetCreationParams()->eCursorType = FXCT_ARROW;
}

CPWL_SBButton::~CPWL_SBButton() = default;

void CPWL_SBButton::DrawThisAppearance(CFX_RenderDevice* pDevice,
                                       const CFX_Matrix& mtUser2Device) {
  if (!IsVisible())
    return;

  CFX_FloatRect rectWnd = GetWindowRect();
  if (rectWnd.IsEmpty())
    return;

  CFX_PointF ptCenter = GetCenterPoint();
  int32_t nTransparency = GetTransparency();

  // draw border
  pDevice->DrawStrokeRect(mtUser2Device, rectWnd,
                          ArgbEncode(nTransparency, 100, 100, 100), 0.0f);
  pDevice->DrawStrokeRect(mtUser2Device, rectWnd.GetDeflated(0.5f, 0.5f),
                          ArgbEncode(nTransparency, 255, 255, 255), 1.0f);

  if (m_eSBButtonType != Type::kPosButton) {
    // draw background
    pDevice->DrawShadow(mtUser2Device, true, false,
                        rectWnd.GetDeflated(1.0f, 1.0f), nTransparency, 80,
                        220);
    // draw arrow
    if (rectWnd.top - rectWnd.bottom > 6.0f) {
      float fX = rectWnd.left + 1.5f;
      float fY = rectWnd.bottom;
      std::vector<CFX_PointF> pts;
      static constexpr float kOffsetsX[] = {2.5f, 2.5f, 4.5f, 6.5f,
                                            6.5f, 4.5f, 2.5f};
      static constexpr float kOffsetsY[] = {5.0f, 6.0f, 4.0f, 6.0f,
                                            5.0f, 3.0f, 5.0f};
      static constexpr float kOffsetsMinY[] = {4.0f, 3.0f, 5.0f, 3.0f,
                                               4.0f, 6.0f, 4.0f};
      static_assert(pdfium::size(kOffsetsX) == pdfium::size(kOffsetsY),
                    "Wrong offset count");
      static_assert(pdfium::size(kOffsetsX) == pdfium::size(kOffsetsMinY),
                    "Wrong offset count");
      const float* pOffsetsY =
          m_eSBButtonType == Type::kMinButton ? kOffsetsMinY : kOffsetsY;
      for (size_t i = 0; i < pdfium::size(kOffsetsX); ++i)
        pts.push_back(CFX_PointF(fX + kOffsetsX[i], fY + pOffsetsY[i]));
      pDevice->DrawFillArea(mtUser2Device, pts,
                            ArgbEncode(nTransparency, 255, 255, 255));
    }
    return;
  }

  // draw shadow effect
  CFX_PointF ptTop = CFX_PointF(rectWnd.left, rectWnd.top - 1.0f);
  CFX_PointF ptBottom = CFX_PointF(rectWnd.left, rectWnd.bottom + 1.0f);

  ptTop.x += 1.5f;
  ptBottom.x += 1.5f;

  const FX_COLORREF refs[] = {ArgbEncode(nTransparency, 210, 210, 210),
                              ArgbEncode(nTransparency, 220, 220, 220),
                              ArgbEncode(nTransparency, 240, 240, 240),
                              ArgbEncode(nTransparency, 240, 240, 240),
                              ArgbEncode(nTransparency, 210, 210, 210),
                              ArgbEncode(nTransparency, 180, 180, 180),
                              ArgbEncode(nTransparency, 150, 150, 150),
                              ArgbEncode(nTransparency, 150, 150, 150),
                              ArgbEncode(nTransparency, 180, 180, 180),
                              ArgbEncode(nTransparency, 210, 210, 210)};
  for (FX_COLORREF ref : refs) {
    pDevice->DrawStrokeLine(&mtUser2Device, ptTop, ptBottom, ref, 1.0f);

    ptTop.x += 1.0f;
    ptBottom.x += 1.0f;
  }

  // draw friction
  if (rectWnd.Height() <= 8.0f)
    return;

  FX_COLORREF crStroke = ArgbEncode(nTransparency, 120, 120, 120);
  float nFrictionWidth = 5.0f;
  float nFrictionHeight = 5.5f;
  CFX_PointF ptLeft = CFX_PointF(ptCenter.x - nFrictionWidth / 2.0f,
                                 ptCenter.y - nFrictionHeight / 2.0f + 0.5f);
  CFX_PointF ptRight = CFX_PointF(ptCenter.x + nFrictionWidth / 2.0f,
                                  ptCenter.y - nFrictionHeight / 2.0f + 0.5f);

  for (size_t i = 0; i < 3; ++i) {
    pDevice->DrawStrokeLine(&mtUser2Device, ptLeft, ptRight, crStroke, 1.0f);
    ptLeft.y += 2.0f;
    ptRight.y += 2.0f;
  }
}

bool CPWL_SBButton::OnLButtonDown(uint32_t nFlag, const CFX_PointF& point) {
  CPWL_Wnd::OnLButtonDown(nFlag, point);

  if (CPWL_Wnd* pParent = GetParentWindow())
    pParent->NotifyLButtonDown(this, point);

  m_bMouseDown = true;
  SetCapture();

  return true;
}

bool CPWL_SBButton::OnLButtonUp(uint32_t nFlag, const CFX_PointF& point) {
  CPWL_Wnd::OnLButtonUp(nFlag, point);

  if (CPWL_Wnd* pParent = GetParentWindow())
    pParent->NotifyLButtonUp(this, point);

  m_bMouseDown = false;
  ReleaseCapture();

  return true;
}

bool CPWL_SBButton::OnMouseMove(uint32_t nFlag, const CFX_PointF& point) {
  CPWL_Wnd::OnMouseMove(nFlag, point);

  if (CPWL_Wnd* pParent = GetParentWindow())
    pParent->NotifyMouseMove(this, point);

  return true;
}
