// WaitDlg.cpp : implementation file
//

#include "stdafx.h"
#include "WaitDlg.h"
#include <apl_gui.h>

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

CUIntArray list_threads;
CRITICAL_SECTION list_threads_protect;



/////////////////////////////////////////////////////////////////////////////
// CTransportWaitDlg dialog
#define m_class_info _T("")

CTransportWaitDlg::CTransportWaitDlg(CWnd* pParent /*=NULL*/)
: CaplTranslateDialog(CTransportWaitDlg::IDD, pParent)
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);

	InitializeCriticalSection(&m_text_operate);

	//{{AFX_DATA_INIT(CTransportWaitDlg)
	m_txt =  APL_T("Ждем ответ сервера");
	//}}AFX_DATA_INIT
	m_thread = 0;
	m_pClient = 0;
	m_idx = 0;
	m_can_break = true;
	m_is_percentage_changed = 0;	
	m_percentage = 0;
	is_res_load  =FALSE;
	m_external_use=false;
	m_new_text = _T("");
	m_is_break = 0;
	m_img_lst = (CImageList*)aplGetWaitDlgImgLst();
	m_last_icon=0;

	//OutputDebugString("** CTransportWaitDlg::CTransportWaitDlg\n");

}

CTransportWaitDlg::~CTransportWaitDlg()
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);

	//OutputDebugString("** CTransportWaitDlg::~CTransportWaitDlg\n");
	if(m_pClient!=0){
		m_pClient->m_wt_dlg = 0;
	}
	if(m_last_icon!=0) DestroyIcon(m_last_icon);
	DeleteCriticalSectionODS(&m_text_operate);
}


void CTransportWaitDlg::DoDataExchange(CDataExchange* pDX)
{
	CaplTranslateDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CTransportWaitDlg)
	DDX_Control(pDX, IDC_MY_TEXT, m_CtrlTxt);
	DDX_Control(pDX, IDC_PROGRESSBAR, m_ProgressBar);
	DDX_Control(pDX, IDC_BTN_BREAK, m_CtrlBtnBreak);
	DDX_Control(pDX, IDC_WAIT_IMG, m_img);
	DDX_Text(pDX, IDC_MY_TEXT, m_txt);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CTransportWaitDlg, CaplTranslateDialog)
//{{AFX_MSG_MAP(CTransportWaitDlg)
ON_BN_CLICKED(IDC_BTN_BREAK, OnBtnBreak)
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTransportWaitDlg message handlers


void CTransportWaitDlg::OnBtnBreak() 
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);

	// TODO: Add your control notification handler code here
	if(m_external_use)
	{
		SetBreak(true);
	}
	else
	{
		if(m_pClient!=0)
		{
			m_pClient->SetBreak(true);
		}
		OnOK();
	}
}

void CTransportWaitDlg::OnTimer(UINT nIDEvent) 
{
	//OutputDebugString("** CTransportWaitDlg::OnTimer\n");
	if(ID_TIMER_WAIT_DLG_OPERATE==nIDEvent)
	{
		if(m_img_lst!=0)
		{
			m_idx++; if(m_idx>8) m_idx=0;
			m_last_icon=m_img_lst->ExtractIcon(m_idx/3);
			HICON old_ico=m_img.SetIcon(m_last_icon);
			if(old_ico != 0)DestroyIcon(old_ico);
		}

		if(m_external_use)
		{
			//OutputDebugString("** CTransportWaitDlg::OnTimer 1\n");
			if(IsBreak() || m_thread->IsNeedDelete())
			{
				CaplStackLogger stack_logger(_T("void CTransportWaitDlg::OnTimer(UINT nIDEvent) - 1"), true);

				// основная нить ставит флаг и посылает PostMessage этому диалогу внутри критической секции
				// ставим ограничение - а то диалог может обработать флаг и завершиться до того, как основная функция отработает PostMessage
				EnterCriticalSectionODS(&list_threads_protect);
				LeaveCriticalSectionODS(&list_threads_protect);
				OnOK();
				return;
			}
		}
		else
		{
			//OutputDebugString("** CTransportWaitDlg::OnTimer 2\n");
			if(m_pClient==0)
			{
				CaplStackLogger stack_logger(_T("void CTransportWaitDlg::OnTimer(UINT nIDEvent) - 2"),true);
				// уф, класс умер, нам тоже не жить
				OnOK();
				return;
			}
			else if(m_pClient->m_NeedAutoDelete)
			{
				CaplStackLogger stack_logger(_T("void CTransportWaitDlg::OnTimer(UINT nIDEvent) - 3"),true);
				// уф, класс должен быстро умереть, нам тоже не жить
				OnOK();
				return;
			}
			else
			{
				if(m_pClient->IsReadyData())
				{
					CaplStackLogger stack_logger(_T("void CTransportWaitDlg::OnTimer(UINT nIDEvent) - IsReadyData()"),true);
					int buf=0,size;
					size=m_pClient->m_LastReadyData;
					LogDebugMessageIfDefFormat1(_T("timer ID_TIMER_BLOCK - Ready Data; size data %i"),size);
					/**/
					int res=m_pClient->Receive(&buf,4,MSG_PEEK);
					LogDebugMessageIfDef(res!=-1? APL_T("timer ID_TIMER_BLOCK - прокачали удачно"): APL_T("Client: timer ID_TIMER_BLOCK - прокачали неудачно"));
				}
			}
			//LogDebugMessageIfDef(_T("CTransportWaitDlg.OnTimer  ");
			if(m_pClient->IsBreakWaitData())
			{
				CaplStackLogger stack_logger(_T("void CTransportWaitDlg::OnTimer(UINT nIDEvent) - m_pClient->IsBufferFull()"),true);
				// ага, пока пользователь тормозил, пришли данные с сервера! Поздно кнопочки жать!
				OnOK();
				return;
			}		
		}

		if(InterlockedExchange(&m_is_percentage_changed,0)==1)
		{
			//OutputDebugString("** CTransportWaitDlg::OnTimer 4\n");
			LogDebugMessageIfDef( APL_T("устанавливаем процентаж на диалоге"));
			int percentage=InterlockedExchangeAdd(&m_percentage,0);
			LogDebugMessageIfDef( APL_T("установили процентаж на диалоге"));
			if(m_is_minimize)
			{
				CRect rect;
				m_is_minimize=false;
				GetWindowRect(&rect);
				rect.bottom=rect.top+(m_max_size.bottom-m_max_size.top);
				MoveWindow(rect);
			}
			if(percentage<0)percentage=0;
			if(percentage>99)percentage=99;
			m_ProgressBar.SetPos(percentage);
			CString str;
			str.Format( APL_T("Обработка данных - выполнено %i %%"), percentage);
			SetWindowText(str);
		}
		EnterCriticalSectionODS(&m_text_operate);
		if(m_new_text != _T(""))
		{
			m_CtrlTxt.SetWindowText(m_new_text);
			m_new_text = _T("");
		}
		LeaveCriticalSectionODS(&m_text_operate);

		// если сервер не отвечает слишком долго при сохранении - то надо дать возможность прервать процесс
		// задаем таймаут в 5 минут
		if(m_can_break)
		{
			if(m_start_tick_timer.CheckTimeOut(1000*60*5))
			{
				m_CtrlBtnBreak.EnableWindow(TRUE);
			}
		}

	}
	//OutputDebugString("** CTransportWaitDlg::OnTimer end\n");
	CaplTranslateDialog::OnTimer(nIDEvent);
}

void CTransportWaitDlg::OnOK() 
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);

	//OutputDebugString(_T("** CTransportWaitDlg::OnOK\n"));
	KillTimer(ID_TIMER_WAIT_DLG_OPERATE);
	CaplTranslateDialog::OnOK();
	DestroyWindow();
}


BOOL CTransportWaitDlg::OnInitDialog() 
{
	//OutputDebugString(_T("** CTransportWaitDlg::OnInitDialog\n"));
	if(0==m_pClient && !m_external_use)return FALSE;

	CaplStackLogger stack_logger(__APL_FUNC__,true);

	CaplSetResourceHandle res_handle(module_inst);

	CaplTranslateDialog::OnInitDialog();
	
	m_CtrlBtnBreak.EnableWindow(m_can_break);

	m_start_tick_timer.Start();

	CRect rect,rect1;
	int len;
	
	// определяем высоту текста и подгоняем высоту диалога
	CPaintDC dc(this); // device context for painting
	CSize sz = dc.GetTextExtent(m_txt); //размеры строки
	m_CtrlTxt.GetWindowRect(&rect);
	ScreenToClient(&rect);
	int rect_width=rect.Width();
	if(rect.Width()>sz.cx)
	{
		// уменьшаем длину на
		len=rect.Width()-sz.cx;
		if(len>140)len = 140;
		// сама строка - сначала горизонтальный размер
		rect.right -= len;
		// потом вертикальный
		rect.top += 8;
		m_CtrlTxt.MoveWindow(&rect);
		// диалог
		GetWindowRect(&rect);
		rect.right -= len/2;
		rect.left += len/2;
		MoveWindow(&rect);
		// кнопка
		m_CtrlBtnBreak.GetWindowRect(&rect);
		ScreenToClient(&rect);
		rect.left -= len;
		rect.right -= len;
		m_CtrlBtnBreak.MoveWindow(&rect);
		// прогресс
		m_ProgressBar.GetWindowRect(&rect);
		ScreenToClient(&rect);
		rect.right -= len;
		m_ProgressBar.MoveWindow(&rect);
	}
	else if(rect.Width() == sz.cx)
	{
	}
	else
	{
		DWORD style = GetWindowLong(m_CtrlTxt.m_hWnd, GWL_STYLE);
		SetWindowLong(m_CtrlTxt.m_hWnd, GWL_STYLE, style ^ SS_CENTERIMAGE);
	}


	// определяем вертикальныен размеры и прячем прогресс-бар до вызова SetProgressRstio
	m_CtrlBtnBreak.GetWindowRect(&rect);
	m_ProgressBar.GetWindowRect(&rect1);
	len = rect1.bottom - rect.bottom;
	GetWindowRect(&rect);
	m_max_size = rect;
	rect.bottom -= len;
	MoveWindow(&rect);
	m_is_minimize = true;
	m_ProgressBar.SetRange(0,100);
	
	SetTimer(ID_TIMER_WAIT_DLG_OPERATE,INTERVAL_TIMER_WAIT_DLG_OPERATE,0);
	//SetForegroundWindow();
	//SetActiveWindow( );
	//OutputDebugString("** CTransportWaitDlg::OnInitDialog end\n");
	return TRUE;  // return TRUE unless you set the focus to a control
	// EXCEPTION: OCX Property Pages should return FALSE
}

void CTransportWaitDlg::SetBreak(bool param)
{
	CaplStackLogger stack_logger(__APL_FUNC__, true);

	long par;
	if(param){ par=1; }else{ par=0; };
	InterlockedExchange(&m_is_break, par);
	DEBUG_BEEP(1000,100);
}

bool CTransportWaitDlg::IsBreak()
{
	return (InterlockedExchange(&m_is_break,0)==1);
}

// void CTransportWaitDlg::SetNeedDelete(bool param)
// {
// 	if(m_thread==0) return;
// 	m_thread->SetNeedDelete(param);
// }

// bool CTransportWaitDlg::IsNeedDelete()
// {
// 	if(m_thread==0) return true;
// 	return m_thread->IsNeedDelete();
// }


void CTransportWaitDlg::OnCancel() 
{
	//OutputDebugString("** CTransportWaitDlg::OnCancel\n");
	///	CaplTranslateDialog::OnCancel();
}

void CTransportWaitDlg::SetProgressRatio(int percentage)
{
	LogDebugMessageIfDef( APL_T("устанавливаем процентаж"));
	InterlockedExchange(&m_percentage,percentage);
	InterlockedExchange(&m_is_percentage_changed,1);
	LogDebugMessageIfDef( APL_T("устанавили процентаж"));
}

void CTransportWaitDlg::SetText(LPCTSTR text)
{
	EnterCriticalSectionODS(&m_text_operate);
	m_new_text=text;
	LeaveCriticalSectionODS(&m_text_operate);
}

/////////////////////////////////////////////////////////////////////////////
// CTransportWaitDlgThread

IMPLEMENT_DYNCREATE(CTransportWaitDlgThread, CWinThread)

CTransportWaitDlgThread::CTransportWaitDlgThread()
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);

	m_Text = _T("");
	m_dlg = 0;
	m_event_delete = CreateEvent(0,TRUE,FALSE,_T(""));
	m_main_wnd = 0;
}

CTransportWaitDlgThread::~CTransportWaitDlgThread()
{
	CaplStackLogger stack_logger(__APL_FUNC__, true);

	int i;
	EnterCriticalSectionODS(&list_threads_protect);
	for(i=0;i<list_threads.GetSize();i++)
	{
		if(list_threads[i] == (long)this)
		{
			list_threads.RemoveAt(i);
			break;
		}
	}
	LeaveCriticalSectionODS(&list_threads_protect);
	CloseHandle(m_event_delete);
}


BOOL CTransportWaitDlgThread::InitInstance()
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);

	DWORD res;
	//OutputDebugString("** CTransportWaitDlgThread::InitInstance\n");
	// диалог запустится не раньше, чем через 3 секунды
	// а если надо прервать отработку диалога - установят event и мы сразу закончим эту нить
	res = WaitForSingleObject(m_event_delete, 3000);
	//OutputDebugString("** CTransportWaitDlgThread::InitInstance 1\n");

	switch(res)
	{
	case WAIT_FAILED:
	case WAIT_OBJECT_0:
		// сигнальное состояние эвента, выходим из функции
		return FALSE;
		break;
	case WAIT_TIMEOUT:
		// таймаут вышел, показываем диалог
		break;
	}

//	Перестановку ресурсов перенес в OnInitDialog и переделал на использование иконок бочек из apl_gui
// 	HINSTANCE hInstOld = AfxGetResourceHandle();
// 	AfxSetResourceHandle(module_inst);

	CTransportWaitDlg dlg;
	dlg.m_thread = this;
	if(m_Text != _T(""))
	{
		dlg.m_txt = m_Text;
	}
	dlg.m_external_use = true;
	m_pMainWnd = &dlg;
	m_dlg = &dlg;

	dlg.DoModal();
	
//	AfxSetResourceHandle(hInstOld);
	m_dlg=0;

	//OutputDebugString("** CTransportWaitDlgThread::InitInstance 3\n");
	return FALSE;
}

int CTransportWaitDlgThread::ExitInstance()
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);

	//OutputDebugString("** CTransportWaitDlgThread::ExitInstance()\n");
	// TODO:  perform any per-thread cleanup here
	return CWinThread::ExitInstance();
}

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

/////////////////////////////////////////////////////////////////////////////
// CTransportWaitDlgThread message handlers

void CTransportWaitDlgThread::SetNeedDelete(bool param)
{
	CaplStackLogger stack_logger(__APL_FUNC__, true);

	if(param)
	{
		SetEvent(m_event_delete);
	}
	else
	{
		ResetEvent(m_event_delete);
	};
}

bool CTransportWaitDlgThread::IsNeedDelete()
{
	DWORD res = WaitForSingleObject(m_event_delete, 0);
	return (res == WAIT_FAILED || res == WAIT_OBJECT_0);
}

/*
UINT WaitDlgThreadProc(LPVOID lpParameter){
}
*/
long AFX_EXT_API StartTransportWaitDlg(LPCTSTR text)
{
	CTransportWaitDlgThread *thread = (CTransportWaitDlgThread *)AfxBeginThread(RUNTIME_CLASS(CTransportWaitDlgThread), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
	thread->m_Text = text;
	thread->m_main_wnd=AfxGetMainWnd();
	thread->ResumeThread();
	EnterCriticalSectionODS(&list_threads_protect);
	list_threads.Add((long) thread);
	LeaveCriticalSectionODS(&list_threads_protect);
	return (long) thread;
}

bool AFX_EXT_API IsBreakTransportWaitDlg(long thread)
{

	if(thread==0) return false;

	bool is_break = false;
	bool found = false;
	int i;
	EnterCriticalSectionODS(&list_threads_protect);
	for(i=0;i<list_threads.GetSize();i++)
	{
		if(list_threads[i] == thread)
		{
			found = true;
			break;
		}
	}
	if(found)
	{
		if(((CTransportWaitDlgThread*)thread)->m_dlg!=0)
		{
			found = ((CTransportWaitDlgThread*)thread)->m_dlg->IsBreak();
		}
		else
		{
			found = false;
		}
	}
	LeaveCriticalSectionODS(&list_threads_protect);

	return found;
}

bool AFX_EXT_API SetTransportWaitDlgText(long thread, LPCTSTR text)
{
	if(thread == 0) return false;
	bool found = false;
	int i;
	EnterCriticalSectionODS(&list_threads_protect);
	for(i=0;i<list_threads.GetSize();i++)
	{
		if(list_threads[i]==thread)
		{
			found = true;
			break;
		}
	}
	if(found)
	{
		if(((CTransportWaitDlgThread*)thread)->m_dlg!=0)
		{
			(((CTransportWaitDlgThread*)thread)->m_dlg)->SetText(text);
		}
	}
	LeaveCriticalSectionODS(&list_threads_protect);

	return true;
}

void AFX_EXT_API EndTransportWaitDlg(long thread, bool foreground_main_wnd)
{
	int count=0;

	if(thread==0) return;

	bool found = false;
	int i;
	EnterCriticalSectionODS(&list_threads_protect);
	for(i=0;i<list_threads.GetSize();i++)
	{
		if(list_threads[i]==thread)
		{
			found = true;
			break;
		}
	}
	if(found)
	{
		CTransportWaitDlgThread* wdt=(CTransportWaitDlgThread*)thread;
		if(wdt!=0)
		{
			wdt->SetNeedDelete(true);
			/*
			HANDLE hThread=wdt->m_hThread;
			CWnd* main_wnd=wdt->m_main_wnd;
			// окно зачастую не успевает создаться, тогда PostMessage вызывает ошибку
			// кроме того там таймер очень частый, нет смысла в дополнительном подстегивании
	// 		if(wdt->m_dlg!=0){
	// 			wdt->m_dlg->PostMessage(WM_TIMER,ID_TIMER_WAIT_DLG_OPERATE,0);
	// 		}

			if(main_wnd!=0 && foreground_main_wnd)
			{
				//main_wnd->SetForegroundWindow( );
				//main_wnd->SetActiveWindow( );
			}
			*/
		}

	}
	LeaveCriticalSectionODS(&list_threads_protect);



// 	DWORD exit_code;
// 	int counter=0;
// 	while(true){
// 		if(!GetExitCodeThread(hThread,&exit_code)){
// 			break;
// 		}
// 		if(exit_code!=STILL_ACTIVE){
// 			break;
// 		}
// 		Sleep(10);
// 		counter++;
// 	}
// 	exit_code=0;
}
