// MFileFindDlg.cpp : implementation file
//

#include "stdafx.h"
#include "MFileFind.h"
#include "MFileFindDlg.h"

#include "LookFor.h"

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

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMFileFindDlg dialog

CMFileFindDlg::CMFileFindDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CMFileFindDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CMFileFindDlg)
	m_LookIn = _T("");
	m_Named = _T("");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMFileFindDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CMFileFindDlg)
	DDX_Control(pDX, IDC_FOUNDIST, m_FoundList);
	DDX_Text(pDX, IDC_LOOKIN, m_LookIn);
	DDX_Text(pDX, IDC_NAMED, m_Named);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CMFileFindDlg, CDialog)
	//{{AFX_MSG_MAP(CMFileFindDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_FIND, OnFind)
	ON_BN_CLICKED(IDC_STOP, OnStop)
	ON_WM_SIZE()
	ON_WM_CLOSE()
	//}}AFX_MSG_MAP
     ON_MESSAGE(WM_MYFOUND, OnFound)
 END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMFileFindDlg message handlers

BOOL CMFileFindDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	m_FoundList.InsertColumn(0, "Name" );
	m_FoundList.InsertColumn(1, "In Folder" );
	m_FoundList.InsertColumn(2, "Size" );
	m_FoundList.InsertColumn(3, "Modified" );
	CRect Rect;
	m_FoundList.GetClientRect( &Rect );
	m_FoundList.SetColumnWidth( 0, Rect.right / 3 );
	m_FoundList.SetColumnWidth( 1, Rect.right / 3 );
	m_FoundList.SetColumnWidth( 2, Rect.right / 8 );
	m_FoundList.SetColumnWidth( 3, Rect.right / 6 );

	char * pPath = m_LookIn.GetBuffer( _MAX_PATH );
	GetCurrentDirectory( _MAX_PATH, pPath );
	m_LookIn.ReleaseBuffer();
	UpdateData( FALSE );

	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CMFileFindDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CMFileFindDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CMFileFindDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

// This is the function that will execute in the child thread, to do 
// the actual file finding.
UINT DoFind( LPVOID pParam )
{
	static int Depth;
	CTime Time;
	CString GenStr;
	BOOL MoreFiles;

	Depth++;
	CLookFor* pLookFor = (CLookFor*)pParam;
	CFileFind Find;

	// Step 1: Find matching files in Folder
	CString Path;
	Path = pLookFor->GetPath();
	if( Path.IsEmpty() )
	{
		char * pPath = Path.GetBuffer( _MAX_PATH );
		GetCurrentDirectory( _MAX_PATH, pPath );
		Path.ReleaseBuffer();
	}

	if( Path[ Path.GetLength()-1 ] != '\\' )
		Path += "\\";
	Path += pLookFor->GetNamed();

	if( Find.FindFile( Path ) )
	{
		do 
		{
			MoreFiles = Find.FindNextFile();
			GenStr = Find.GetFileName();
			if( GenStr.CompareNoCase(".")==0 || GenStr.CompareNoCase("..") ==0 )
				continue;

			pLookFor->AddFound( Find );

		} while( MoreFiles && !pLookFor->IsCanceled() );
	}

	// Step 2: Look for Sub-directories
	Path = pLookFor->GetPath();
	if( Path.IsEmpty() )
	{
		char * pPath = Path.GetBuffer( _MAX_PATH );
		GetCurrentDirectory( _MAX_PATH, pPath );
		Path.ReleaseBuffer();
	}

	if( Path[ Path.GetLength()-1 ] != '\\' )
		Path += "\\";
	Path += "*.*";

	if( Find.FindFile( Path ) )
	{
		do 
		{
			MoreFiles = Find.FindNextFile();
			GenStr = Find.GetFileName();
			if( GenStr.CompareNoCase(".")==0 || GenStr.CompareNoCase("..") ==0 )
				continue;
			if( Find.IsDirectory() )
			{
				CLookFor Next;
				CString Tmp;
				Tmp = pLookFor->GetPath();
				if( Tmp[ Tmp.GetLength()-1] != '\\' )
					Tmp.Format( "%s\\%s", (LPCSTR)pLookFor->GetPath(), (LPCSTR)GenStr );
				else
					Tmp.Format( "%s%s", (LPCSTR)pLookFor->GetPath(), (LPCSTR)GenStr );
				Next.SetPath(Tmp);
				DoFind( &Next );
			}
		} while( MoreFiles && !pLookFor->IsCanceled() );
	}

	Depth--;
	if( Depth == 0 ) // Last call
		pLookFor->Stop();
	return( 1 );
}


// User hit Find button.  Disable button and start child thread
void CMFileFindDlg::OnFind() 
{
	m_FoundList.DeleteAllItems();
	UpdateData();
	m_Start.SetData( m_Named, m_LookIn, GetDlgItem( IDC_FIND )->m_hWnd, GetDlgItem( IDC_STOP )->m_hWnd );
	m_Start.Start();
	AfxBeginThread( DoFind, (LPVOID)&m_Start );
}

// User hit the Stop button.  Cancel the child thread and timer
void CMFileFindDlg::OnStop() 
{
	m_Start.Cancel();	
}

// On Resize, readjust size of the list
void CMFileFindDlg::OnSize(UINT nType, int cx, int cy) 
{
	CDialog::OnSize(nType, cx, cy);

	if( m_FoundList.GetSafeHwnd() )
	{
		CRect Pos;
	
		m_FoundList.GetWindowRect( Pos );
		ScreenToClient(&Pos);
		m_FoundList.SetWindowPos( 0, 0, 0, cx-Pos.left*2, cy-Pos.top-Pos.left, SWP_NOMOVE|SWP_NOZORDER);
	}
	
}

// If user closes dialog, make sure we terminate child thread
void CMFileFindDlg::OnClose() 
{
	// Tell thread to terminate, then wait for it to terminate
	m_Start.Cancel();
	while( m_Start.IsRunning() )
		;
	CDialog::OnClose();
}

// On a 'MyFound' message, get the found items, and add to List Control
void CMFileFindDlg::OnFound(WPARAM wp, LPARAM lp)
{
	// Use Critical section to safegaurd the m_FoundList collection
	m_Start.Lock();
	
	int Index;
	while( m_Start.m_Found.GetSize() )
	{
		Index = m_FoundList.InsertItem( m_FoundList.GetItemCount(), m_Start.m_Found.GetAt(0) );
		m_FoundList.SetItemText( Index, 1, m_Start.m_Found.GetAt(1) );
		m_FoundList.SetItemText( Index, 2, m_Start.m_Found.GetAt(2) );
		m_FoundList.SetItemText( Index, 3, m_Start.m_Found.GetAt(3) );
		m_Start.m_Found.RemoveAt(0, 4 );
	}

	m_Start.Unlock();
}

void CMFileFindDlg::OnOK() 
{
	// There is no OK button, but we do this because the ENTER
	// key would normally close the Dialog, and instead we want
	// it to trigger the Find button.
	if( GetDlgItem( IDC_FIND )->IsWindowEnabled() )
		OnFind();	
}
