// XTPChartNumberFormat.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 "Common/XTPPropExchange.h"
#include "Common/XTPVC80Helpers.h"

#include "../Types/XTPChartTypes.h"
#include "../XTPChartDefines.h"
#include "../XTPChartElement.h"
#include <Chart/XTPChartLegendItem.h>
#include <Common/XTPMathUtils.h>

#include "../XTPChartSeriesPoint.h"
#include "../XTPChartSeries.h"

#include "XTPChartNumberFormat.h"

#ifndef LOCALE_SYEARMONTH
#define LOCALE_SYEARMONTH             0x00001006   // year month format string
#endif



//////////////////////////////////////////////////////////////////////////
// CXTPChartNumberFormat

CXTPChartNumberFormat::CXTPChartNumberFormat(CXTPChartElement* pOwner)
{
	m_pOwner = pOwner;

	m_strPattern = _T("");
	m_nCategory = xtpChartGeneral;
	m_nDecimalPlaces = -1;
	m_bUseThousandSeparator = TRUE;
	m_nLocale = LOCALE_USER_DEFAULT;



	memset(&m_fmtNumber, 0, sizeof(m_fmtNumber));
	m_fmtNumber.lpDecimalSep = new TCHAR[10];
	m_fmtNumber.lpThousandSep = new TCHAR[10];

	CreateNumberFormat();

	memset(&m_fmtCurrency, 0, sizeof(m_fmtCurrency));
	m_fmtCurrency.lpDecimalSep = new TCHAR[10];
	m_fmtCurrency.lpThousandSep = new TCHAR[10];
	m_fmtCurrency.lpCurrencySymbol = new TCHAR[10];

	CreateCurrencyFormat();

	m_nDateTimeCategory = xtpChartDateTimeShortDate;
	CreateDateTimeFormat();


#ifdef _XTP_ACTIVEX
	EnableAutomation();
	EnableTypeLib();
#endif

}

CXTPChartNumberFormat::~CXTPChartNumberFormat()
{
	delete[] m_fmtNumber.lpDecimalSep;
	delete[] m_fmtNumber.lpThousandSep;

	delete[] m_fmtCurrency.lpDecimalSep;
	delete[] m_fmtCurrency.lpThousandSep;
	delete[] m_fmtCurrency.lpCurrencySymbol;
}

void CXTPChartNumberFormat::DoPropExchange(CXTPPropExchange* pPX)
{
	PX_String(pPX, _T("Pattern"), m_strPattern,  _T(""));
	PX_Enum(pPX, _T("Category"), m_nCategory, xtpChartGeneral);
	PX_Int(pPX, _T("DecimalPlaces"), m_nDecimalPlaces, -1);
	PX_Bool(pPX, _T("UseThousandSeparator"), m_bUseThousandSeparator, TRUE);
	PX_DWord(pPX, _T("Locale"), m_nLocale, LOCALE_USER_DEFAULT);
	PX_String(pPX, _T("CurrencySymbol"), m_strCurrencySymbol,  _T(""));

	PX_Enum(pPX, _T("DateTimeCategory"), m_nDateTimeCategory, xtpChartDateTimeShortDate);

	PX_String(pPX, _T("DateTimeFormat"), m_strDateTimeFormat,  _T(""));

	if (pPX->IsLoading())
	{
		CreateNumberFormat();
		CreateCurrencyFormat();
		CreateDateTimeFormat();
	}
}


CString CXTPChartNumberFormat::GetLocaleString(LCTYPE LCType, int nMaxLength)
{
	CString strResult;

	::GetLocaleInfo(m_nLocale, LCType , strResult.GetBufferSetLength(nMaxLength), nMaxLength);
	strResult.ReleaseBuffer();

	return strResult;
}

int CXTPChartNumberFormat::GetLocaleLong(LCTYPE LCType) const
{
	TCHAR szResult[5];

	int nResult = ::GetLocaleInfo(m_nLocale, LCType , szResult, 4);
	ASSERT(nResult >= 2 && nResult <= 3);

	return _ttoi(szResult);
}

void CXTPChartNumberFormat::CreateCurrencyFormat()
{
	m_fmtCurrency.NumDigits = m_nDecimalPlaces == -1 ? GetLocaleLong(LOCALE_IDIGITS) : m_nDecimalPlaces;
	m_fmtCurrency.LeadingZero = GetLocaleLong(LOCALE_ILZERO);
	m_fmtCurrency.Grouping = 3;
	m_fmtCurrency.NegativeOrder = GetLocaleLong(LOCALE_INEGCURR);


	m_fmtCurrency.PositiveOrder = GetLocaleLong(LOCALE_ICURRENCY);

	GetLocaleInfo(m_nLocale, LOCALE_SDECIMAL, m_fmtCurrency.lpDecimalSep, 10);

	if (m_bUseThousandSeparator)
		GetLocaleInfo(m_nLocale, LOCALE_STHOUSAND, m_fmtCurrency.lpThousandSep, 10);
	else
		m_fmtCurrency.lpThousandSep[0] = 0;

	if (m_strCurrencySymbol.IsEmpty())
		GetLocaleInfo(m_nLocale, LOCALE_SCURRENCY, m_fmtCurrency.lpCurrencySymbol, 10);
	else
		STRNCPY_S(m_fmtCurrency.lpCurrencySymbol, 10, m_strCurrencySymbol, 9);
}

void CXTPChartNumberFormat::CreateNumberFormat()
{
	m_fmtNumber.NumDigits = m_nDecimalPlaces == -1 ? GetLocaleLong(LOCALE_IDIGITS) : m_nDecimalPlaces;
	m_fmtNumber.LeadingZero = GetLocaleLong(LOCALE_ILZERO);;
	m_fmtNumber.Grouping = 3;
	m_fmtNumber.NegativeOrder = GetLocaleLong(LOCALE_INEGNUMBER);

	GetLocaleInfo(m_nLocale, LOCALE_SDECIMAL, m_fmtNumber.lpDecimalSep, 10);

	if (m_bUseThousandSeparator)
		GetLocaleInfo(m_nLocale, LOCALE_STHOUSAND, m_fmtNumber.lpThousandSep, 10);
	else
		m_fmtNumber.lpThousandSep[0] = 0;

}

CString CXTPChartNumberFormat::DoubleToString(double dValue) const
{
	CString strResult;

	switch (m_nCategory)
	{
	case xtpChartGeneral:
		{
			strResult.Format(_T("%g"), dValue);

			if (m_fmtNumber.lpDecimalSep[0] == _T(','))
				strResult.Replace(_T('.'), _T(','));

			return strResult;
		}

	case xtpChartNumber:
		{
			CString strTemp;
			strTemp.Format(_T("%lf"), dValue);
			strTemp.Replace(_T(','), _T('.'));

			GetNumberFormat(m_nLocale, 0, (LPCTSTR)strTemp, &m_fmtNumber, strResult.GetBuffer(40), 40);
			strResult.ReleaseBuffer();
			return strResult;
		}

	case xtpChartCurrency:
		{
			CString strTemp;
			strTemp.Format(_T("%lf"), dValue);
			strTemp.Replace(_T(','), _T('.'));

			GetCurrencyFormat(m_nLocale, 0, (LPCTSTR)strTemp, &m_fmtCurrency, strResult.GetBuffer(40), 40);
			strResult.ReleaseBuffer();
			return strResult;
		}

	case xtpChartPercentage:
		{
			CString strTemp;
			strTemp.Format(_T("%lf"), dValue * 100);
			strTemp.Replace(_T(','), _T('.'));

			GetNumberFormat(m_nLocale, 0, (LPCTSTR)strTemp, &m_fmtNumber, strResult.GetBuffer(40), 40);
			strResult.ReleaseBuffer();

			strResult += _T('%');
			return strResult;
		}

	case xtpChartScientific:
		{
			if (m_nDecimalPlaces == -1)
				strResult.Format(_T("%e"), dValue);
			else
			{
				CString strFormat;
				strFormat.Format(_T("%%.%de"), m_nDecimalPlaces);

				strResult.Format(strFormat, dValue);

			}
			return strResult;
		}
	}

	return strResult;
}

CString CXTPChartNumberFormat::FormatNumber(double dValue) const
{
	if (CXTPMathUtils::Compare(dValue, 0) == 0)
		dValue = 0;

	CString strResult;

	if (!m_strPattern.IsEmpty())
	{
		strResult.Format(m_strPattern, dValue);

		int nIndex = strResult.Find(_T("{V}"));
		if (nIndex != -1)
		{
			CString str = DoubleToString(dValue);

			strResult.Replace(_T("{V}"), str);
		}
	}
	else
	{
		strResult = DoubleToString(dValue);
	}

	return strResult;
}

CString CXTPChartNumberFormat::FormatString(LPCTSTR lpsz) const
{
	if (m_strPattern.IsEmpty())
		return lpsz;


	CXTPChartString strResult;
	strResult.Format(m_strPattern, lpsz);

	int nIndex = strResult.Find(_T("{V}"));
	if (nIndex != -1)
	{
		strResult.Replace(_T("{V}"), lpsz);
	}

	return strResult;
}

CString CXTPChartNumberFormat::FormatPoint(CXTPChartSeriesPoint* pSeriesPoint, double dValue) const
{
	if (CXTPMathUtils::Compare(dValue, 0) == 0)
		dValue = 0;

	CString strResult;

	if (!m_strPattern.IsEmpty())
	{
		strResult.Format(m_strPattern, dValue);

		int nIndex = strResult.Find(_T("{V}"));
		if (nIndex != -1)
		{
			CString str = DoubleToString(dValue);

			strResult.Replace(_T("{V}"), str);
		}

		nIndex = strResult.Find(_T("{A}"));
		if (nIndex != -1)
		{
			CString strArgument = pSeriesPoint->GetArgument();

			if (pSeriesPoint->GetSeries()->GetArgumentScaleType() == xtpChartScaleDateTime)
			{
				COleDateTime dt((DATE)pSeriesPoint->GetArgumentValue());
				strArgument = FormatDate(dt);
			}

			strResult.Replace(_T("{A}"), strArgument);
		}

		strResult.Replace(_T("{S}"), pSeriesPoint->GetSeries()->GetName());
	}
	else
	{
		strResult = DoubleToString(dValue);
	}

	return strResult;
}

void CXTPChartNumberFormat::CreateDateTimeFormat()
{
	m_strActiveDateTimeFormat = m_strDateTimeFormat;

	if (m_nDateTimeCategory == xtpChartDateTimeLongDate)
	{
		m_strActiveDateTimeFormat = GetLocaleString(LOCALE_SLONGDATE, 255);
	}
	else if (m_nDateTimeCategory == xtpChartDateTimeShortDate)
	{
		m_strActiveDateTimeFormat = GetLocaleString(LOCALE_SSHORTDATE, 255);
	}
	else if (m_nDateTimeCategory == xtpChartDateTimeMonthAndDay)
	{
		BOOL bDayMonth = GetLocaleLong(LOCALE_ILDATE) == 1;

		if (bDayMonth)
			m_strActiveDateTimeFormat = _T("d MMMM ");
		else
			m_strActiveDateTimeFormat = _T("MMMM d");
	}
	else if (m_nDateTimeCategory == xtpChartDateTimeMonthAndYear)
	{
		m_strActiveDateTimeFormat = GetLocaleString(LOCALE_SYEARMONTH, 255);
	}
	else if (m_nDateTimeCategory == xtpChartDateTimeLongTime || m_nDateTimeCategory == xtpChartDateTimeShortTime)
	{
		////////////////////////////////////////////////////////////////////////////
		//  LOCALE_STIME    // time separator
		//
		//  LOCALE_ITLZERO  //leading zeros in time field
		//      0 No leading zeros for hours.
		//      1 Leading zeros for hours.
		//
		//  LOCALE_ITIME    // time format specifier
		//      0 AM / PM 12-hour format.
		//      1 24-hour format.
		//
		//  LOCALE_ITIMEMARKPOSN    // time marker position
		//      0 Use as suffix.
		//      1 Use as prefix.
		//
		//  LOCALE_S1159    // AM designator
		//  LOCALE_S2359    // PM designator
		////////////////////////////////////////////////////////////////////////////

		CString strTmp;

		CString strTimeSeparator = GetLocaleString(LOCALE_STIME, 16);

		BOOL b24HFormat = GetLocaleLong(LOCALE_ITIME) == 1;

		BOOL bHLZero = GetLocaleLong(LOCALE_ITLZERO) == 1;

		BOOL bAMPMPrefix = GetLocaleLong(LOCALE_ITIMEMARKPOSN) == 1;

		//---------------------------------------------------------------------------
		CString strTimeFormat;
		strTimeFormat += strTimeSeparator;
		strTimeFormat += _T("mm");

		if (b24HFormat)
		{
			strTmp = bHLZero ? _T("HH") : _T("H");
			strTimeFormat = strTmp + strTimeFormat;
		}
		else //12 AM/PM Format
		{
			strTmp = bHLZero ? _T("hh") : _T("h");
			strTimeFormat = strTmp + strTimeFormat;

		}

		if (m_nDateTimeCategory == xtpChartDateTimeLongTime)
			strTimeFormat = strTimeFormat + strTimeSeparator + _T("ss");

		if (!b24HFormat)
		{
			if (bAMPMPrefix)
			{
				strTimeFormat = _T("tt ") + strTimeFormat;
			}
			else
			{
				strTimeFormat = strTimeFormat + _T(" tt");
			}
		}

		m_strActiveDateTimeFormat = strTimeFormat;
	}
}

CString CXTPChartNumberFormat::FormatDate(COleDateTime& dt) const
{
	CString strResult;

	if (m_nDateTimeCategory == xtpChartDateTimeGeneral)
	{
		return dt.Format((DWORD)0, m_nLocale);
	}
	else if (m_nDateTimeCategory != xtpChartDateTimeCustom)
	{
		SYSTEMTIME st;
		if (dt.GetAsSystemTime(st))
		{
			if (m_nDateTimeCategory == xtpChartDateTimeLongTime || m_nDateTimeCategory == xtpChartDateTimeShortTime)
				::GetTimeFormat(m_nLocale, 0, &st, m_strActiveDateTimeFormat, strResult.GetBufferSetLength(255), 255);
			else
				::GetDateFormat(m_nLocale, 0, &st, m_strActiveDateTimeFormat, strResult.GetBufferSetLength(255), 255);
			strResult.ReleaseBuffer();
		}
	}
	else
	{
		if (m_strActiveDateTimeFormat.IsEmpty())
		{
			return dt.Format(VAR_DATEVALUEONLY);
		}
		else
		{
			if (m_strActiveDateTimeFormat.Find(_T("%")) >= 0)
				return dt.Format(m_strActiveDateTimeFormat);

			SYSTEMTIME st;
			if (dt.GetAsSystemTime(st))
			{
				CString strPattern;

				::GetTimeFormat(m_nLocale, 0, &st, m_strActiveDateTimeFormat, strPattern.GetBufferSetLength(255), 255);
				strPattern.ReleaseBuffer();

				::GetDateFormat(m_nLocale, 0, &st, strPattern, strResult.GetBufferSetLength(255), 255);
				strResult.ReleaseBuffer();
			}
		}
	}

	return strResult;
}

#ifdef _XTP_ACTIVEX

BEGIN_DISPATCH_MAP(CXTPChartNumberFormat, CCmdTarget)
	DISP_PROPERTY_EX_ID(CXTPChartNumberFormat, "Pattern", DISPID_VALUE, OleGetPattern, OleSetPattern, VT_BSTR)
	DISP_PROPERTY_EX_ID(CXTPChartNumberFormat, "Category", 2, GetCategory, SetCategory, VT_I4)
	DISP_PROPERTY_EX_ID(CXTPChartNumberFormat, "DecimalPlaces", 3, GetDecimalPlaces, SetDecimalPlaces, VT_I4)
	DISP_PROPERTY_EX_ID(CXTPChartNumberFormat, "UseThousandSeparator", 4, GetUseThousandSeparator, SetUseThousandSeparator, VT_BOOL)
	DISP_PROPERTY_EX_ID(CXTPChartNumberFormat, "Locale", 5, GetLocale, SetLocale, VT_I4)
	DISP_PROPERTY_EX_ID(CXTPChartNumberFormat, "CurrencySymbol", 6, OleGetCurrencySymbol, OleSetCurrencySymbol, VT_BSTR)
	DISP_PROPERTY_EX_ID(CXTPChartNumberFormat, "DateTimeCategory", 7, GetDateTimeCategory, SetDateTimeCategory, VT_I4)
	DISP_PROPERTY_EX_ID(CXTPChartNumberFormat, "DateTimeFormat", 8, OleGetDateDateTimeFormat, SetDateTimeFormat, VT_BSTR)
END_DISPATCH_MAP()


// {A90BCC77-27BF-4cb1-9ABF-4558D9835223}
static const GUID IID_IChartNumberFormat =
{ 0xa90bcc77, 0x27bf, 0x4cb1, { 0x9a, 0xbf, 0x45, 0x58, 0xd9, 0x83, 0x52, 0x23 } };

BEGIN_INTERFACE_MAP(CXTPChartNumberFormat, CCmdTarget)
	INTERFACE_PART(CXTPChartNumberFormat, IID_IChartNumberFormat, Dispatch)
END_INTERFACE_MAP()

IMPLEMENT_OLETYPELIB_EX(CXTPChartNumberFormat, IID_IChartNumberFormat)


BSTR CXTPChartNumberFormat::OleGetPattern()
{
	return m_strPattern.AllocSysString();
}

void CXTPChartNumberFormat::OleSetPattern(LPCTSTR lpszValue)
{
	SetPattern(lpszValue);
}


BSTR CXTPChartNumberFormat::OleGetCurrencySymbol()
{
	return m_strCurrencySymbol.AllocSysString();
}

void CXTPChartNumberFormat::OleSetCurrencySymbol(LPCTSTR lpszValue)
{
	SetCurrencySymbol(lpszValue);
}

BSTR CXTPChartNumberFormat::OleGetDateDateTimeFormat()
{
	return m_strDateTimeFormat.AllocSysString();
}


#endif