// 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 "../../include/fsdk_define.h"
#include "../../include/fsdk_mgr.h"
#include "../../include/fpdfxfa/fpdfxfa_util.h"
#include "../../include/fpdfxfa/fpdfxfa_doc.h"
#include "../../include/fpdfxfa/fpdfxfa_page.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 = FX_NEW CPDF_Page;
		m_pPDFPage->Load(pPDFDoc, pDict);
		m_pPDFPage->ParseContent();
		return TRUE;
	}

	return FALSE;
}

FX_BOOL CPDFXFA_Page::LoadXFAPageView()
{
	if (!m_pDocument)
		return FALSE;
	XFA_HDOC pXFADoc = m_pDocument->GetXFADoc();
	if (pXFADoc)
	{
		IXFA_DocView* pXFADocView = m_pDocument->GetXFADocView();
		if (!pXFADocView) 
			return FALSE;

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

		if (m_pXFAPageView)
			if (m_pXFAPageView == pPageView)
				return TRUE;

		m_pXFAPageView = pPageView;
		int iStatus = m_pXFAPageView->LoadPageView(NULL);

		return TRUE;
	}

	return FALSE;
}

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

	int iDocType = m_pDocument->GetDocType();
	CPDF_Document* pPDFDoc = m_pDocument->GetPDFDoc();
	XFA_HDOC pXFADoc = m_pDocument->GetXFADoc();

	switch (iDocType)
	{
	case DOCTYPE_PDF:
	case DOCTYPE_STATIC_XFA:
		{
			return LoadPDFPage();
		}
	case DOCTYPE_DYNIMIC_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 = FX_NEW CPDF_Page();
	m_pPDFPage->Load(m_pDocument->GetPDFDoc(), pageDict);
	m_pPDFPage->ParseContent();

	return TRUE;
}

FX_FLOAT CPDFXFA_Page::GetPageWidth()
{
	ASSERT(m_pDocument != NULL);

	if (!m_pPDFPage && !m_pXFAPageView)
		return 0.0f;

	int nDocType = m_pDocument->GetDocType();
	switch (nDocType)
	{
	case DOCTYPE_DYNIMIC_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()
{
	ASSERT(m_pDocument != NULL);

	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_DYNIMIC_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)
{
	ASSERT(m_pDocument != NULL);

	if (!m_pPDFPage && !m_pXFAPageView)
		return;

	CPDF_Matrix page2device;
	CPDF_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;

	CPDF_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_AffineMatrix& matrix, int xPos, int yPos, 
	int xSize, int ySize, int iRotate) const
{
	ASSERT(m_pDocument != NULL);

	if (!m_pPDFPage && !m_pXFAPageView)
		return;

	int nDocType = m_pDocument->GetDocType();
	switch (nDocType)
	{
	case DOCTYPE_DYNIMIC_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;
	}

}