/*

WinPopup Protocol plugin for Miranda IM.

Copyright (C) 2004-2011 Nikolay Raspopov

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "stdafx.h"

contact_scanner	pluginScanner;

contact_scanner::contact_scanner () :
	m_ScannerTerm (NULL),
	m_Scanner (NULL)
{
}

contact_scanner::~contact_scanner ()
{
	Destroy ();
}

bool contact_scanner::Create ()
{
	// ������ ������� ���������
	if (m_ScannerTerm)
		ResetEvent (m_ScannerTerm);
	else
		m_ScannerTerm = CreateEvent (NULL, TRUE, FALSE, NULL);

	if ( ! m_Scanner )
		m_Scanner = (HANDLE)mir_forkthread( ScannerThread, this );

	return ( m_Scanner != NULL );
}

void contact_scanner::AskForDestroy()
{
	if (m_ScannerTerm)
		SetEvent (m_ScannerTerm);
}

void contact_scanner::Destroy ()
{
	AskForDestroy();

	if (m_Scanner)
	{
		if (WaitForSingleObject (m_Scanner, ALMOST_INFINITE) == WAIT_TIMEOUT)
		{
			LOG("Terminate scanner!");
			TerminateThread (m_Scanner, 0);
		}
		m_Scanner = NULL;
	}

	if (m_ScannerTerm) {
		CloseHandle (m_ScannerTerm);
		m_ScannerTerm = NULL;
	}
}

contact_scanner::operator bool () const
{
	return ( m_Scanner != NULL );
}

// First, Next, ... Next, NULL, First, Next...
HANDLE contact_scanner::GetNextScannableContact()
{
	static HANDLE hContact = NULL;
	if (!hContact)
		hContact = (HANDLE) CallService (MS_DB_CONTACT_FINDFIRST, 0, 0);

	// ����������� ������� ���������
	while( hContact )
	{
		// �������� �� ���������� ��������� ��������
		if ( IsMyContact( hContact ) &&
			!DBGetContactSettingByte (hContact, "CList", "NotOnList", 0) &&
			!DBGetContactSettingByte (hContact, "CList", "Hidden", 0) )
		{
			// ���������� ������� ������ ������ �� ������� ����������
			// ���������� ������� ��������. ����� ��������?
			DWORD elapsed = GetElapsed (hContact, "LastSeen");
			if ( elapsed >= MIN_PING_INTERVAL )
				break;
		}
		hContact = (HANDLE) CallService (MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
	}
	return hContact;
}

int contact_scanner::ScanContact(HANDLE  hContact)
{
	if ( ! pluginInstalled )
		return ID_STATUS_OFFLINE;

#ifdef CHAT_ENABLED
	if ( IsChatRoom( hContact ) )
	{
		CString sSession = GetChatSession( hContact );
		if ( pluginChatEnabled && ! sSession.IsEmpty() )
		{
			CAtlList< CString > lst;
			EnumWorkgroups( lst );
			for ( POSITION pos = lst.GetHeadPosition(); pos; )
			{
				if ( lst.GetNext( pos ) == sSession )
					return ID_STATUS_ONLINE;
			}
		}
		return ID_STATUS_OFFLINE;	
	}
	else
#endif // CHAT_ENABLED
	{
		int status = ID_STATUS_OFFLINE;

		// ��������� ������� "Always Online"
		if ( DBGetContactSettingByte( hContact, modname, "AlwaysOnline", FALSE ) )
			status = ID_STATUS_ONLINE;

		// ��������� ����� ��������
		CString sNick = GetNick( hContact );
		if ( ! sNick.IsEmpty() )
		{
			if ( IsGroup( hContact ) )
			{
				// ��� "���" ����� ������
				if ( sNick == _T("*") )
					return ID_STATUS_ONLINE;

				// ������������ ����� � �������� � �����
				CAtlList< CString > lst;
				EnumWorkgroups( lst );
				for ( POSITION pos = lst.GetHeadPosition(); pos; )
				{
					if ( lst.GetNext( pos ).CompareNoCase( sNick ) == 0 )
						return ID_STATUS_ONLINE;
				}
			}
			else if ( IsLegacyOnline( NULL ) || IsLegacyOnline( hContact ) )
			{
				// ���������� ����� ����� �� ������� NetBIOS-����� "Nick <00> U"
				netbios_name nname( sNick, 0x00, false );
				UCHAR foo;
				if ( pluginNetBIOS.FindNameLana( nname, foo ) )
				{
					status = ID_STATUS_ONLINE;

					// ����������� ����� �������� "Nick <00> U"
					pluginNetBIOS.AskStatus( nname );
				}
			}
			else
			{
				// ���������� ����� ����� �� ������� NetBIOS-����� "Nick <03> U"
				netbios_name nname( sNick, 0x03, false );
				UCHAR foo;
				if ( pluginNetBIOS.FindNameLana( nname, foo ) )
				{
					status = ID_STATUS_ONLINE;

					// ����������� ����� �������� "Nick <03> U"
					pluginNetBIOS.AskStatus( nname );
				}
			}
		}
		return status;
	}
}

void contact_scanner::Scanner ()
{
	while (WaitForSingleObject (m_ScannerTerm, 1000) == WAIT_TIMEOUT)
	{
		// ������� ���������� ��������� �� ��������
		if ( HANDLE hContact = GetNextScannableContact() )
		{
			// �������� ��������
			SetContactStatus( hContact, ScanContact( hContact ), true );
		}
	}
}

void contact_scanner::ScannerThread (LPVOID lpParameter)
{
	if ( contact_scanner* pScanner = (contact_scanner*)lpParameter )
	{
		pScanner->Scanner();
		pScanner->m_Scanner = NULL;
	}
}