#include "StdAfx.h" CQuotesProviderGoogleFinance::CQuotesProviderGoogleFinance() { } CQuotesProviderGoogleFinance::~CQuotesProviderGoogleFinance() { } namespace { tstring build_url(HANDLE hContact,const tstring& rsURL) { tostringstream o; o << rsURL << _T("?q=") << Quotes_DBGetStringT(hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_ID); return o.str(); } struct CGoogleInfo { enum { giRate = 0x0001, giOpen = 0x0002, giPercentChangeAfterHours = 0x0004, giPercentChangeToYesterdayClose = 0x0008 }; CGoogleInfo() : m_dRate(0.0),m_dOpenValue(0.0),m_dPercentChangeAfterHours(0.0),m_dPercentChangeToYersterdayClose(0.0),m_nFlags(0){} // tstring m_sCmpID; tstring m_sCmpName; double m_dRate; double m_dOpenValue; double m_dPercentChangeAfterHours; double m_dPercentChangeToYersterdayClose; // tstring m_sRateID; // tstring m_sDiffID; byte m_nFlags; }; tstring make_rate_id_value(const tstring& rsCmpID,int nFlags) { tostringstream o; o << _T("ref_") << rsCmpID; switch(nFlags) { default: assert(!"Unknown type of value"); case CGoogleInfo::giRate: o << _T("_l"); break; case CGoogleInfo::giPercentChangeAfterHours: o << _T("_ecp"); break; case CGoogleInfo::giPercentChangeToYesterdayClose: o << _T("_cp"); break; } return o.str(); } tstring get_var_value(const tstring& rsHTML,LPCTSTR pszVarName,size_t cVarNameLength) { tstring sResult; tstring::size_type n = rsHTML.find(pszVarName); if(tstring::npos != n) { size_t cLengthHTML = rsHTML.size(); for(size_t i = n + cVarNameLength;i < cLengthHTML;++i) { TCHAR c = rsHTML[i]; if(_T(';') == c) { break; } else { sResult.push_back(c); } } } return sResult; } tstring get_company_id(const tstring& rsHTML) { static LPCTSTR pszVarName = _T("setCompanyId("); static size_t cVarNameLength = _tcslen(pszVarName); tstring sResult; tstring::size_type n = rsHTML.find(pszVarName); if(tstring::npos != n) { size_t cLengthHTML = rsHTML.size(); for(size_t i = n + cVarNameLength;i < cLengthHTML;++i) { TCHAR c = rsHTML[i]; if(_T(')') == c) { break; } else { sResult.push_back(c); } } } return sResult; // return get_var_value(rsHTML,pszVarName,cVarNameLength); } tstring get_company_name(const tstring& rsHTML) { static LPCTSTR pszVarName = _T("var _companyName = "); static size_t cVarNameLength = _tcslen(pszVarName); tstring s = get_var_value(rsHTML,pszVarName,cVarNameLength); if(s.size() > 0 && _T('\'') == s[0]) { s.erase(s.begin()); } if(s.size() > 0 && _T('\'') == s[s.size()-1]) { s.erase(s.rbegin().base()-1); } return s; } bool get_double_value(const tstring& rsText,double& rdValue) { tistringstream input(rsText); input.imbue(std::locale("English_United States.1252")); input >> rdValue; if ((true == input.bad()) || (true == input.fail())) { tistringstream inputSys(rsText); input.imbue(GetSystemLocale()); input >> rdValue; return (false == inputSys.bad()) && (false == inputSys.fail()); } else { return true; } } bool get_rate(const IHTMLNode::THTMLNodePtr& pRate,CGoogleInfo& rInfo) { tstring sRate = pRate->GetText(); if(true == get_double_value(sRate,rInfo.m_dRate)) { rInfo.m_nFlags |= CGoogleInfo::giRate; return true; } else { return false; } } bool get_inline_data(const IHTMLNode::THTMLNodePtr& pNode,CGoogleInfo& rInfo) { size_t cChild = pNode->GetChildCount(); for(size_t i = 0;i < cChild;++i) { IHTMLNode::THTMLNodePtr pChild = pNode->GetChildPtr(i); size_t c = pChild->GetChildCount(); assert(2 == c); if(c >= 2) { IHTMLNode::THTMLNodePtr pName = pChild->GetChildPtr(0); tstring sName = pName->GetText(); if(0 == quotes_stricmp(sName.c_str(),_T("Open"))) { IHTMLNode::THTMLNodePtr pValue = pChild->GetChildPtr(1); tstring sValue = pValue->GetText(); if(true == get_double_value(sValue,rInfo.m_dOpenValue)) { rInfo.m_nFlags |= CGoogleInfo::giOpen; } return true; } } } return false; } bool get_dif_value(const IHTMLNode::THTMLNodePtr& pNode,CGoogleInfo& rInfo,int nItem) { tstring sDiff = pNode->GetText(); // this value is in brackets and it has percentage sign. // Remove these symbols. for(tstring::iterator i = sDiff.begin();i != sDiff.end();) { TCHAR s = *i; if(_T('(') == s || _T(')') == s || _T('%') == s) { i = sDiff.erase(i); } else { ++i; } } double* pValue = NULL; switch(nItem) { case CGoogleInfo::giPercentChangeAfterHours: pValue = &rInfo.m_dPercentChangeAfterHours; break; case CGoogleInfo::giPercentChangeToYesterdayClose: pValue = &rInfo.m_dPercentChangeToYersterdayClose; break; } assert(pValue); if ((pValue) && (true == get_double_value(sDiff,*pValue))) { rInfo.m_nFlags |= nItem; return true; } else { return false; } } bool parse_responce(const tstring& rsHTML,CGoogleInfo& rInfo) { IHTMLEngine::THTMLParserPtr pHTMLParser = CModuleInfo::GetHTMLEngine()->GetParserPtr(); IHTMLNode::THTMLNodePtr pRoot = pHTMLParser->ParseString(rsHTML); if(pRoot) { tstring sCmpID = get_company_id(rsHTML); if(false == sCmpID.empty()) { tstring sRateID = make_rate_id_value(sCmpID,CGoogleInfo::giRate); IHTMLNode::THTMLNodePtr pRate = pRoot->GetElementByID(sRateID); if(pRate && get_rate(pRate,rInfo)) { rInfo.m_sCmpName = get_company_name(rsHTML); IHTMLNode::THTMLNodePtr pInline = pRoot->GetElementByID(_T("snap-data")); if(pInline) { get_inline_data(pInline,rInfo); } tstring sDiffID = make_rate_id_value(sCmpID,CGoogleInfo::giPercentChangeAfterHours); IHTMLNode::THTMLNodePtr pDiff = pRoot->GetElementByID(sDiffID); if(pDiff) { get_dif_value(pDiff,rInfo,CGoogleInfo::giPercentChangeAfterHours); } sDiffID = make_rate_id_value(sCmpID,CGoogleInfo::giPercentChangeToYesterdayClose); pDiff = pRoot->GetElementByID(sDiffID); if(pDiff) { get_dif_value(pDiff,rInfo,CGoogleInfo::giPercentChangeToYesterdayClose); } return true; } //return (true == parse_html_node(pRoot,rInfo)); } } return false; } } void CQuotesProviderGoogleFinance::RefreshQuotes(TContracts& anContacts) { CHTTPSession http; tstring sURL = GetURL(); bool bUseExtendedStatus = CModuleInfo::GetInstance().GetExtendedStatusFlag(); for(TContracts::const_iterator i = anContacts.begin();i != anContacts.end() && IsOnline();++i) { HANDLE hContact = *i; if(bUseExtendedStatus) { SetContactStatus(hContact,ID_STATUS_OCCUPIED); } tstring sFullURL = build_url(hContact,sURL); // LogIt(Info,sFullURL); if ((true == http.OpenURL(sFullURL)) && (true == IsOnline())) { tstring sHTML; if ((true == http.ReadResponce(sHTML)) && (true == IsOnline())) { // LogIt(Info,sHTML); CGoogleInfo Info; parse_responce(sHTML,Info); if(true == IsOnline()) { if(Info.m_nFlags&CGoogleInfo::giRate) { if(Info.m_nFlags&CGoogleInfo::giOpen) { Quotes_DBWriteDouble(hContact,QUOTES_MODULE_NAME,DB_STR_GOOGLE_FINANCE_OPEN_VALUE,Info.m_dOpenValue); } if(Info.m_nFlags&CGoogleInfo::giPercentChangeAfterHours) { Quotes_DBWriteDouble(hContact,QUOTES_MODULE_NAME,DB_STR_GOOGLE_FINANCE_DIFF,Info.m_dPercentChangeAfterHours); } if(Info.m_nFlags&CGoogleInfo::giPercentChangeToYesterdayClose) { Quotes_DBWriteDouble(hContact,QUOTES_MODULE_NAME,DB_STR_GOOGLE_FINANCE_PERCENT_CHANGE_TO_YERSTERDAY_CLOSE,Info.m_dPercentChangeToYersterdayClose); } if(false == Info.m_sCmpName.empty()) { db_set_ts(hContact,QUOTES_MODULE_NAME,DB_STR_QUOTE_DESCRIPTION,Info.m_sCmpName.c_str()); } WriteContactRate(hContact,Info.m_dRate); continue; } } } } SetContactStatus(hContact,ID_STATUS_NA); } } void CQuotesProviderGoogleFinance::Accept(CQuotesProviderVisitor& visitor)const { CQuotesProviderFinance::Accept(visitor); visitor.Visit(*this); }