#include "stdafx.h"
#include "VBox.h"

namespace ui
{

VLayout::VLayout()
{

}

CSize VLayout::ArrangeChild(const std::vector<Control*>& items, UiRect rc)
{
	// Determine the minimum size
	CSize szAvailable(rc.right - rc.left, rc.bottom - rc.top);

	int nAdjustables = 0;
	int cyFixed = 0;
	int nEstimateNum = 0;
	for( auto it = items.begin(); it != items.end(); it++ ) {
		auto pControl = *it;
		if( !pControl->IsVisible() ) continue;
		if( pControl->IsFloat() ) continue;
		CSize sz = pControl->EstimateSize(szAvailable);
		if( sz.cy == DUI_LENGTH_STRETCH ) {
			nAdjustables++;
			cyFixed += pControl->GetMargin().top + pControl->GetMargin().bottom;
		}
		else {
			if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight();
			if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight();
			cyFixed += sz.cy + pControl->GetMargin().top + pControl->GetMargin().bottom;
		}
			
		nEstimateNum++;
	}
	cyFixed += (nEstimateNum - 1) * m_iChildMargin;

	// Place elements
	int cyNeeded = 0;
	int cyExpand = 0;
	if( nAdjustables > 0 ) cyExpand = MAX(0, (szAvailable.cy - cyFixed) / nAdjustables);
	int deviation = szAvailable.cy - cyFixed - cyExpand * nAdjustables;
	// Position the elements
	CSize szRemaining = szAvailable;
	int iPosLeft = rc.left;
	int iPosRight = rc.right;
	int iPosY = rc.top;
	int iAdjustable = 0;
	int max_width = 0;

	for( auto it = items.begin(); it != items.end(); it++ ) {
		auto pControl = *it;
		if( !pControl->IsVisible() ) continue;
		if( pControl->IsFloat() ) {
			SetFloatPos(pControl, rc);
			continue;
		}

		UiRect rcMargin = pControl->GetMargin();
		szRemaining.cy -= rcMargin.top;
		CSize sz = pControl->EstimateSize(szRemaining);
		if( sz.cy == DUI_LENGTH_STRETCH ) {
			iAdjustable++;
			sz.cy = cyExpand;
			if (deviation > 0) {
				sz.cy += 1;
				deviation--;
			}
		}
		if (sz.cy < pControl->GetMinHeight()) sz.cy = pControl->GetMinHeight();
		if (sz.cy > pControl->GetMaxHeight()) sz.cy = pControl->GetMaxHeight();
			
		if( sz.cx == DUI_LENGTH_STRETCH ) sz.cx = szAvailable.cx - rcMargin.left - rcMargin.right;
		if( sz.cx < 0 ) sz.cx = 0;
		if( sz.cx < pControl->GetMinWidth() ) sz.cx = pControl->GetMinWidth();
		if( pControl->GetMaxWidth() >= 0 && sz.cx > pControl->GetMaxWidth() ) sz.cx = pControl->GetMaxWidth();

		int childLeft = 0;
		int childRight = 0;
		HorAlignType horAlignType = pControl->GetHorAlignType();
		if (horAlignType == kHorAlignLeft) {
			childLeft = iPosLeft + rcMargin.left;
			childRight = childLeft + sz.cx;
		}
		else if (horAlignType == kHorAlignRight) {
			childRight = iPosRight - rcMargin.right;
			childLeft = childRight - sz.cx;
		}
		else if (horAlignType == kHorAlignCenter) {
			childLeft = iPosLeft + (iPosRight - iPosLeft + rcMargin.left - rcMargin.right - sz.cx) / 2;
			childRight = childLeft + sz.cx;
		}

		UiRect rcCtrl(childLeft, iPosY + rcMargin.top, childRight, iPosY + rcMargin.top + sz.cy);
		max_width = MAX(max_width, rcCtrl.GetWidth());
		pControl->SetPos(rcCtrl);

		iPosY += sz.cy + m_iChildMargin + rcMargin.top + rcMargin.bottom;
		cyNeeded += sz.cy + rcMargin.top + rcMargin.bottom;
		szRemaining.cy -= sz.cy + m_iChildMargin + rcMargin.bottom;
	}
	cyNeeded += (nEstimateNum - 1) * m_iChildMargin;

	CSize size(max_width, cyNeeded);
	return size;
}

CSize VLayout::AjustSizeByChild(const std::vector<Control*>& items, CSize szAvailable)
{
	CSize totalSize;
	CSize itemSize;
	Control* pChildControl = NULL;
	int count = (int)items.size();
	int estimateChildCount = 0;
	for(int it = 0; it < count; it++) 
	{
		pChildControl = (Control*)items[it];
		if (!pChildControl->IsVisible() || pChildControl->IsFloat()) {
			continue;
		}

		estimateChildCount++;
		itemSize = pChildControl->EstimateSize(szAvailable);
		if( itemSize.cx < pChildControl->GetMinWidth() ) itemSize.cx = pChildControl->GetMinWidth();
		if( pChildControl->GetMaxWidth() >= 0 && itemSize.cx > pChildControl->GetMaxWidth() ) itemSize.cx = pChildControl->GetMaxWidth();
		if( itemSize.cy < pChildControl->GetMinHeight() ) itemSize.cy = pChildControl->GetMinHeight();
		if( itemSize.cy > pChildControl->GetMaxHeight() ) itemSize.cy = pChildControl->GetMaxHeight();
		totalSize.cx = MAX(itemSize.cx + pChildControl->GetMargin().left + pChildControl->GetMargin().right, totalSize.cx);
		totalSize.cy += itemSize.cy + pChildControl->GetMargin().top + pChildControl->GetMargin().bottom;
	}

	if (estimateChildCount - 1 > 0) {
		totalSize.cy += (estimateChildCount - 1) * m_iChildMargin;
	}
	totalSize.cx += m_rcPadding.left + m_rcPadding.right;
	totalSize.cy += m_rcPadding.top + m_rcPadding.bottom;
	return totalSize;
}

VBox::VBox() : Box(new VLayout())
{

}

}
