// XTPChartSeriesLabel.cpp
//
// This file is a part of the XTREME TOOLKIT PRO MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <math.h>

#include "Common/XTPPropExchange.h"

#include "Types/XTPChartTypes.h"

#include "XTPChartDefines.h"
#include "XTPChartElement.h"
#include <Chart/XTPChartLegendItem.h>
#include "XTPChartElementView.h"

#include "XTPChartSeriesLabel.h"
#include <Chart/XTPChartSeriesPointView.h>
#include "XTPChartSeriesView.h"
#include "XTPChartSeriesPoint.h"
#include "XTPChartSeries.h"
#include "XTPChartSeriesStyle.h"


#include <Common/XTPMathUtils.h>
#include "Utils/XTPChartNumberFormat.h"
#include "Common/Base/Types/XTPPoint3.h"
#include "Appearance/XTPChartBorder.h"
#include "Appearance/XTPChartFillStyle.h"
#include "Appearance/XTPChartAppearance.h"

#include "Drawing/XTPChartDeviceCommand.h"
#include "Drawing/XTPChartLineDeviceCommand.h"


//////////////////////////////////////////////////////////////////////////
// CXTPChartSeriesLabel

IMPLEMENT_SERIAL(CXTPChartSeriesLabel, CXTPChartTextElement, VERSIONABLE_SCHEMA | _XTP_SCHEMA_CURRENT)

CXTPChartSeriesLabel::CXTPChartSeriesLabel()
{
	m_pFont = CXTPChartFont::GetTahoma8();
	m_clrTextColor = CXTPChartColor::Empty;
	m_clrBackColor = CXTPChartColor::Empty;
	m_clrLineColor = CXTPChartColor::Empty;

	m_pBorder = new CXTPChartBorder(this);

	m_pFillStyle = new CXTPChartFillStyle(this);
	m_pFillStyle->SetFillMode(xtpChartFillSolid);

	m_bAntialiasing = FALSE;
	m_bVisible = TRUE;
	m_bShowLines = TRUE;
	m_nLineLength = 10;

	m_nTransparency = 255;

	m_pFormat = new CXTPChartNumberFormat(this);

}

CXTPChartSeriesLabel::~CXTPChartSeriesLabel()
{
	SAFE_RELEASE(m_pFont);
	SAFE_RELEASE(m_pBorder);
	SAFE_RELEASE(m_pFillStyle);
	SAFE_RELEASE(m_pFormat);
}

void CXTPChartSeriesLabel::SetFont(CXTPChartFont* pFont)
{
	SAFE_RELEASE(m_pFont);
	m_pFont = pFont;
	OnChartChanged();
}

void CXTPChartSeriesLabel::SetFormat(LPCTSTR lpszFormat)
{
	m_pFormat->SetPattern(lpszFormat);
}

CXTPChartString CXTPChartSeriesLabel::GetPointLabel(CXTPChartSeriesPoint* pPoint, int nValueIndex) const
{
	if (!pPoint->GetLabelText().IsEmpty())
		return pPoint->GetLabelText();

	double dValue = pPoint->GetValue(nValueIndex == - 1 ? pPoint->GetSeries()->GetStyle()->GetSeriesPointValueIndex() : nValueIndex);


	return m_pFormat->FormatPoint(pPoint, dValue);
}

CXTPChartColor CXTPChartSeriesLabel::GetActualBackColor() const
{
	CXTPChartColor clrBackColor = m_clrBackColor;

	if (clrBackColor.IsEmpty())
	{
		CXTPChartSeriesStyle* pStyle = DYNAMIC_DOWNCAST(CXTPChartSeriesStyle, GetOwner());
		ASSERT(pStyle);

		clrBackColor = pStyle->GetStyleAppearance()->GetLabelAppearance()->BackgroundColor;
	}

	if (m_nTransparency != 255)
	{
		return CXTPChartColor((BYTE)m_nTransparency, clrBackColor.GetR(), clrBackColor.GetG(), clrBackColor.GetB());
	}

	return clrBackColor;
}

CXTPChartColor CXTPChartSeriesLabel::GetActualConnectorColor() const
{
	CXTPChartColor clrLineColor = GetLineColor();
#if 0
	if (clrLineColor.IsEmpty())
	{
		CXTPChartSeriesStyle* pStyle = (CXTPChartSeriesStyle*)GetOwner();

		clrLineColor = pStyle->GetStyleAppearance()->GetLabelAppearance()->ConnectorColor;

		if (clrLineColor.IsEmpty())
			clrLineColor = m_pPointView->GetColor().GetDarkColor();
	}

	int nTransparency = GetTransparency();

	if (nTransparency != 255)
	{
		return CXTPChartColor((BYTE)nTransparency, clrLineColor.GetR(), clrLineColor.GetG(), clrLineColor.GetB());
	}
#endif
	return clrLineColor;
}


void CXTPChartSeriesLabel::DoPropExchange(CXTPPropExchange* pPX)
{
	PX_Bool(pPX, _T("Visible"), m_bVisible, TRUE);
	PX_Bool(pPX, _T("Antialiasing"), m_bAntialiasing, FALSE);
	PX_Bool(pPX, _T("ShowLines"), m_bShowLines, TRUE);
	PX_Int(pPX, _T("LineLength"), m_nLineLength, 10);

	CXTPPropExchangeSection secFormat(pPX->GetSection(_T("Format")));
	m_pFormat->DoPropExchange(&secFormat);

	PX_Font(pPX, _T("Font"), m_pFont);

	PX_Color(pPX, _T("BackColor"), m_clrBackColor);
	PX_Color(pPX, _T("TextColor"), m_clrTextColor);
	PX_Color(pPX, _T("LineColor"), m_clrLineColor);

	if (pPX->GetSchema() >= _XTP_SCHEMA_1500)
		PX_Int(pPX, _T("Transparency"), m_nTransparency, 255);

	CXTPPropExchangeSection secFillStyle(pPX->GetSection(_T("FillStyle")));
	m_pFillStyle->DoPropExchange(&secFillStyle);

	CXTPPropExchangeSection secBorder(pPX->GetSection(_T("Border")));
	m_pBorder->DoPropExchange(&secBorder);

}


//////////////////////////////////////////////////////////////////////////
// CXTPChartSeriesLabelConnectorPainterBase

CXTPChartSeriesLabelConnectorPainterBase::CXTPChartSeriesLabelConnectorPainterBase(CXTPPoint2f startPoint, CXTPChartPointF finishPoint, CXTPChartRectF bounds)
{
	m_startPoint = startPoint;
	m_finishPoint = finishPoint;
	m_bounds = bounds;
}

enum XTPChartAngleOrientation
{
	xtpChartAngleQuadrant1,
	xtpChartAngleQuadrant2,
	xtpChartAngleQuadrant3,
	xtpChartAngleQuadrant4,
	xtpChartAngle0,
	xtpChartAngle90,
	xtpChartAngle180,
	xtpChartAngle270,
};

static XTPChartAngleOrientation GetAngleOrientation(double angle, double deadAngle)
{
	angle = CXTPMathUtils::NormalizeRadian(angle);
	angle = angle < 0 ? 2 * CXTPMathUtils::m_dPI + angle : angle;
	XTPChartAngleOrientation disposition;
	if (CXTPMathUtils::Compare(angle, 0, deadAngle) == 0)
		disposition = xtpChartAngle0;
	else if (CXTPMathUtils::Compare(angle, CXTPMathUtils::m_dPI / 2.0, deadAngle) == 0)
		disposition = xtpChartAngle90;
	else if (CXTPMathUtils::Compare(angle, CXTPMathUtils::m_dPI, deadAngle) == 0)
		disposition = xtpChartAngle180;
	else if (CXTPMathUtils::Compare(angle, 3 * CXTPMathUtils::m_dPI / 2.0, deadAngle) == 0)
		disposition = xtpChartAngle270;
	else if (angle > 0 && angle < CXTPMathUtils::m_dPI / 2.0)
		disposition = xtpChartAngleQuadrant1;
	else if (angle > CXTPMathUtils::m_dPI / 2.0 && angle < CXTPMathUtils::m_dPI)
		disposition = xtpChartAngleQuadrant2;
	else if (angle > CXTPMathUtils::m_dPI && angle < 3 * CXTPMathUtils::m_dPI / 2.0)
		disposition = xtpChartAngleQuadrant3;
	else
		disposition = xtpChartAngleQuadrant4;
	return disposition;
}


CXTPChartRectF CXTPChartSeriesLabelConnectorPainterBase::CalcBorderBoundsForTangentDrawing(const CXTPPoint3d& point, double angle, const CXTPChartSizeF& textSize, int borderThickness, CXTPChartRectF& innerBounds)
{
	const double DeadAngle = CXTPMathUtils::m_dPI / 180.0 * 10;

	CXTPChartRectF bounds(0, 0, (float)floor(textSize.Width + 2 * borderThickness), (float)floor(textSize.Height + 2 * borderThickness));
	CXTPPoint3d topLeft = point;

	XTPChartAngleOrientation disposition = GetAngleOrientation(angle, DeadAngle);
	switch (disposition)
	{
				case xtpChartAngle0:
					topLeft.Offset(0, -bounds.Height / 2.0);
					break;
				case xtpChartAngle90:
					topLeft.Offset(-bounds.Width / 2.0, -bounds.Height);
					break;
				case xtpChartAngle180:
					topLeft.Offset(-bounds.Width, -bounds.Height / 2.0);
					break;
				case xtpChartAngle270:
					topLeft.Offset(-bounds.Width / 2.0, 0);
					break;
				case xtpChartAngleQuadrant1:
					topLeft.Offset(0, -bounds.Height);
					break;
				case xtpChartAngleQuadrant2:
					topLeft.Offset(-bounds.Width, -bounds.Height);
					break;
				case xtpChartAngleQuadrant3:
					topLeft.Offset(-bounds.Width, 0);
					break;
				case xtpChartAngleQuadrant4:
					break;
	}
	bounds.Offset(topLeft);
	bounds.Round();

	innerBounds = bounds;
	innerBounds.Inflate((float)-borderThickness, (float)-borderThickness);
	return bounds;

}

//////////////////////////////////////////////////////////////////////////
// CXTPChartSeriesLabelLineConnectorPainter

CXTPChartSeriesLabelLineConnectorPainter::CXTPChartSeriesLabelLineConnectorPainter(CXTPChartPointF startPoint, CXTPChartPointF finishPoint, double angle, CXTPChartRectF bounds)
	: CXTPChartSeriesLabelConnectorPainterBase(startPoint, finishPoint, bounds)
{
	m_angle = angle;
}

CXTPChartDeviceCommand* CXTPChartSeriesLabelLineConnectorPainter::CreateDeviceCommand(CXTPChartDeviceContext* pDC, CXTPChartSeriesLabel* pLabel, const CXTPChartColor& color)
{
	UNREFERENCED_PARAMETER(pDC);
	UNREFERENCED_PARAMETER(pLabel);

	CXTPChartDeviceCommand* pContaier = new CXTPChartPolygonAntialiasingDeviceCommand();
	pContaier->AddChildCommand(new CXTPChartSolidLineDeviceCommand(m_startPoint, m_finishPoint, color, 1));

	return pContaier;
}