// 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/pdfwindow/PDFWindow.h"
#include "../../include/pdfwindow/PWL_Wnd.h"
#include "../../include/pdfwindow/PWL_ListCtrl.h"

/* ---------------------------- CPWL_ListCtrl ---------------------------- */

CPWL_ListCtrl::CPWL_ListCtrl() : 
	m_rcContent(0,0,0,0),
	m_ptScroll(0,0), 
	m_fItemSpace(0.0f),
	m_fTopSpace(0.0f),
	m_fBottomSpace(0.0f)
{
}

CPWL_ListCtrl::~CPWL_ListCtrl()
{
}

void CPWL_ListCtrl::SetScrollPos(const CPDF_Point& point)
{
	m_ptScroll = point;

	if (m_ptScroll.x < m_rcContent.left)
		m_ptScroll.x = m_rcContent.left;

	if (m_ptScroll.x > m_rcContent.right)
		m_ptScroll.x = m_rcContent.right;

	if (m_ptScroll.y > m_rcContent.top)
		m_ptScroll.y = m_rcContent.top;

	if (m_ptScroll.y < m_rcContent.bottom)
		m_ptScroll.y = m_rcContent.bottom;	
}

CPDF_Point CPWL_ListCtrl::GetScrollPos() const
{
	return m_ptScroll;
}

CPDF_Rect CPWL_ListCtrl::GetScrollArea() const
{
	return m_rcContent;
}

void CPWL_ListCtrl::ResetFace()
{
	ResetAll(FALSE, 0);
}

void CPWL_ListCtrl::ResetContent(FX_INT32 nStart)
{
	if (nStart < 0)
		nStart = 0;
	if (nStart >= 0 && nStart < m_aChildren.GetSize())
		ResetAll(TRUE, nStart);
}

FX_FLOAT CPWL_ListCtrl::GetContentsHeight(FX_FLOAT fLimitWidth)
{
	FX_FLOAT fRet = m_fTopSpace;

	FX_FLOAT fBorderWidth = (FX_FLOAT)this->GetBorderWidth();

	if (fLimitWidth > fBorderWidth* 2)
	{
		for (FX_INT32 i=0,sz=m_aChildren.GetSize(); i<sz; i++)
		{
			if (CPWL_Wnd* pChild = m_aChildren.GetAt(i))
			{
				FX_FLOAT fLeft = pChild->GetItemLeftMargin();
				FX_FLOAT fRight = pChild->GetItemRightMargin();

				fRet += pChild->GetItemHeight(fLimitWidth - fBorderWidth* 2 - fLeft - fRight);
				fRet += m_fItemSpace;
			}
		}

		fRet -= m_fItemSpace;
	}

	fRet += m_fBottomSpace;

	return fRet;
}

void CPWL_ListCtrl::ResetAll(FX_BOOL bMove, FX_INT32 nStart)
{
	CPDF_Rect rcClient = GetClientRect();

	FX_FLOAT fWidth = rcClient.Width();

	FX_FLOAT fy = 0.0f - m_fTopSpace;

	if (nStart-1 >= 0 && nStart-1 < m_aChildren.GetSize())
		if (CPWL_Wnd* pChild = m_aChildren.GetAt(nStart-1))
			fy = pChild->GetWindowRect().bottom - m_fItemSpace;

	for (FX_INT32 i=nStart,sz=m_aChildren.GetSize(); i<sz; i++)
	{
		if (CPWL_Wnd* pChild = m_aChildren.GetAt(i))
		{
			FX_FLOAT fLeft = pChild->GetItemLeftMargin();
			FX_FLOAT fRight = pChild->GetItemRightMargin();

			pChild->SetChildMatrix(
				CPDF_Matrix(1,0,0,1, 
				rcClient.left - m_ptScroll.x, 
				rcClient.top - m_ptScroll.y)
				);

			if (bMove)
			{
				FX_FLOAT fItemHeight = pChild->GetItemHeight(fWidth - fLeft - fRight);
				pChild->Move(CPDF_Rect(fLeft, fy-fItemHeight, fWidth - fRight, fy), TRUE, FALSE);
				fy -= fItemHeight;
				fy -= m_fItemSpace;
			}
		}
	}

	fy += m_fItemSpace;

	fy -= m_fBottomSpace;

	if (bMove)
	{
		m_rcContent.left = 0;
		m_rcContent.top = 0;
		m_rcContent.right = fWidth;
		m_rcContent.bottom = fy;
	}
}

void CPWL_ListCtrl::SetItemSpace(FX_FLOAT fSpace)
{
	m_fItemSpace = fSpace;
}

void CPWL_ListCtrl::SetTopSpace(FX_FLOAT fSpace)
{
	m_fTopSpace = fSpace;
}

void CPWL_ListCtrl::SetBottomSpace(FX_FLOAT fSpace)
{
	m_fBottomSpace = fSpace;
}

void CPWL_ListCtrl::RePosChildWnd()
{
	ResetFace();
}

void CPWL_ListCtrl::DrawChildAppearance(CFX_RenderDevice* pDevice, CPDF_Matrix* pUser2Device)
{
	pDevice->SaveState();
	CPDF_Rect rcClient = GetClientRect();
	CPDF_Rect rcTemp = rcClient;
	pUser2Device->TransformRect(rcTemp);
	FX_RECT rcClip((FX_INT32)rcTemp.left,
		(FX_INT32)rcTemp.bottom,
		(FX_INT32)rcTemp.right,
		(FX_INT32)rcTemp.top);

	pDevice->SetClip_Rect(&rcClip);

	for (FX_INT32 i=0,sz=m_aChildren.GetSize(); i<sz; i++)
	{
		if (CPWL_Wnd * pChild = m_aChildren.GetAt(i))
		{
			CPDF_Rect rcChild = pChild->ChildToParent(pChild->GetWindowRect());
			if (!(rcChild.top < rcClient.bottom || rcChild.bottom > rcClient.top))
			{
				CPDF_Matrix mt = pChild->GetChildMatrix();
				if (mt.IsIdentity())
				{
					pChild->DrawAppearance(pDevice,pUser2Device);
				}
				else
				{
					mt.Concat(*pUser2Device);
					pChild->DrawAppearance(pDevice,&mt);
				}
			}
		}
	}
	
	pDevice->RestoreState();
}

FX_INT32 CPWL_ListCtrl::GetItemIndex(CPWL_Wnd* pItem)
{
	for (FX_INT32 i=0, sz=m_aChildren.GetSize(); i<sz; i++)
	{
		if (pItem == m_aChildren.GetAt(i))
			return i;
	}

	return -1;
}

CPDF_Point CPWL_ListCtrl::InToOut(const CPDF_Point& point) const
{
	CPDF_Rect rcClient = GetClientRect();

	return CPDF_Point(point.x + rcClient.left - m_ptScroll.x, 
		point.y + rcClient.top - m_ptScroll.y);
}

CPDF_Point CPWL_ListCtrl::OutToIn(const CPDF_Point& point) const
{
	CPDF_Rect rcClient = GetClientRect();

	return CPDF_Point(point.x - rcClient.left + m_ptScroll.x, 
		point.y - rcClient.top + m_ptScroll.y);
}

CPDF_Rect CPWL_ListCtrl::InToOut(const CPDF_Rect& rect) const
{
	CPDF_Rect rcClient = GetClientRect();

	return CPDF_Rect(rect.left + rcClient.left - m_ptScroll.x,
		rect.bottom + rcClient.top - m_ptScroll.y,
		rect.right + rcClient.left - m_ptScroll.x,
		rect.top + rcClient.top - m_ptScroll.y);
}

CPDF_Rect CPWL_ListCtrl::OutToIn(const CPDF_Rect& rect) const
{
	CPDF_Rect rcClient = GetClientRect();

	return CPDF_Rect(rect.left - rcClient.left + m_ptScroll.x,
		rect.bottom - rcClient.top + m_ptScroll.y,
		rect.right - rcClient.left + m_ptScroll.x,
		rect.top - rcClient.top + m_ptScroll.y);
}