// WaitDlgThread.cpp : implementation file
//

#include "stdafx.h"
#include "WaitDlg.h"
#include "WaitDlgThread.h"
#include "WaitDlg.h"
#include "apl_gui.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CWaitDlgThread

CUIntArray list_threads;
CRITICAL_SECTION list_threads_protect;

long CWaitDlgThread::st_iCurrentThreadCounter=0;
bool CWaitDlgThread::st_bEnableMultipleWaitDialog=false;

IMPLEMENT_DYNCREATE(CWaitDlgThread, CWinThread)


LPWORD lpwAlign ( LPWORD lpIn)
{
	ULONG ul;
	ul = (ULONG) lpIn;
	ul +=3;
	ul >>=2;
	ul <<=2;
	return (LPWORD) ul;
} 

CWaitDlgThread::CWaitDlgThread()
	: m_pParentWnd(NULL)
{
	m_sTitle =  APL_T("Загрузка данных");
	m_Text = _T("");
	m_event_End = CreateEvent(0,TRUE,FALSE,_T(""));
	m_bSetText = false;
	m_bShowWaitDlg = false;
	m_bShowDlg = TRUE;
	m_pDlgWnd = NULL;
	m_ParentThreadId=0;
}

CWaitDlgThread::~CWaitDlgThread()
{
	int i;
	EnterCriticalSection(&list_threads_protect);
	for(i=0;i<list_threads.GetSize();i++)
	{
		if(list_threads[i]==(long)this)
		{
			list_threads.RemoveAt(i);
			break;
		}
	}
	LeaveCriticalSection(&list_threads_protect);

	CloseHandle(m_event_End);
}


BOOL CWaitDlgThread::InitInstance()
{
	DWORD res=WaitForSingleObject(m_event_End,500);
	// если сигнальное состояние эвента, выходим из функции
	if(res==WAIT_FAILED || res== WAIT_OBJECT_0)
		return FALSE;

	//Убрано, т.к. переделано на работу без ресурсов
	//HINSTANCE m_hInstOld = AfxGetResourceHandle();
	//AfxSetResourceHandle(module_inst);
	
	CWaitDlg dlg;
	m_pMainWnd = &dlg;
	m_pDlgWnd = &dlg;
	dlg.m_txt = m_Text;
	dlg.m_sTitle = m_sTitle;
	dlg.m_bShowDlg = m_bShowDlg;
	dlg.m_Thread = this;
	dlg.setPos = setPos;
	dlg.windowPos = windowPos;

	//dlg.Create(CWaitDlg::IDD);
	
	// Создаем в памяти чтобы не использовать ресурсы
	{
		HGLOBAL hgbl;
		LPDLGTEMPLATE lpdt;
		LPDLGITEMTEMPLATE lpdit;
		LPWORD lpw;
		LPWSTR lpwsz;
		int nchar;

		hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024);
		if (!hgbl)	return -1;

		lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);

		// Определение диалогового окна.
		lpdt->style = WS_POPUP | WS_BORDER | DS_MODALFRAME | WS_CAPTION | DS_CENTER; // еще надо DS_SETFONT 

		lpdt->cdit = 2;	// число элементов управления
		lpdt->x  = 0;  lpdt->y  = 0;
		lpdt->cx = 172; lpdt->cy = 26;

		lpw = (LPWORD) (lpdt + 1);
		*lpw++ = 0;	// меню нет
		*lpw++ = 0;	// класс предопределенного диалогового окна (по умолчанию)

		lpwsz = (LPWSTR) lpw;

		nchar = MultiByteToWideChar (CP_ACP, 0, "Wait!!!",  -1, lpwsz, 50);
		lpw   += nchar;

		// Определение статического текста в элементе управления.
		// CTEXT           "Пожалуйста подождите . . .",IDC_MY_TEXT,26,8,142,17

		lpw = lpwAlign (lpw); 		// выравнивание DLGITEMTEMPLATE по границе DWORD
		lpdit = (LPDLGITEMTEMPLATE) lpw;
		lpdit->x  = 26; lpdit->y  = 8;
		lpdit->cx = 142; lpdit->cy = 17;
		lpdit->id = IDC_MY_TEXT;  // идентификатор текста
		lpdit->style = WS_CHILD | WS_VISIBLE | SS_CENTER;

		lpw = (LPWORD) (lpdit + 1);
		*lpw++ = 0xFFFF;
		*lpw++ = 0x0082;	// класс статического элемента

		lpw = lpwAlign (lpw);	// выравнивание созданных данных по границе DWORD
		*lpw++ = 0;		// созданных данных нет */


		// Определение иконки. ICON            "",IDC_WAIT_IMG,1,3,21,20
		lpw = lpwAlign (lpw); 		// выравнивание DLGITEMTEMPLATE по границе DWORD
		lpdit = (LPDLGITEMTEMPLATE) lpw;
		lpdit->x  = 1; lpdit->y  = 3;
		lpdit->cx = 21; lpdit->cy = 20;
		lpdit->id = IDC_WAIT_IMG;  // идентификатор текста
		lpdit->style = WS_CHILD | WS_VISIBLE | SS_ICON;

		lpw = (LPWORD) (lpdit + 1);
		*lpw++ = 0xFFFF;
		*lpw++ = 0x0082;	// класс статического элемента

		lpw = lpwAlign (lpw);	// выравнивание созданных данных по границе DWORD
		*lpw++ = 0;		// созданных данных нет */
		GlobalUnlock(hgbl); 

		BOOL b=dlg.CreateIndirect(hgbl);

		GlobalFree(hgbl); 
		if(!b)return FALSE;
	}

	dlg.ShowWindow(SW_SHOW);
	
	//AfxSetResourceHandle(m_hInstOld); Убрано, т.к. переделано на работу без ресурсов
	Run();
	dlg.DestroyWindow();
	return FALSE;
}

int CWaitDlgThread::ExitInstance()
{
	m_pDlgWnd=0;
  return CWinThread::ExitInstance();
}

BEGIN_MESSAGE_MAP(CWaitDlgThread, CWinThread)
	//{{AFX_MSG_MAP(CWaitDlgThread)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CWaitDlgThread::SetText( LPCTSTR text/*=NULL*/, LPCTSTR title/*=NULL*/ )
{
	if(text)
		m_Text = text;
	if(title)
		m_sTitle = title;

	if(m_pDlgWnd)
	{
		if(text)
			m_pDlgWnd->m_txt = text;
		if(title)
			m_pDlgWnd->m_sTitle = title;

		m_bSetText = true;
	}
}

void CWaitDlgThread::ShowWaitDlg(BOOL bShow)
{
	m_bShowDlg = bShow;

	if(m_pDlgWnd)
	{
		m_pDlgWnd->m_bShowDlg = bShow;
		m_pDlgWnd->ShowWindow(m_pDlgWnd->m_bShowDlg);
		m_bShowWaitDlg = false;
	}
	else
		m_bShowWaitDlg = true;
}

/////////////////////////////////////////////////////////////////////////////
// CWaitDlgThread message handlers


//*******************************************************************
//*******************************************************************
//*******************************************************************
long AFX_EXT_API aplStartWaitDlg(LPCTSTR text, LPCTSTR title,  bool setPos /*= false*/, HWND windowPos /*= HWND_TOPMOST*/)
{
	//return 0;
	if(CWaitDlgThread::st_bEnableMultipleWaitDialog==false)
	{
		if(CWaitDlgThread::st_iCurrentThreadCounter>0) return 0;
	}

	CWaitDlgThread *thread = (CWaitDlgThread *)AfxBeginThread(RUNTIME_CLASS(CWaitDlgThread), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
	if(0 == thread) return 0;
	thread->m_Text = text;
	if(title)
		thread->m_sTitle = title;

	thread->m_pParentWnd =  (AfxGetMainWnd()==0)?0:AfxGetMainWnd()->GetForegroundWindow();
	thread->setPos = setPos;
	thread->windowPos = windowPos;
	thread->m_ParentThreadId=::GetCurrentThreadId();

	EnterCriticalSection(&list_threads_protect);
	list_threads.Add((long) thread);
	LeaveCriticalSection(&list_threads_protect);

	thread->ResumeThread();

	CWaitDlgThread::st_iCurrentThreadCounter++;

	return (long) thread;
}

void AFX_EXT_API aplSetTextWaitDlg(long thread, LPCTSTR text, LPCTSTR title)
{
	if(thread==0) return;

	int i;
	bool found=false;
	EnterCriticalSection(&list_threads_protect);
	for(i=0;i<list_threads.GetSize();i++)
	{
		if(list_threads[i]==thread)
		{
			found = true;
			break;
		}
	}
	if(found)
	{
		CWaitDlgThread* pThread = (CWaitDlgThread*)thread;
		pThread->SetText(text, title);
	}
	LeaveCriticalSection(&list_threads_protect);
}

void AFX_EXT_API aplShowWaitDlg(long thread, BOOL bShow)
{
	if(thread==0) return;

	int i;
	bool found=false;
	EnterCriticalSection(&list_threads_protect);
	for(i=0;i<list_threads.GetSize();i++)
	{
		if(list_threads[i]==thread)
		{
			found = true;
			break;
		}
	}
	if(found)
	{
		CWaitDlgThread* pThread = (CWaitDlgThread*)thread;
		pThread->ShowWaitDlg(bShow);
	}
	LeaveCriticalSection(&list_threads_protect);
}

void AFX_EXT_API aplEndWaitDlg(long thread)
{
	//Sleep(5000);
	if(thread==0) return;
	int i;
	bool found=false;
	EnterCriticalSection(&list_threads_protect);
	for(i=0;i<list_threads.GetSize();i++)
	{
		if(list_threads[i]==thread)
		{
			found = true;
			break;
		}
	}
	if(found)
	{
		SetEvent(((CWaitDlgThread*)thread)->m_event_End);
		((CWaitDlgThread*)thread)->m_pDlgWnd=NULL;  // Чтобы перестал вызываться SetText
	}
	LeaveCriticalSection(&list_threads_protect);


	//Если здесь поставить только AfxGetMainWnd()->SetForegroundWindow(), то будет нарушена модальность многих диалогов!!!!
/*
	CWnd *wnd=AfxGetMainWnd()->GetForegroundWindow();
	if(wnd!=0)
	{
		//wnd->SetActiveWindow();
		wnd->SetForegroundWindow( );
	}
*/
	CWaitDlgThread::st_iCurrentThreadCounter--;
}

