// Copyright 2014 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 "xfa/fwl/cfwl_form.h"

#include <utility>

#include "third_party/base/ptr_util.h"
#include "xfa/fde/tto/fde_textout.h"
#include "xfa/fwl/cfwl_app.h"
#include "xfa/fwl/cfwl_event.h"
#include "xfa/fwl/cfwl_formproxy.h"
#include "xfa/fwl/cfwl_messagemouse.h"
#include "xfa/fwl/cfwl_notedriver.h"
#include "xfa/fwl/cfwl_noteloop.h"
#include "xfa/fwl/cfwl_themebackground.h"
#include "xfa/fwl/cfwl_themepart.h"
#include "xfa/fwl/cfwl_themetext.h"
#include "xfa/fwl/cfwl_widgetmgr.h"
#include "xfa/fwl/ifwl_themeprovider.h"
#include "xfa/fwl/theme/cfwl_widgettp.h"

CFWL_Form::CFWL_Form(const CFWL_App* app,
                     std::unique_ptr<CFWL_WidgetProperties> properties,
                     CFWL_Widget* pOuter)
    : CFWL_Widget(app, std::move(properties), pOuter),
      m_pSubFocus(nullptr),
      m_fCXBorder(0),
      m_fCYBorder(0) {
  m_rtRelative.Reset();
  m_rtRestore.Reset();

  RegisterForm();
  RegisterEventTarget(nullptr);
}

CFWL_Form::~CFWL_Form() {
  UnregisterEventTarget();
  UnRegisterForm();
}

FWL_Type CFWL_Form::GetClassID() const {
  return FWL_Type::Form;
}

bool CFWL_Form::IsInstance(const CFX_WideStringC& wsClass) const {
  if (wsClass == CFX_WideStringC(FWL_CLASS_Form))
    return true;
  return CFWL_Widget::IsInstance(wsClass);
}

CFX_RectF CFWL_Form::GetClientRect() {
  CFX_RectF rect = m_pProperties->m_rtWidget;
  rect.Offset(-rect.left, -rect.top);
  return rect;
}

void CFWL_Form::Update() {
  if (m_iLock > 0)
    return;
  if (!m_pProperties->m_pThemeProvider)
    m_pProperties->m_pThemeProvider = GetAvailableTheme();

  Layout();
}

FWL_WidgetHit CFWL_Form::HitTest(const CFX_PointF& point) {
  GetAvailableTheme();

  CFX_RectF rtCap(m_fCYBorder, m_fCXBorder, -2 * m_fCYBorder, 0 - m_fCXBorder);
  return rtCap.Contains(point) ? FWL_WidgetHit::Titlebar
                               : FWL_WidgetHit::Client;
}

void CFWL_Form::DrawWidget(CFX_Graphics* pGraphics, const CFX_Matrix* pMatrix) {
  if (!pGraphics)
    return;
  if (!m_pProperties->m_pThemeProvider)
    return;

  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
  DrawBackground(pGraphics, pTheme);

#ifdef FWL_UseMacSystemBorder
  return;
#endif
  CFWL_ThemeBackground param;
  param.m_pWidget = this;
  param.m_dwStates = CFWL_PartState_Normal;
  param.m_pGraphics = pGraphics;
  param.m_rtPart = m_rtRelative;
  if (pMatrix)
    param.m_matrix.Concat(*pMatrix);
  if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_Border) {
    param.m_iPart = CFWL_Part::Border;
    pTheme->DrawBackground(&param);
  }
}

CFWL_Widget* CFWL_Form::DoModal() {
  const CFWL_App* pApp = GetOwnerApp();
  if (!pApp)
    return nullptr;

  CFWL_NoteDriver* pDriver = pApp->GetNoteDriver();
  if (!pDriver)
    return nullptr;

  m_pNoteLoop = pdfium::MakeUnique<CFWL_NoteLoop>();
  m_pNoteLoop->SetMainForm(this);

  pDriver->PushNoteLoop(m_pNoteLoop.get());
  RemoveStates(FWL_WGTSTATE_Invisible);
  pDriver->Run();

#if _FX_OS_ != _FX_MACOSX_
  pDriver->PopNoteLoop();
#endif

  m_pNoteLoop.reset();
  return nullptr;
}

void CFWL_Form::EndDoModal() {
  if (!m_pNoteLoop)
    return;

#if (_FX_OS_ == _FX_MACOSX_)
  m_pNoteLoop->EndModalLoop();
  const CFWL_App* pApp = GetOwnerApp();
  if (!pApp)
    return;

  CFWL_NoteDriver* pDriver =
      static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
  if (!pDriver)
    return;

  pDriver->PopNoteLoop();
  SetStates(FWL_WGTSTATE_Invisible);
#else
  SetStates(FWL_WGTSTATE_Invisible);
  m_pNoteLoop->EndModalLoop();
#endif
}

void CFWL_Form::DrawBackground(CFX_Graphics* pGraphics,
                               IFWL_ThemeProvider* pTheme) {
  CFWL_ThemeBackground param;
  param.m_pWidget = this;
  param.m_iPart = CFWL_Part::Background;
  param.m_pGraphics = pGraphics;
  param.m_rtPart = m_rtRelative;
  param.m_rtPart.Deflate(m_fCYBorder, m_fCXBorder, m_fCYBorder, m_fCXBorder);
  pTheme->DrawBackground(&param);
}

CFX_RectF CFWL_Form::GetEdgeRect() {
  CFX_RectF rtEdge = m_rtRelative;
  if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_Border) {
    FX_FLOAT fCX = GetBorderSize(true);
    FX_FLOAT fCY = GetBorderSize(false);
    rtEdge.Deflate(fCX, fCY, fCX, fCY);
  }
  return rtEdge;
}

void CFWL_Form::SetWorkAreaRect() {
  m_rtRestore = m_pProperties->m_rtWidget;
  CFWL_WidgetMgr* pWidgetMgr = GetOwnerApp()->GetWidgetMgr();
  if (!pWidgetMgr)
    return;
  RepaintRect(m_rtRelative);
}

void CFWL_Form::Layout() {
  m_rtRelative = GetRelativeRect();

#ifndef FWL_UseMacSystemBorder
  IFWL_ThemeProvider* theme = GetAvailableTheme();
  m_fCXBorder = theme ? theme->GetCXBorderSize() : 0.0f;
  m_fCYBorder = theme ? theme->GetCYBorderSize() : 0.0f;
#endif
}

void CFWL_Form::RegisterForm() {
  const CFWL_App* pApp = GetOwnerApp();
  if (!pApp)
    return;

  CFWL_NoteDriver* pDriver =
      static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
  if (!pDriver)
    return;

  pDriver->RegisterForm(this);
}

void CFWL_Form::UnRegisterForm() {
  const CFWL_App* pApp = GetOwnerApp();
  if (!pApp)
    return;

  CFWL_NoteDriver* pDriver =
      static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
  if (!pDriver)
    return;

  pDriver->UnRegisterForm(this);
}

void CFWL_Form::OnProcessMessage(CFWL_Message* pMessage) {
#ifndef FWL_UseMacSystemBorder
  if (!pMessage)
    return;

  switch (pMessage->GetType()) {
    case CFWL_Message::Type::Mouse: {
      CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
      switch (pMsg->m_dwCmd) {
        case FWL_MouseCommand::LeftButtonDown:
          OnLButtonDown(pMsg);
          break;
        case FWL_MouseCommand::LeftButtonUp:
          OnLButtonUp(pMsg);
          break;
        default:
          break;
      }
      break;
    }
    default:
      break;
  }
#endif  // FWL_UseMacSystemBorder
}

void CFWL_Form::OnDrawWidget(CFX_Graphics* pGraphics,
                             const CFX_Matrix* pMatrix) {
  DrawWidget(pGraphics, pMatrix);
}

void CFWL_Form::OnLButtonDown(CFWL_MessageMouse* pMsg) {
  SetGrab(true);
}

void CFWL_Form::OnLButtonUp(CFWL_MessageMouse* pMsg) {
  SetGrab(false);
}
