#include "skype.h"
#include <sstream>

void CSkypeProto::UpdateProfileAvatar(SEObject *obj, HANDLE hContact)
{
	uint newTS = obj->GetUintProp(/* *::P_AVATAR_TIMESTAMP */ 182);
	//if (!newTS) return; //uncomment when skypekit will be work correctly

	DWORD oldTS = this->getDword(hContact, "AvatarTS", 0);

	ptrW path( this->GetContactAvatarFilePath(hContact));
	bool isAvatarFileExists = CSkypeProto::FileExists(path);
	if (newTS > oldTS || !isAvatarFileExists)
	{
		SEBinary data = obj->GetBinProp(/* *::P_AVATAR_IMAGE */ 37);
		if (data.size() > 0)
		{
			FILE *fp = ::_wfopen(path, L"wb");
			if (fp)
			{
				::fwrite(data.data(), sizeof(char), data.size(), fp);
				::fclose(fp);

				this->setDword(hContact, "AvatarTS", newTS);

				if (hContact)
				{
					PROTO_AVATAR_INFORMATIONW pai = { sizeof(pai) };
					pai.format = PA_FORMAT_JPEG;
					pai.hContact = hContact;
					::wcscpy(pai.filename, path);
						
					this->SendBroadcast(hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE)&pai, 0);
				}
				else
				{
					BYTE digest[16];
					::mir_md5_hash((BYTE*)data.data(), (int)data.size(), digest);
					::db_set_blob(hContact, this->m_szModuleName, "AvatarHash", digest, 16);

					::CallService(MS_AV_SETMYAVATART, (WPARAM)m_szModuleName, (LPARAM)path);
				}
			}
		}
		else if (isAvatarFileExists)
		{
			::_wremove(path);
			this->SendBroadcast(hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, NULL, 0);
		}
	}
}

void CSkypeProto::UpdateProfileAboutText(SEObject *obj, HANDLE hContact)
{
	ptrW aboutText(::mir_utf8decodeW(obj->GetStrProp(/* *::P_ABOUT */ 18)));
	if ( !::wcslen(aboutText))
		this->delSetting(hContact, "About");
	else
		this->setTString(hContact, "About", aboutText);
}

void CSkypeProto::UpdateProfileBirthday(SEObject *obj, HANDLE hContact)
{
	uint data = obj->GetUintProp(/* *::P_BIRTHDAY */ 7);
	if (data > 0)
	{
		TCHAR date[20];
		_itot_s(data, date, 10);

		INT day, month, year;
		_stscanf(date, _T("%04d%02d%02d"), &year, &month, &day);

		SYSTEMTIME sToday = {0};
		GetLocalTime(&sToday);

		if (sToday.wYear > year) return;
		else if(sToday.wYear == year && sToday.wMonth > month) return;
		else if(sToday.wYear == year && sToday.wMonth == month && sToday.wDay >= day) return;

		this->setByte(hContact, "BirthDay", day);
		this->setByte(hContact, "BirthMonth", month);
		this->setWord(hContact, "BirthYear", year);

		int nAge = sToday.wYear - year;
		if (sToday.wMonth < month || (sToday.wMonth == month && sToday.wDay < day))
			nAge--;
		if (nAge)
			this->setWord(hContact, "Age", (WORD)nAge );
	}
	else
	{
		this->delSetting(hContact, "BirthDay");
		this->delSetting(hContact, "BirthMonth");
		this->delSetting(hContact, "BirthYear");
		this->delSetting(hContact, "Age");
	}
}

void CSkypeProto::UpdateProfileCity(SEObject *obj, HANDLE hContact)
{
	ptrW city(::mir_utf8decodeW(obj->GetStrProp(/* *::P_CITY */ 12)));
	if ( !::wcslen(city))
		this->delSetting(hContact, "City");
	else
		this->setTString(hContact, "City", city);
}

void CSkypeProto::UpdateProfileCountry(SEObject *obj, HANDLE hContact)
{
	char *country;
	ptrA isocode(::mir_strdup(obj->GetStrProp(/* *::P_COUNTRY */ 10)));
	if ( !::strlen(isocode))
		this->delSetting(hContact, "Country");
	else
	{
		country = (char *)CallService(MS_UTILS_GETCOUNTRYBYISOCODE, (WPARAM)isocode, 0);
		this->setTString(hContact, "Country", _A2T(country));
	}
}

void CSkypeProto::UpdateProfileEmails(SEObject *obj, HANDLE hContact)
{
	ptrW emails(::mir_utf8decodeW(obj->GetStrProp(/* *::P_EMAILS */ 16)));
	if (::wcscmp(emails, L"") == 0)
	{
		this->delSetting(hContact, "e-mail0");
		this->delSetting(hContact, "e-mail1");
		this->delSetting(hContact, "e-mail2");
	}
	else
	{
		StringList emls = emails;
		for (size_t i = 0; i < emls.size(); i++)
		{
			std::stringstream ss;
			ss << "e-mail" << i;
			std::string key = ss.str();
		
			this->setTString(hContact, key.c_str(), emls[i]);
		}
	}
}

void CSkypeProto::UpdateProfileFullName(SEObject *obj, HANDLE hContact)
{
	ptrW fullname(::mir_utf8decodeW(obj->GetStrProp(/* *::P_FULLNAME */ 5)));
	if ( !::wcslen(fullname))
	{
		this->delSetting(hContact, "FirstName");
		this->delSetting(hContact, "LastName");
	}
	else
	{
		StringList names = fullname;

		this->setTString(hContact, "FirstName", names[0]);
		if (names.size() > 1)
			this->setTString(hContact, "LastName", names[1]);
	}
}

void CSkypeProto::UpdateProfileGender(SEObject *obj, HANDLE hContact)
{
	uint data = obj->GetUintProp(/* *::P_GENDER */ 8);
	if (data)
		this->setByte(hContact, "Gender", (BYTE)(data == 1 ? 'M' : 'F'));
	else
		this->delSetting(hContact, "Gender");
}

void CSkypeProto::UpdateProfileHomepage(SEObject *obj, HANDLE hContact)
{
	ptrW homepage(::mir_utf8decodeW(obj->GetStrProp(/* *::P_HOMEPAGE */ 17)));
	if (::wcscmp(homepage, L"") == 0)
		this->delSetting(hContact, "Homepage");
	else
		this->setTString(hContact, "Homepage", homepage);
}

void CSkypeProto::UpdateProfileLanguages(SEObject *obj, HANDLE hContact)
{
	ptrW isocodes(::mir_utf8decodeW(obj->GetStrProp(/* *::P_LANGUAGES */ 9)));

	this->delSetting(hContact, "Language1");
	this->delSetting(hContact, "Language2");
	this->delSetting(hContact, "Language3");

	StringList langs = isocodes;
	for (size_t i = 0; i < langs.size(); i++)
	{
		if (CSkypeProto::languages.count(langs[i]))
		{
			std::stringstream ss;
			ss << "Language" << i + 1;
			std::string key = ss.str();
			std::wstring val = CSkypeProto::languages[langs[i]];
			this->setTString(hContact, key.c_str(), val.c_str());
		}
	}
}

void CSkypeProto::UpdateProfileMobilePhone(SEObject *obj, HANDLE hContact)
{
	ptrW phone(::mir_utf8decodeW(obj->GetStrProp(/* *::P_PHONE_MOBILE */ 15)));
	if ( !::wcslen(phone))
		this->delSetting(hContact, "Cellular");
	else
		this->setTString(hContact, "Cellular", phone);
}

void CSkypeProto::UpdateProfileNick(SEObject *obj, HANDLE hContact)
{
	ptrW nick;
	if (hContact)
	{
		CContact *contact = (CContact *)obj;
		nick = ::mir_utf8decodeW(contact->GetNick());
	}
	else
		nick = ::mir_utf8decodeW(obj->GetStrProp(Account::P_FULLNAME));

	if ( !::wcslen(nick))
		this->delSetting(hContact, "Nick");
	else
		this->setTString(hContact, "Nick", nick);
}

void CSkypeProto::UpdateProfilePhone(SEObject *obj, HANDLE hContact)
{
	ptrW phone(::mir_utf8decodeW(obj->GetStrProp(/* *::P_PHONE_MOBILE */ 13)));
	if ( !::wcslen(phone))
		this->delSetting(hContact, "Phone");
	else
		this->setTString(hContact, "Phone", phone);
}

void CSkypeProto::UpdateProfileOfficePhone(SEObject *obj, HANDLE hContact)
{
	ptrW phone(::mir_utf8decodeW(obj->GetStrProp(/* *::P_PHONE_OFFICE */ 14)));
	if ( !::wcslen(phone))
		this->delSetting(hContact, "CompanyPhone");
	else
		this->setTString(hContact, "CompanyPhone", phone);		
}

void CSkypeProto::UpdateProfileState(SEObject *obj, HANDLE hContact)
{
	ptrW state(::mir_utf8decodeW(obj->GetStrProp(/* *::P_PROVINCE */ 11)));
	if ( !::wcslen(state))
		this->delSetting(hContact, "State");
	else
		this->setTString(hContact, "State", state);		
}

void CSkypeProto::UpdateProfileStatusMessage(SEObject *obj, HANDLE hContact)
{
	ptrW statusMessage(::mir_utf8decodeW(obj->GetStrProp(/* *::P_MOOD_TEXT */ 26)));
	if ( !::wcslen(statusMessage))
		this->delSetting(hContact, "XStatusMsg");
	else
		this->setTString(hContact, "XStatusMsg", statusMessage);
}

void CSkypeProto::UpdateProfileTimezone(SEObject *obj, HANDLE hContact)
{
	LONG data = obj->GetUintProp(/* *::P_TIMEZONE */ 27);
	if (data > 0)
	{
		LONG diffmin = (data - 24*3600) / 60;
		wchar_t sign[2];
		if (diffmin < 0)
			::wcscpy(sign, L"-");
		else
			::wcscpy(sign, L"+");
		uint hours = ::abs((int)(diffmin / 60));
		uint mins = ::abs((int)(diffmin % 60));
		wchar_t timeshift[7];
		::mir_sntprintf(timeshift, SIZEOF(timeshift), _T("%s%d:%02d"), sign, hours, mins);
			
		wchar_t *szMin = wcschr(timeshift, ':');
		int nTz = ::_wtoi(timeshift) * -2;
		nTz += (nTz < 0 ? -1 : 1) * (szMin ? _ttoi( szMin + 1 ) / 30 : 0);

		this->setByte(hContact, "Timezone", (signed char)nTz);
	}
	else this->delSetting(hContact, "Timezone");
}

void CSkypeProto::UpdateProfile(SEObject *obj, HANDLE hContact)
{
	this->debugLogW(L"Updating profile for %p", hContact);
	this->UpdateProfileAvatar(obj, hContact);

	uint newTS = hContact ? obj->GetUintProp(Contact::P_PROFILE_TIMESTAMP) : obj->GetUintProp(Account::P_PROFILE_TIMESTAMP);
	this->UpdateProfileAboutText(obj, hContact);
	this->UpdateProfileBirthday(obj, hContact);
	this->UpdateProfileCity(obj, hContact);
	this->UpdateProfileCountry(obj, hContact);
	this->UpdateProfileEmails(obj, hContact);
	this->UpdateProfileFullName(obj, hContact);
	this->UpdateProfileGender(obj, hContact);
	this->UpdateProfileHomepage(obj, hContact);
	this->UpdateProfileLanguages(obj, hContact);
	this->UpdateProfileMobilePhone(obj, hContact);
	this->UpdateProfileNick(obj, hContact);
	this->UpdateProfilePhone(obj, hContact);
	this->UpdateProfileOfficePhone(obj, hContact);
	this->UpdateProfileState(obj, hContact);
	this->UpdateProfileStatusMessage(obj, hContact);
	this->UpdateProfileTimezone(obj, hContact);

	if (hContact)
	{
		ContactRef ref(obj->getOID());
		this->UpdateContactClient(hContact, ref);
		this->UpdateContactLastEventDate(hContact, ref);
		this->UpdateContactOnlineSinceTime(hContact, ref);
	}

	this->setDword(hContact, "ProfileTS", newTS);
}