// 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 "fpdfsdk/include/fpdfxfa/fpdfxfa_page.h"

#include "core/fpdfapi/fpdf_parser/include/cpdf_document.h"
#include "core/include/fpdfapi/fpdf_page.h"
#include "fpdfsdk/include/fpdfxfa/fpdfxfa_doc.h"
#include "fpdfsdk/include/fpdfxfa/fpdfxfa_util.h"
#include "fpdfsdk/include/fsdk_define.h"
#include "fpdfsdk/include/fsdk_mgr.h"

CPDFXFA_Page::CPDFXFA_Page(CPDFXFA_Document* pDoc, int page_index)
    : m_pPDFPage(NULL),
      m_pXFAPageView(NULL),
      m_iPageIndex(page_index),
      m_pDocument(pDoc),
      m_iRef(1) {}

CPDFXFA_Page::~CPDFXFA_Page() {
  if (m_pPDFPage)
    delete m_pPDFPage;
  m_pPDFPage = NULL;
  m_pXFAPageView = NULL;
}

void CPDFXFA_Page::Release() {
  m_iRef--;
  if (m_iRef > 0)
    return;

  if (m_pDocument)
    m_pDocument->RemovePage(this);

  delete this;
}

FX_BOOL CPDFXFA_Page::LoadPDFPage() {
  if (!m_pDocument)
    return FALSE;
  CPDF_Document* pPDFDoc = m_pDocument->GetPDFDoc();
  if (pPDFDoc) {
    CPDF_Dictionary* pDict = pPDFDoc->GetPage(m_iPageIndex);
    if (pDict == NULL)
      return FALSE;
    if (m_pPDFPage) {
      if (m_pPDFPage->m_pFormDict == pDict)
        return TRUE;

      delete m_pPDFPage;
      m_pPDFPage = NULL;
    }

    m_pPDFPage = new CPDF_Page;
    m_pPDFPage->Load(pPDFDoc, pDict);
    m_pPDFPage->ParseContent(nullptr);
    return TRUE;
  }

  return FALSE;
}

FX_BOOL CPDFXFA_Page::LoadXFAPageView() {
  if (!m_pDocument)
    return FALSE;
  IXFA_Doc* pXFADoc = m_pDocument->GetXFADoc();
  if (!pXFADoc)
    return FALSE;

  IXFA_DocView* pXFADocView = m_pDocument->GetXFADocView();
  if (!pXFADocView)
    return FALSE;

  IXFA_PageView* pPageView = pXFADocView->GetPageView(m_iPageIndex);
  if (!pPageView)
    return FALSE;

  if (m_pXFAPageView == pPageView)
    return TRUE;

  m_pXFAPageView = pPageView;
  (void)m_pXFAPageView->LoadPageView(nullptr);
  return TRUE;
}

FX_BOOL CPDFXFA_Page::LoadPage() {
  if (!m_pDocument || m_iPageIndex < 0)
    return FALSE;

  int iDocType = m_pDocument->GetDocType();
  switch (iDocType) {
    case DOCTYPE_PDF:
    case DOCTYPE_STATIC_XFA: {
      return LoadPDFPage();
    }
    case DOCTYPE_DYNAMIC_XFA: {
      return LoadXFAPageView();
    }
    default:
      return FALSE;
  }

  return FALSE;
}

FX_BOOL CPDFXFA_Page::LoadPDFPage(CPDF_Dictionary* pageDict) {
  if (!m_pDocument || m_iPageIndex < 0 || !pageDict)
    return FALSE;

  if (m_pPDFPage)
    delete m_pPDFPage;

  m_pPDFPage = new CPDF_Page();
  m_pPDFPage->Load(m_pDocument->GetPDFDoc(), pageDict);
  m_pPDFPage->ParseContent(nullptr);

  return TRUE;
}

FX_FLOAT CPDFXFA_Page::GetPageWidth() {
  if (!m_pPDFPage && !m_pXFAPageView)
    return 0.0f;

  int nDocType = m_pDocument->GetDocType();
  switch (nDocType) {
    case DOCTYPE_DYNAMIC_XFA: {
      if (m_pXFAPageView) {
        CFX_RectF rect;
        m_pXFAPageView->GetPageViewRect(rect);
        return rect.width;
      }
    } break;
    case DOCTYPE_STATIC_XFA:
    case DOCTYPE_PDF: {
      if (m_pPDFPage)
        return m_pPDFPage->GetPageWidth();
    } break;
    default:
      return 0.0f;
  }

  return 0.0f;
}

FX_FLOAT CPDFXFA_Page::GetPageHeight() {
  if (!m_pPDFPage && !m_pXFAPageView)
    return 0.0f;

  int nDocType = m_pDocument->GetDocType();
  switch (nDocType) {
    case DOCTYPE_PDF:
    case DOCTYPE_STATIC_XFA: {
      if (m_pPDFPage)
        return m_pPDFPage->GetPageHeight();
    } break;
    case DOCTYPE_DYNAMIC_XFA: {
      if (m_pXFAPageView) {
        CFX_RectF rect;
        m_pXFAPageView->GetPageViewRect(rect);
        return rect.height;
      }
    } break;
    default:
      return 0.0f;
  }

  return 0.0f;
}

void CPDFXFA_Page::DeviceToPage(int start_x,
                                int start_y,
                                int size_x,
                                int size_y,
                                int rotate,
                                int device_x,
                                int device_y,
                                double* page_x,
                                double* page_y) {
  if (!m_pPDFPage && !m_pXFAPageView)
    return;

  CFX_Matrix page2device;
  CFX_Matrix device2page;
  FX_FLOAT page_x_f, page_y_f;

  GetDisplayMatrix(page2device, start_x, start_y, size_x, size_y, rotate);

  device2page.SetReverse(page2device);
  device2page.Transform((FX_FLOAT)(device_x), (FX_FLOAT)(device_y), page_x_f,
                        page_y_f);

  *page_x = (page_x_f);
  *page_y = (page_y_f);
}

void CPDFXFA_Page::PageToDevice(int start_x,
                                int start_y,
                                int size_x,
                                int size_y,
                                int rotate,
                                double page_x,
                                double page_y,
                                int* device_x,
                                int* device_y) {
  if (!m_pPDFPage && !m_pXFAPageView)
    return;

  CFX_Matrix page2device;
  FX_FLOAT device_x_f, device_y_f;

  GetDisplayMatrix(page2device, start_x, start_y, size_x, size_y, rotate);

  page2device.Transform(((FX_FLOAT)page_x), ((FX_FLOAT)page_y), device_x_f,
                        device_y_f);

  *device_x = FXSYS_round(device_x_f);
  *device_y = FXSYS_round(device_y_f);
}

void CPDFXFA_Page::GetDisplayMatrix(CFX_Matrix& matrix,
                                    int xPos,
                                    int yPos,
                                    int xSize,
                                    int ySize,
                                    int iRotate) const {
  if (!m_pPDFPage && !m_pXFAPageView)
    return;

  int nDocType = m_pDocument->GetDocType();
  switch (nDocType) {
    case DOCTYPE_DYNAMIC_XFA: {
      if (m_pXFAPageView) {
        CFX_Rect rect;
        rect.Set(xPos, yPos, xSize, ySize);
        m_pXFAPageView->GetDisplayMatrix(matrix, rect, iRotate);
      }
    } break;
    case DOCTYPE_PDF:
    case DOCTYPE_STATIC_XFA: {
      if (m_pPDFPage) {
        m_pPDFPage->GetDisplayMatrix(matrix, xPos, yPos, xSize, ySize, iRotate);
      }
    } break;
    default:
      return;
  }
}
