// Copyright 2016 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/cfx_systemhandler.h"

#include "fpdfsdk/formfiller/cffl_formfiller.h"
#include "fpdfsdk/include/fsdk_mgr.h"

namespace {

int CharSet2CP(int charset) {
  if (charset == 128)
    return 932;
  if (charset == 134)
    return 936;
  if (charset == 129)
    return 949;
  if (charset == 136)
    return 950;
  return 0;
}

}  // namespace

void CFX_SystemHandler::SetCursor(int32_t nCursorType) {
  m_pEnv->FFI_SetCursor(nCursorType);
}

void CFX_SystemHandler::InvalidateRect(FX_HWND hWnd, FX_RECT rect) {
  CPDFSDK_Annot* pSDKAnnot = (CPDFSDK_Annot*)hWnd;
  CPDFSDK_PageView* pPageView = pSDKAnnot->GetPageView();
  UnderlyingPageType* pPage = pSDKAnnot->GetUnderlyingPage();
  if (!pPage || !pPageView)
    return;

  CFX_Matrix page2device;
  pPageView->GetCurrentMatrix(page2device);
  CFX_Matrix device2page;
  device2page.SetReverse(page2device);
  FX_FLOAT left, top, right, bottom;
  device2page.Transform((FX_FLOAT)rect.left, (FX_FLOAT)rect.top, left, top);
  device2page.Transform((FX_FLOAT)rect.right, (FX_FLOAT)rect.bottom, right,
                        bottom);
  CFX_FloatRect rcPDF(left, bottom, right, top);
  rcPDF.Normalize();

  m_pEnv->FFI_Invalidate(pPage, rcPDF.left, rcPDF.top, rcPDF.right,
                         rcPDF.bottom);
}

void CFX_SystemHandler::OutputSelectedRect(void* pFormFiller,
                                           CFX_FloatRect& rect) {
  CFFL_FormFiller* pFFL = (CFFL_FormFiller*)pFormFiller;
  if (!pFFL)
    return;

  CFX_FloatPoint leftbottom = CFX_FloatPoint(rect.left, rect.bottom);
  CFX_FloatPoint righttop = CFX_FloatPoint(rect.right, rect.top);
  CFX_FloatPoint ptA = pFFL->PWLtoFFL(leftbottom);
  CFX_FloatPoint ptB = pFFL->PWLtoFFL(righttop);
  CPDFSDK_Annot* pAnnot = pFFL->GetSDKAnnot();
  UnderlyingPageType* pPage = pAnnot->GetUnderlyingPage();
  ASSERT(pPage);

  m_pEnv->FFI_OutputSelectedRect(pPage, ptA.x, ptB.y, ptB.x, ptA.y);
}

bool CFX_SystemHandler::IsSelectionImplemented() const {
  if (m_pEnv) {
    FPDF_FORMFILLINFO* pInfo = m_pEnv->GetFormFillInfo();
    if (pInfo && pInfo->FFI_OutputSelectedRect)
      return true;
  }
  return false;
}

bool CFX_SystemHandler::FindNativeTrueTypeFont(int32_t nCharset,
                                               CFX_ByteString sFontFaceName) {
  CFX_FontMgr* pFontMgr = CFX_GEModule::Get()->GetFontMgr();
  if (!pFontMgr)
    return false;

  CFX_FontMapper* pFontMapper = pFontMgr->GetBuiltinMapper();
  if (!pFontMapper)
    return false;

  if (pFontMapper->m_InstalledTTFonts.empty())
    pFontMapper->LoadInstalledFonts();

  for (const auto& font : pFontMapper->m_InstalledTTFonts) {
    if (font.Compare(sFontFaceName.AsStringC()))
      return true;
  }

  return false;
}

CPDF_Font* CFX_SystemHandler::AddNativeTrueTypeFontToPDF(
    CPDF_Document* pDoc,
    CFX_ByteString sFontFaceName,
    uint8_t nCharset) {
  if (!pDoc)
    return nullptr;

  CFX_Font* pFXFont = new CFX_Font();
  pFXFont->LoadSubst(sFontFaceName, TRUE, 0, 0, 0, CharSet2CP(nCharset), FALSE);
  CPDF_Font* pFont = pDoc->AddFont(pFXFont, nCharset, FALSE);
  delete pFXFont;
  return pFont;
}

int32_t CFX_SystemHandler::SetTimer(int32_t uElapse,
                                    TimerCallback lpTimerFunc) {
  return m_pEnv->FFI_SetTimer(uElapse, lpTimerFunc);
}

void CFX_SystemHandler::KillTimer(int32_t nID) {
  m_pEnv->FFI_KillTimer(nID);
}

FX_SYSTEMTIME CFX_SystemHandler::GetLocalTime() {
  return m_pEnv->FFI_GetLocalTime();
}

bool CFX_SystemHandler::IsSHIFTKeyDown(uint32_t nFlag) const {
  return !!m_pEnv->FFI_IsSHIFTKeyDown(nFlag);
}

bool CFX_SystemHandler::IsCTRLKeyDown(uint32_t nFlag) const {
  return !!m_pEnv->FFI_IsCTRLKeyDown(nFlag);
}

bool CFX_SystemHandler::IsALTKeyDown(uint32_t nFlag) const {
  return !!m_pEnv->FFI_IsALTKeyDown(nFlag);
}