#include "StdAfx.h"

CQuotesProviderDukasCopy::CQuotesProviderDukasCopy()
{
}

CQuotesProviderDukasCopy::~CQuotesProviderDukasCopy()
{
}

namespace
{
	inline tstring get_quote_id(HANDLE hContact)
	{
		return Quotes_DBGetStringT(hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_ID);
	}

	inline bool is_quote_id_equal(HANDLE hContact,const tstring& sID)
	{
		return sID == get_quote_id(hContact);
	}
}

bool CQuotesProviderDukasCopy::IsQuoteWatched(const CQuote& rQuote)const
{
	return m_aContacts.end() != std::find_if(m_aContacts.begin(),m_aContacts.end(),
		boost::bind(is_quote_id_equal,_1,rQuote.GetID()));
}

bool CQuotesProviderDukasCopy::WatchForQuote(const CQuote& rQuote,bool bWatch)
{
	const tstring& sQuoteID = rQuote.GetID();
	TContracts::iterator i = 
		std::find_if(m_aContacts.begin(),m_aContacts.end(),
			boost::bind(is_quote_id_equal,_1,sQuoteID));

	if((false == bWatch) && (i != m_aContacts.end()))
	{
		HANDLE hContact = *i;
		{// for CCritSection
			CGuard<CLightMutex> cs(m_cs);
			m_aContacts.erase(i);
		}

		CallService(MS_DB_CONTACT_DELETE,reinterpret_cast<WPARAM>(hContact),0);
		return true;
	}
	else if((true == bWatch) && (i == m_aContacts.end()))
	{
		HANDLE hContact = CreateNewContact(rQuote.GetSymbol());
		if(hContact)
		{
			db_set_ts(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_ID,sQuoteID.c_str());
			if(false == rQuote.GetName().empty())
			{
				db_set_ts(hContact,QUOTES_PROTOCOL_NAME,DB_STR_QUOTE_DESCRIPTION,rQuote.GetName().c_str());
			}

			return true;
		}

	}
	return false;
}

tstring CQuotesProviderDukasCopy::BuildHTTPURL()const
{
	tostringstream sURL;
	sURL << GetURL();

	{
		CGuard<CLightMutex> cs(m_cs);
		for(TContracts::const_iterator i = m_aContacts.begin();i != m_aContacts.end();++i)
		{
			HANDLE hContact = *i;
			tstring sID = get_quote_id(hContact);
			if(false == sID.empty())
			{
				sURL << sID << _T(",");
			}
		}
	}

	return sURL.str();
}

namespace
{
	struct CEconomicRateInfo
	{
		CEconomicRateInfo() : m_dCurRate(0.0),m_dPrevRate(0.0) {}
		tstring m_sName;
		double m_dCurRate;
		double m_dPrevRate;
		tstring m_sID;
	};

	typedef std::vector<CEconomicRateInfo> TEconomicRates;
	typedef IHTMLNode::THTMLNodePtr THTMLNodePtr;

	bool string2double(const TCHAR* pszText,double& rValue)
	{
		assert(pszText);
		try
		{
			rValue = boost::lexical_cast<double>(pszText);
		}
		catch(boost::bad_lexical_cast &)
		{
			return false;
		}

		return true;
	}


	void parse_row(const THTMLNodePtr& pRow,TEconomicRates& raRates)
	{
		CEconomicRateInfo ri;
		ri.m_sID = pRow->GetAttribute(_T("sid"));
		if(false == ri.m_sID.empty())
		{
			unsigned short cColsHandled = 0;
			tostringstream sSidID;
			sSidID << _T("id") << ri.m_sID;
			size_t cNodes = pRow->GetChildCount();
			for(size_t i = 0;i < cNodes && cColsHandled < 2;++i)
			{
				THTMLNodePtr pCol = pRow->GetChildPtr(i);
				if(pCol)
				{
					tstring sColID = pCol->GetAttribute(_T("id"));
					if(false == sColID.empty())
					{
						if(0 == quotes_stricmp(sColID.c_str(),_T("stock")))
						{
							ri.m_sName = pCol->GetText();
							if(false == ri.m_sName.empty())
							{
								++cColsHandled;
							}
						}
						else if(0 == quotes_stricmp(sSidID.str().c_str(),sColID.c_str()))
						{
							tstring sRate = pCol->GetText();
							if((false == sRate.empty()) && (true == string2double(sRate.c_str(),ri.m_dCurRate)))
							{
								ri.m_dPrevRate = ri.m_dCurRate;
								++cColsHandled;
								tstring sOldRate = pCol->GetAttribute(_T("oldPrice"));
								if(false == sOldRate.empty())
								{
									string2double(sOldRate.c_str(),ri.m_dPrevRate);
								}
							}
						}
					}
				}
			}

			if(2 == cColsHandled)
			{
				raRates.push_back(ri);
			}
		}
	}

// 	void parse_table(const THTMLNodePtr& pNode,TEconomicRates& raRates)
// 	{
// 		size_t cNodes = pNode->GetChildCount();
// 		for(size_t i = 0;i < cNodes;++i)
// 		{
// 			THTMLNodePtr pChild = pNode->GetChildPtr(i);
// 			if(pChild && pChild->Is(IHTMLNode::TableRow))
// 			{
// 				parse_row(pChild,raRates);
// 			}
// 		}
// 
// 	}

	void parser_html_node(const THTMLNodePtr& pNode,TEconomicRates& raRates)
	{
		size_t cNodes = pNode->GetChildCount();
		for(size_t i = 0;i < cNodes;++i)
		{
			THTMLNodePtr pChild = pNode->GetChildPtr(i);
			if(pChild && pChild->Is(IHTMLNode::TableRow))
			{
				parse_row(pChild,raRates);
			}
		}
	}

	bool parse_HTML(const tstring& sHTML,TEconomicRates& raRates)
	{
		IHTMLEngine::THTMLParserPtr pHTMLParser = CModuleInfo::GetHTMLEngine()->GetParserPtr();
		THTMLNodePtr pRoot = pHTMLParser->ParseString(sHTML);
		if(pRoot)
		{
			parser_html_node(pRoot,raRates);
			return true;
		}
		else
		{
			return false;
		}
	}
}


void CQuotesProviderDukasCopy::RefreshQuotes(TContracts& anContacts)
{
	if(CModuleInfo::GetInstance().GetExtendedStatusFlag())
	{
		std::for_each(anContacts.begin(),anContacts.end(),
			boost::bind(SetContactStatus,_1,ID_STATUS_OCCUPIED));
	}

	tstring sURL = BuildHTTPURL();

	CHTTPSession http;
// 	LogIt(Info,sURL);
	if(true == http.OpenURL(sURL))
	{
		if(true == IsOnline())
		{
			tstring sHTML;
			if(true == http.ReadResponce(sHTML))
			{
// 				LogIt(Info,sHTML);
				if(true == IsOnline())
				{
					TEconomicRates aRates;
					if(true == parse_HTML(sHTML,aRates)
						&& (true == IsOnline()))
					{
						for(TEconomicRates::const_iterator it = aRates.begin();(it != aRates.end()) && (true == IsOnline());++it)
						{
							const CEconomicRateInfo& ri = *it;

							TContracts::iterator i = std::find_if(anContacts.begin(),anContacts.end(),
								boost::bind(is_quote_id_equal,_1,ri.m_sID));
							if(i != anContacts.end() && (true == IsOnline()))
							{
								HANDLE hContact = *i;
								anContacts.erase(i);

								WriteContactRate(hContact,ri.m_dCurRate,ri.m_sName);
							}
						}
					}
				}
			}
		}
	}

	std::for_each(anContacts.begin(),anContacts.end(),
		boost::bind(&SetContactStatus,_1,ID_STATUS_NA));
}

void CQuotesProviderDukasCopy::ShowPropertyPage(WPARAM wp,OPTIONSDIALOGPAGE& odp)
{
	ShowDukasCopyPropPage(this,wp,odp);
}

void CQuotesProviderDukasCopy::Accept(CQuotesProviderVisitor& visitor)const
{
	CQuotesProviderBase::Accept(visitor);
	visitor.Visit(*this);
}

HANDLE CQuotesProviderDukasCopy::GetContactByQuoteID(const tstring& rsQuoteID)const
{
	CGuard<CLightMutex> cs(m_cs);

	TContracts::const_iterator i = std::find_if(m_aContacts.begin(),m_aContacts.end(),
		boost::bind(std::equal_to<tstring>(),rsQuoteID,boost::bind(get_quote_id,_1)));
	if(i != m_aContacts.end())
	{
		return *i;
	}
	else
	{
		return NULL;
	}
}

// #ifdef CHART_IMPLEMENT
// bool CQuotesProviderDukasCopy::Chart(HANDLE hContact,const tstring& url)const
// {
// 	LogIt(Info,url);
// 
// 	CHTTPSession http;
// 	if((true == http.OpenURL(url)))
// 	{
// 		tstring sHTML;
// 		if((true == http.ReadResponce(sHTML)))
// 		{
// 			LogIt(Info,sHTML);
// 		}
// 	}
// 
// 	return false;
// }
// #endif //CHART_IMPLEMENT