// UnmasswDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Unmassw.h"
#include "UnmasswDlg.h"
#include "UnmassAboutDlg.h"
#include "ChArchType.h"

#include <direct.h>
#include <assert.h>
#include <process.h>
#include <stdio.h>
#include <io.h>

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

/////////////////////////////////////////////////////////////////////////////
// CUnmasswDlg dialog


CUnmasswDlg::CUnmasswDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CUnmasswDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CUnmasswDlg)
	m_info = _T("");
	m_info2 = _T("");
	//}}AFX_DATA_INIT
}

void CUnmasswDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CUnmasswDlg)
	DDX_Control(pDX, IDC_COMBOselTypes, m_SelTypes);
	DDX_Control(pDX, IDC_PROGRESS1, m_progress);
	DDX_Control(pDX, IDC_BUTTONdir, m_DirButton);
	DDX_Control(pDX, IDC_LISTfiles, m_list);
	DDX_Text(pDX, IDC_STATICinfo, m_info);
	DDX_Text(pDX, IDC_STATICinfo2, m_info2);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CUnmasswDlg, CDialog)
	//{{AFX_MSG_MAP(CUnmasswDlg)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTONopen, OnBUTTONopen)
	ON_BN_CLICKED(IDC_BUTTONextract, OnBUTTONextract)
	ON_BN_CLICKED(IDC_BUTTONdir, OnBUTTONdir)
	ON_WM_DESTROY()
	ON_BN_CLICKED(IDC_BUTTONabout, OnBUTTONabout)
	ON_NOTIFY(LVN_COLUMNCLICK, IDC_LISTfiles, OnColumnclickLISTfiles)
	ON_WM_SIZE()
	ON_WM_CREATE()
	ON_NOTIFY(NM_DBLCLK, IDC_LISTfiles, OnDblclkLISTfiles)
	ON_BN_CLICKED(IDC_BUTTONselAdd, OnBUTTONselAdd)
	ON_BN_CLICKED(IDC_BUTTONselRem, OnBUTTONselRem)
	ON_BN_CLICKED(IDC_BUTTONaddFile, OnBUTTONaddFile)
	ON_BN_CLICKED(IDC_BUTTONaddDir, OnBUTTONaddDir)
	ON_BN_CLICKED(IDC_BUTTONunlinkFile, OnBUTTONunlinkFile)
	ON_BN_CLICKED(IDC_BUTTONdelFile, OnBUTTONdelFile)
	ON_BN_CLICKED(IDC_BUTTONcreateArchive, OnBUTTONcreateArchive)
	ON_WM_CLOSE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CUnmasswDlg message handlers

#define BUTTON_OPEN_STRING "&Open .."
#define BUTTON_CLOSE_STRING "C&lose"

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

	icon = LoadIcon( AfxGetInstanceHandle(), MAKEINTRESOURCE( IDR_MAINFRAME ) );
	SetIcon( icon, true );		// Set big icon
	SetIcon( icon, false );		// Set small icon


	ArchiveOpened = 0;

	int		i;

	GetModuleFileName( NULL, ProgramPath, 512 );
	i = strlen( ProgramPath ) - 1;
	while (( ProgramPath[ i ] != '\\' ) && ( ProgramPath[ i ] != '/' ))
		i--;
	ProgramPath[ i ] = 0;

	strcpy( TempDir, ProgramPath );
	strcat( TempDir, "\\TEMP" );

	// ======== init =====
	m_list.SetExtendedStyle( LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES );
	
	m_list.InsertColumn( 0, "#", LVCFMT_LEFT, 40 );
	m_list.InsertColumn( 1, "file", LVCFMT_LEFT, 280 );
	m_list.InsertColumn( 2, "size", LVCFMT_LEFT, 70 );
	m_list.InsertColumn( 3, "type", LVCFMT_LEFT, 50 );

	FileInfo = NULL;
//	FileInfo.SetVariableSize( sizeof( CMassArchive::s_FileRec ) );
	InListPos = NULL;

	m_progress.ShowWindow( false );
	m_progress.SetRange( 0, 100 );
	m_progress.SetPos( 23 );

	SetWindowText( NAME_VER );

	m_info = NAME_VER" created by Mirex";

	getcwd( OutputDir, MaxPathLength );
	strcpy( OpenDir, OutputDir );

	sort_displayed = sort_undefined;

	InitWndPositions();

	UpdateData( false );
	return TRUE;  // return TRUE  unless you set the focus to a control
}

// 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 CUnmasswDlg::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, icon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

HCURSOR CUnmasswDlg::OnQueryDragIcon()
{
	return (HCURSOR) icon;
}

void CUnmasswDlg::OnBUTTONopen() 
{
	unsigned long	l, i, j;
	CString			filter, cstr, cstr2, ext;
	int				res;

	//ak je otvoreny tak close
	if ( ArchiveOpened == 1 ) {

		CloseArchive();

	}

	chdir( OpenDir );

	filter = "All files *.*|*.*|";
	for( i=0; i<mass.massftypes_count; i++ ) {
		cstr.Format( "%s|", mass.GetTypeIdentString( i ) );
		
		//GetTypeExt moze vratit aj viac pripon, musim po jednom pridat
		ext = mass.GetTypeExt( i );
		j = l = 0;
		while ( true ) {
			while (( l < ext.GetLength() ) && ( ext.GetAt( l ) != ',' ))
				l++;
			cstr2.Format( "*.%s", ext.Mid( j, l - j ) );
			cstr += cstr2;

			if ( l == ext.GetLength() )
				break;
			else
				cstr += "; ";
			j = l + 1;
			l = j;
		} ;

		cstr += "|";

		filter += cstr;
	}

	filter += "||";

	CFileDialog		dlg( true, NULL, NULL, 0, filter, this );

	if ( dlg.DoModal() == IDOK ) { 

		CloseArchive();

		OpenArchive( dlg.GetPathName().GetBuffer(0) );
		
	}
}

void CUnmasswDlg::OnBUTTONextract() 
{
	POSITION		pos = m_list.GetFirstSelectedItemPosition();
	int				nItem;
	unsigned long	count = 0, files;

	files = m_list.GetSelectedCount();

	if ( files == 0 ) {
		m_info = "No files selected";
		UpdateData( false );
		return;
	}

	GetDlgItem( IDC_STATICinfo )->ShowWindow( false );
	m_progress.ShowWindow( true );
	m_progress.SetPos( 0 );
	UpdateData( false );

	while ( pos != NULL ) {
		
		nItem = InListPos[ m_list.GetNextSelectedItem(pos) ];

		memcpy( &mass.FileRec, &FileInfo[nItem].FileRec, sizeof( CMassArchive::s_FileRec ) );
		sprintf( mass.FileRec.name, "%s\\%s",
			OutputPath.GetBuffer(0), FileInfo[nItem].FileRec.name );

/*		mass.FileRec.offset = FileInfo[ nItem ].FileRec.offset;
		mass.FileRec.size = FileInfo[ nItem ].FileRec.size;
		mass.FileRec.flag = FileInfo[ nItem ].FileRec.flag;
		strcpy( mass.FileRec.type, FileInfo[ nItem ].FileRec.type );
*/
		if ( mass.Extract() == 0 ) {
			MessageBox( mass.error );
			break;
		}

		count++;

		m_progress.SetPos( count*100 / files );
		UpdateData( false );
	} ;

	m_progress.ShowWindow( false );
	GetDlgItem( IDC_STATICinfo )->ShowWindow( true );
	m_info.Format( "%lu files extracted. Stopped at file #%lu", count, nItem );
	UpdateData( false );
}

void CUnmasswDlg::OnBUTTONdir() 
{
	CFileDialog		dlg( true, NULL, "this one", OFN_NOVALIDATE, "Choose output directory|mirex rules!||", this );
	CString			path;
	int				pos;

	chdir( OutputDir );

	if ( dlg.DoModal() == IDOK ) {

		getcwd( OutputDir, MaxPathLength );

		path = dlg.GetPathName();

		pos = path.ReverseFind( '\\' );
		if ( pos == -1 ) 
			return;

		path.Delete( pos, path.GetLength() - pos );

		m_DirButton.SetWindowText( path.GetBuffer(0) );

		OutputPath = path;
	}

	m_list.SetFocus();
}


void CUnmasswDlg::OnDestroy() 
{
	int			res, findh;
	_finddata_t	find;
	char		str[ 512 ];

	CDialog::OnDestroy();
	
	m_info = "Deleting temp files";
	UpdateData( false );

	//find all temp files and delete them !
	sprintf( str, "%s\\*.*", TempDir );
	res = findh = _findfirst( str, &find );
	
	while ( res != -1 ) {

		if (( strcmp( find.name, "." ) != 0 ) && ( strcmp( find.name, ".." ) != 0 )) {
			sprintf( str, "%s\\%s", TempDir, find.name );
			remove( str );
		}

		res = _findnext( findh, &find );
	}
	
	_findclose( findh );

	CloseArchive();

}

void CUnmasswDlg::OnBUTTONabout() 
{
	CUnmassAboutDlg	dlg;

	dlg.DoModal();
		
}

void CUnmasswDlg::OnColumnclickLISTfiles(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	
	switch ( pNMListView->iSubItem ) {
	case 0: sort = sort_unsorted; break;
	case 1:	sort = sort_name; break;
	case 2:	sort = sort_size; break;
	case 3:	sort = sort_type; break;
	default:
		assert( false );
		break;
	}
		
	FillListSorted( sort );

	*pResult = 0;
}

//ak je uz list zobrazeny, tak idem po jeho poradi. hodi sa tak, ze ked zosortujes 
//podla size a potom podla type, tak budes mat zoradene podla typu a tiez podla size
void CUnmasswDlg::FillListSorted( e_sort sorttype )
{
	unsigned long		i, it, j, p, size;
//	CDWordArray			sorted;
//	int					filled;
	char				str[ 256 ], 
						name[ CMassArchive::FileNameWithPathMaxLen ], 
						type[ CMassArchive::TypeMaxLen ];
//	CString				cstr;

	if ( sort_displayed == sorttype )
		return;

	UpdateData( );
	m_progress.ShowWindow( true );
	m_info = "Sorting...";
	UpdateData( false );

	if ( sorttype == sort_unsorted )
		for( i=0; i<mass.MassfInfo.files_count; i++ )
			InListPos[ i ] = i;
	else
		for( i=0; i<mass.MassfInfo.files_count; i++ ) {

//			cstr = "";
			name[0] = 127; type[0] = 127; size = MAXLONG;

			it = -1;
			//musim najst ktory zaznam sem vlozim podla kriteria
			for( j=i; j<mass.MassfInfo.files_count; j++ ) {
				switch( sorttype ) {
				case sort_name:
//					if ( cstr.CompareNoCase( FileInfo[ InListPos[ j ] ].FileRec.name ) < 0 ) {
					if ( UnmassTools::_strcasecmp( FileInfo[ InListPos[ j ] ].FileRec.name, name ) < 0 ) {
						it = j;
//						cstr = FileInfo[ InListPos[ j ] ].FileRec.name;
						strcpy( name, FileInfo[ InListPos[ j ] ].FileRec.name );
					}
					break;
				case sort_size:
					if ( FileInfo[ InListPos[ j ] ].FileRec.size < size ) {
						it = j;
						size = FileInfo[ InListPos[ j ] ].FileRec.size;
					}
					break;
				case sort_type:
//					if ( cstr.CompareNoCase( FileInfo[ InListPos[ j ] ].FileRec.type ) < 0 ) {
					if ( UnmassTools::_strcasecmp( FileInfo[ InListPos[ j ] ].FileRec.type, type ) < 0 ) {
						it = j;
//						cstr = FileInfo[ InListPos[ j ] ].FileRec.type;
						strcpy( type, FileInfo[ InListPos[ j ] ].FileRec.type );
					}
					break;
				default:
					assert( false );
					break;
				}//switch sorttype
			}

			assert( it != -1 );

			//takze mam poziciu itemu v InListPos. musim ho dat na poziciu i, a ostatne
			// posunut

			p = InListPos[ it ];
			for( j=it; j>i; j-- )
				InListPos[ j ] = InListPos[ j-1 ];

			InListPos[ i ] = p;

			//zobrazim progress
			if ( (i+1) % 500 == 0 ) {
				m_progress.SetPos( i * 100 / mass.MassfInfo.files_count );
				UpdateData( false );
			}

		}

	m_info = "Purging list";
	UpdateData( false );

	m_list.DeleteAllItems();

	m_info = "Displaying";
	UpdateData( false );

	for( i=0; i<mass.MassfInfo.files_count; i++ ) {

		it = InListPos[ i ];

		sprintf( str, "%lu", it );
		m_list.InsertItem( i, str );
		m_list.SetItemText( i, 1, FileInfo[ it ].FileRec.name );
		sprintf( str, "%lu", FileInfo[ it ].FileRec.size );
		m_list.SetItemText( i, 2, str );
		m_list.SetItemText( i, 3, FileInfo[ it ].FileRec.type );

		if ( (i+1) % 500 == 0 ) {
			m_progress.SetPos( i * 100 / mass.MassfInfo.files_count );
			UpdateData( false );
		}

	}

	m_progress.ShowWindow( false );

	m_info = "";
	UpdateData( false );

	sort_displayed = sorttype;
}

// ======= window sizing ========
void CUnmasswDlg::OnSize(UINT nType, int cx, int cy) 
{
	CDialog::OnSize(nType, cx, cy);

	SizeCtrls.Size();

	RedrawWindow();
}

void CUnmasswDlg::InitWndPositions( void )
{
	SizeCtrls.SetWindow( this );

	SizeCtrls.SetWndEdgeAssignment( IDC_BUTTONopen,
		top_left, top_left, right_bottom, right_bottom );

	SizeCtrls.SetWndEdgeAssignment( IDC_STATICinfo2,
		top_left, right_bottom, top_left, top_left );

	SizeCtrls.SetWndEdgeAssignment( IDC_BUTTONabout,
		right_bottom, right_bottom, top_left, top_left );

	SizeCtrls.SetWndEdgeAssignment( IDC_LISTfiles,
		top_left, right_bottom, top_left, right_bottom );

	SizeCtrls.SetWndEdgeAssignment( IDC_BUTTONextract,
		top_left, top_left, right_bottom, right_bottom );

	SizeCtrls.SetWndEdgeAssignment( IDC_BUTTONaddFile,
		top_left, top_left, right_bottom, right_bottom );

	SizeCtrls.SetWndEdgeAssignment( IDC_BUTTONaddDir,
		top_left, top_left, right_bottom, right_bottom );

	SizeCtrls.SetWndEdgeAssignment( IDC_BUTTONunlinkFile,
		top_left, top_left, right_bottom, right_bottom );

	SizeCtrls.SetWndEdgeAssignment( IDC_BUTTONdelFile,
		top_left, top_left, right_bottom, right_bottom );

	SizeCtrls.SetWndEdgeAssignment( IDC_BUTTONcreateArchive,
		top_left, top_left, right_bottom, right_bottom );

	SizeCtrls.SetWndEdgeAssignment( IDC_BUTTONdir,
		top_left, right_bottom, right_bottom, right_bottom );
	
	SizeCtrls.SetWndEdgeAssignment( IDC_STATICinfo,
		top_left, right_bottom, right_bottom, right_bottom );

	SizeCtrls.SetWndEdgeAssignment( IDC_PROGRESS1,
		top_left, right_bottom, right_bottom, right_bottom );
	//type selection: combo, add, remove
	SizeCtrls.SetWndEdgeAssignment( IDC_COMBOselTypes,
		right_bottom, right_bottom, top_left, top_left );

	SizeCtrls.SetWndEdgeAssignment( IDC_BUTTONselAdd,
		right_bottom, right_bottom, top_left, top_left );

	SizeCtrls.SetWndEdgeAssignment( IDC_BUTTONselRem,
		right_bottom, right_bottom, top_left, top_left );


/*	GetDlgItem( IDC_BUTTONopen )->GetWindowRect( &rct );
	SetMyWindowPosition( wnd_ButtonOpen, IDC_BUTTONopen,
		rct.left, top_left, rct.right, top_left, 
		rct.top, top_left, rct.bottom, top_left );

	GetDlgItem( IDC_STATICinfo2 )->GetWindowRect( &rct );
	SetMyWindowPosition( wnd_info2, IDC_STATICinfo2,
		rct.left, top_left, mainrct.right - rct.right, right_bottom, 
		rct.top, top_left, rct.bottom, top_left );

	GetDlgItem( IDC_BUTTONabout )->GetWindowRect( &rct );
	SetMyWindowPosition( wnd_ButtonAbout, IDC_BUTTONabout,
		mainrct.right - rct.left, right_bottom, mainrct.right - rct.right, right_bottom, 
		rct.top, top_left, rct.bottom, top_left );

	GetDlgItem( IDC_LISTfiles )->GetWindowRect( &rct );
	SetMyWindowPosition( wnd_list, IDC_LISTfiles,
		rct.left, top_left, mainrct.right - rct.right, right_bottom, 
		rct.top, top_left, mainrct.bottom - rct.bottom, right_bottom );

	GetDlgItem( IDC_BUTTONextract )->GetWindowRect( &rct );
	SetMyWindowPosition( wnd_ButtonExtract, IDC_BUTTONextract,
		rct.left, top_left, rct.right, top_left, 
		mainrct.bottom - rct.top, right_bottom, mainrct.bottom - rct.bottom, right_bottom );

	GetDlgItem( IDC_BUTTONdir )->GetWindowRect( &rct );
//	SetMyWindowPosition( wnd_ButtonOutDir, IDC_BUTTONdir,
//		rct.left, top_left, mainrct rct.right, right_bottom, 
//		mainrct.bottom - rct.top, right_bottom, mainrct.bottom - rct.bottom, right_bottom );

	SetWindowEdgeAssignment( wnd_ButtonOutDir, IDC_BUTTONdir,
		top_left, right_bottom, right_bottom, right_bottom );
	
	SetWindowEdgeAssignment( wnd_info, IDC_STATICinfo,
		top_left, right_bottom, right_bottom, right_bottom );

	SetWindowEdgeAssignment( wnd_progress, IDC_PROGRESS1,
		top_left, right_bottom, right_bottom, right_bottom );

	WndDataInitialized = 1;
*/
}

// ======= window sizing END ========

int CUnmasswDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CDialog::OnCreate(lpCreateStruct) == -1)
		return -1;
	
//	WndDataInitialized = 0;
	
	return 0;
}

void CUnmasswDlg::OnDblclkLISTfiles(NMHDR* pNMHDR, LRESULT* pResult) 
{
	POSITION		pos = m_list.GetFirstSelectedItemPosition();
	int				nItem, res;
	unsigned long	count = 0;//, files;
//	char			str[ 512 ];

	if ( pos != NULL ) {
		
		m_info = "Extracting file into temp directory";
		UpdateData( false );

		//create temp directory
		mkdir( TempDir );

		nItem = InListPos[ m_list.GetNextSelectedItem( pos ) ];

		memcpy( &mass.FileRec, &FileInfo[nItem].FileRec, sizeof( CMassArchive::s_FileRec ) );
		sprintf( mass.FileRec.name, "%s\\%s",
			TempDir, FileInfo[nItem].FileRec.name );

		if ( mass.Extract() == 0 )
			MessageBox( mass.error );
		else {
			//file is extracted. now run command
			
			m_info = "Running command...";
			UpdateData( false );

			res = (int) ShellExecute( NULL, "open", mass.FileRec.name, NULL, NULL, SW_SHOW );		

			if ( res > 32 )
				m_info = "previewing returned succes";
			else
				m_info = "previewing returned error, probably no program is assigned to filetype";
			UpdateData( false );
		}
	}

	*pResult = 0;
}

void CUnmasswDlg::OnBUTTONselAdd() 
{
	DoSelect( 1 );
}

void CUnmasswDlg::OnBUTTONselRem()  
{
	DoSelect( 0 );	
}

void CUnmasswDlg::DoSelect( int select )
{
	int				len, i, item;
	unsigned long	lu, state, count;

	CString			cstr;

	UpdateData();

	if ( select )
		state = LVIS_SELECTED;
	else
		state = 0;

	i = m_SelTypes.GetCurSel();
	if ( i == CB_ERR )
		return;

	item = m_SelTypes.GetItemData( i );
	if ( item != - 1 )
		len = strlen( FileInfo[ item ].FileRec.type );

	count = 0;

	for( lu=0; lu<mass.MassfInfo.files_count; lu++ )
		if (( item == -1 ) ||
			(( strlen( FileInfo[ InListPos[ lu ] ].FileRec.type ) == len ) &&
			 ( memcmp( FileInfo[ InListPos[ lu ] ].FileRec.type, 
				FileInfo[ item ].FileRec.type, len ) == 0 )
			)
			) {
//			m_list.SetItemState( InListPos[ lu ], state, LVIS_SELECTED );
			m_list.SetItemState( lu, state, LVIS_SELECTED );
			count++;
		}

	m_info.Format( "%sselected %lu files", select ? "" : "un", count );
	UpdateData( false );
}

void CUnmasswDlg::NewFileIntoList( unsigned long listpos )
{
	int		i, j, res;

	memcpy( &FileInfo[ listpos ].FileRec, &mass.FileRec, 
		sizeof( CMassArchive::s_FileRec ) );

	//ak modul sam nevyplna type, tak tam dam extension
	if (( mass.MassfInfo.flags & CMassArchive::ma_flag_fills_type ) == 0 ) {
		i = strlen( FileInfo[ listpos ].FileRec.name );
		while (( i > 0 ) && ( FileInfo[ listpos ].FileRec.name[ i-1 ] != '.' ))
			i--;

		if ( i == 0 )
			FileInfo[ listpos ].FileRec.type[0] = 0;
		else {
			j = strlen( FileInfo[ listpos ].FileRec.name ) - i;
			if ( j > CMassArchive::TypeMaxLen )
				j = CMassArchive::TypeMaxLen-1;
			memcpy( FileInfo[ listpos ].FileRec.type, &FileInfo[ listpos ].FileRec.name[ i ], j );
			FileInfo[ listpos ].FileRec.type[ j ] = 0;
		}
	}

	//pridam si typ do select comba
	res = m_SelTypes.FindStringExact( 0, FileInfo[ listpos ].FileRec.type );
	if (( res == CB_ERR ) && ( FileInfo[ listpos ].FileRec.type[0] == 0 ) &&
		( NoExtInCombo == 1 ))
		res = 0;

	if ( res == CB_ERR ) {
		m_SelTypes.SetItemData( 
			m_SelTypes.AddString( FileInfo[ listpos ].FileRec.type ), listpos );

		if ( FileInfo[ listpos ].FileRec.type[ 0 ] == 0 )
			NoExtInCombo = 1;
	}

}

int CUnmasswDlg::ReopenFileForWriting( void )
{
	long	attr, i;

	if ( mass.ReopenForWriting() == 0 ) {

		attr = GetFileAttributes( mass.MassfInfo.filenm );
		if ( attr == -1 ) {
			m_info = "Could not get file attributes";
			MessageBox( "Could not get file attributes" );
			return 0;
		}

		if ( attr & FILE_ATTRIBUTE_READONLY ) {
		
			i = MessageBox( "File is read only, I have to remove read-only attribute",
				NULL, MB_OKCANCEL | MB_ICONWARNING );

			if ( i == IDCANCEL ) {
				MessageBox( "Can't modify file with read-only attribute" );
				return 0;
			}

			attr = attr ^ FILE_ATTRIBUTE_READONLY;
			if ( SetFileAttributes( mass.MassfInfo.filenm, attr ) == 0 ) {
				MessageBox( "Could not set file attribute !!" );
				return 0;
			}

		} 
		else {
			MessageBox( "File error, cannot open for writing", NULL, MB_ICONERROR );
			return 0;
		}

	}

	return 1;
}

void CUnmasswDlg::OnBUTTONaddFile() 
{

#define FNAME_BUF_SIZE 20000

	CFileDialog		dlg( true, NULL, NULL, OFN_ALLOWMULTISELECT | OFN_ENABLESIZING | 
				OFN_FILEMUSTEXIST | OFN_HIDEREADONLY , "*.*|*.*||", this );
	POSITION		pos;
	CString			cstr;
	int				i, index, files, fi;
	s_FileInfo		*pFileInfo;
	unsigned long	*pul, files_before;
	int				res;
	char			fnamebuf[ FNAME_BUF_SIZE ];

	if ( ReopenFileForWriting() == 0 )
		return;

//	fnamebuf = ( char* ) malloc( FNAME_BUF_SIZE );
//	if ( fnamebuf == NULL ) {
//		MessageBox( "Not enough mem for allocating buffer" );
//		return;
//	}

//	dlg.m_ofn.Flags = | OFN_ENABLEHOOK;
	dlg.m_ofn.lpstrFile = fnamebuf;
	dlg.m_ofn.nMaxFile	= FNAME_BUF_SIZE;
	memset( fnamebuf, ' ', FNAME_BUF_SIZE );
	fnamebuf[ FNAME_BUF_SIZE-1 ] = 0;

	i = dlg.DoModal();
	fi = CommDlgExtendedError();

	if (( i == 2 ) && ( fi == 0x3003 ))
		MessageBox( "You have selected too many files ... try again" );

	if ( i == IDOK ) {  

		pos = dlg.GetStartPosition();
		files = 0;
		while( pos ) {
			dlg.GetNextPathName( pos );
			files++;
		}


		cstr.Format( "Are you sure to add %i file(s) ?", files );
		res = MessageBox( cstr, NAME_VER, MB_YESNO | MB_ICONQUESTION );
		if ( res == IDNO ) {
//			free( fnamebuf );
			return;
		}

		
		pos = dlg.GetStartPosition();
		index = -1;

		files_before = mass.MassfInfo.files_count;


		GetDlgItem( IDC_STATICinfo )->ShowWindow( false );
		m_progress.ShowWindow( true );
		m_progress.SetPos( 0 );
		UpdateData( false );

		fi = 0;

		while ( pos != NULL ) {
		
			m_progress.SetPos( fi * 100 / files );
			UpdateData( false );

			fi++;

			//filename
			cstr = dlg.GetNextPathName( pos );
			//get filename without path
			i = cstr.ReverseFind( '\\' );

			index = mass.AddFile( cstr.GetBuffer(0), 
				cstr.Right( cstr.GetLength() - i - 1 ).GetBuffer(0) );

			if ( index == -1 ) {
				cstr.Format( "Error adding file #%i", fi );
				MessageBox( cstr, "Error", MB_OK | MB_ICONEXCLAMATION );
				break;
			}

		}

		// ak sa pridali nejake subory, tak ich pridam do listu a presortujem
		//while je to preto aby som to mohol break-nut
		while ( index != -2 ) {
			//add into list
			pFileInfo = ( s_FileInfo* ) 
				realloc( FileInfo,
						sizeof( s_FileInfo ) * mass.MassfInfo.files_count );
			if ( pFileInfo == NULL ) {
				MessageBox( "Out of memory, cannot display new file" );
				break;
			}
			FileInfo = pFileInfo;

			pul = (unsigned long*) 
				realloc( InListPos, 
						sizeof( unsigned long ) * mass.MassfInfo.files_count );
			if ( pul == NULL ) {
				MessageBox( "Out of memory, cannot display new file" );
				break;
			}
			InListPos = pul;

			for( i=files_before; i<mass.MassfInfo.files_count; i++ ) {
				mass.ReadRec( i );
				NewFileIntoList( i );
			}

			//aby to presortovalo
			sort = sort_displayed;
			sort_displayed = sort_undefined;
			FillListSorted( sort );

			index = -2;
		}

		m_progress.ShowWindow( false );
		GetDlgItem( IDC_STATICinfo )->ShowWindow( true );

	}

//	free( fnamebuf );
}

void CUnmasswDlg::OnBUTTONaddDir() 
{

	CFileDialog		dlg( true, NULL, "this one", OFN_NOVALIDATE, "Choose directory|mirex rules!||", this );
//	char			path[ 4096 ];
	int				pos, oripathlen;

	CStringArray	dirs;
	CString			dir, cstr, cstr2, path;
	long			res, findh;
	_finddata_t		find;
	int				files_before, files, index, fi, i;
	s_FileInfo		*pFileInfo;
	unsigned long	*pul;


	chdir( OutputDir );

	if ( dlg.DoModal() == IDOK ) {

		if ( ReopenFileForWriting() == 0 )
			return;

		cstr = dlg.GetPathName();

		pos = cstr.ReverseFind( '\\' );
		if ( pos == -1 ) 
			return;

		cstr.Delete( pos, cstr.GetLength() - pos );

		path = cstr;
		oripathlen = path.GetLength();

/*
	CString		cstr;
	int			res;
	BROWSEINFO	bi;
	ITEMIDLIST	srcdir, *idl;
	char		pth[ MAX_PATH ];



	memset( &bi, 0, sizeof( bi ) );

	srcdir.
	bi.hwndOwner	= this->GetSafeHwnd();
	bi.pidlRoot		= &srcdir;
	bi.pszDisplayName	= pth;
	bi.lpszTitle	= NULL;
	bi.ulFlags		= BIF_BROWSEINCLUDEFILES | BIF_EDITBOX;
	bi.lpfn			= NULL;


	idl = SHBrowseForFolder( &bi );

	free( bi.pszDisplayName );

	if ( idl == NULL )
		return;
*/


		files = 0;

		dirs.Add( cstr );

		while ( dirs.GetSize() > 0 ) {

			dir = dirs.GetAt( 0 );
			dirs.RemoveAt( 0 );

			cstr = dir + "\\*.*";

			res = findh = _findfirst( cstr, &find );
			
			while ( res != -1 ) {

				if ( find.attrib & _A_SUBDIR ) {

					if (( strcmp( find.name, "." ) != 0 ) && 
						( strcmp( find.name, ".." ) != 0 ))
						
						dirs.Add( dir + "\\" + find.name );

				}
				else
					files++;
				
				res = _findnext( findh, &find );
			} ;

		} ;

		_findclose( findh );

		cstr.Format( "Are you sure to add this directory (containing %i files) ?", files );
		res = MessageBox( cstr, NAME_VER, MB_YESNO | MB_ICONQUESTION );
		if ( res == IDNO )
			return;

		files_before = mass.MassfInfo.files_count;

		// now go add `em

		GetDlgItem( IDC_STATICinfo )->ShowWindow( false );
		m_progress.ShowWindow( true );
		m_progress.SetPos( 0 );
		UpdateData( false );

		fi = 0;

		dirs.Add( path );

		while ( dirs.GetSize() > 0 ) {

			dir = dirs.GetAt( 0 );
			dirs.RemoveAt( 0 );

			cstr = dir + "\\*.*";

			res = findh = _findfirst( cstr, &find );
			
			while ( res != -1 ) {

				if ( find.attrib & _A_SUBDIR ) {

					if (( strcmp( find.name, "." ) != 0 ) && 
						( strcmp( find.name, ".." ) != 0 ))
						
						dirs.Add( dir + "\\" + find.name );

				}
				else {
					m_progress.SetPos( fi * 100 / files );
					UpdateData( false );

					fi++;
					if ( fi >= files )
						fi = 0;

					cstr = dir + "\\" + find.name;
					cstr2 = cstr;
					cstr2.Delete( 0, oripathlen+1 );

					index = mass.AddFile( cstr.GetBuffer(0), cstr2.GetBuffer(0) );

					if ( index == -1 ) {
						cstr2.Format( "Error adding file #%i\n(%s)\n%s",
							fi, cstr, mass.error );
						MessageBox( cstr2.GetBuffer(0), "Error", MB_OK | MB_ICONEXCLAMATION );
						dirs.RemoveAll();
						break;
					}

				}
				
				res = _findnext( findh, &find );
			} ;

			_findclose( findh );

		} ;


		// ak sa pridali nejake subory, tak ich pridam do listu a presortujem
		//while je to preto aby som to mohol break-nut
		while ( index != -2 ) {
			//add into list
			pFileInfo = ( s_FileInfo* ) 
				realloc( FileInfo,
						sizeof( s_FileInfo ) * mass.MassfInfo.files_count );
			if ( pFileInfo == NULL ) {
				MessageBox( "Out of memory, cannot display new file" );
				break;
			}
			FileInfo = pFileInfo;

			pul = (unsigned long*) 
				realloc( InListPos, 
						sizeof( unsigned long ) * mass.MassfInfo.files_count );
			if ( pul == NULL ) {
				MessageBox( "Out of memory, cannot display new file" );
				break;
			}
			InListPos = pul;

			for( i=files_before; i<mass.MassfInfo.files_count; i++ ) {
				mass.ReadRec( i );
				NewFileIntoList( i );
			}

			//aby to presortovalo
			sort = sort_displayed;
			sort_displayed = sort_undefined;
			FillListSorted( sort );

			index = -2;
		}

		m_progress.ShowWindow( false );
		GetDlgItem( IDC_STATICinfo )->ShowWindow( true );


	}
}

void CUnmasswDlg::OnBUTTONunlinkFile() 
{
	CString			cstr;
	int				res;
	POSITION		pos;
	int				nItem;
	unsigned long	fi, fc, i;

	if ( ReopenFileForWriting() == 0 )
		return;

	fc = m_list.GetSelectedCount();
	if ( fc == 0 ) {
		m_info = "No files selected";
		UpdateData( false );
		return;
	}

	cstr.Format( "Are you sure to unlink %i files ?", fc );
	res = MessageBox( cstr, NAME_VER, MB_YESNO | MB_ICONQUESTION );
	if ( res == IDNO )
		return;

	
	GetDlgItem( IDC_STATICinfo )->ShowWindow( false );
	m_progress.ShowWindow( true );
	m_progress.SetPos( 0 );
	UpdateData( false );

	pos = m_list.GetFirstSelectedItemPosition();
	fi = 0;

	cstr = "Success.";

	while ( pos != NULL ) {

		m_progress.SetPos( fi * 100 / fc );
		UpdateData( false );

		nItem = InListPos[ m_list.GetNextSelectedItem( pos ) ];

		if ( mass.UnlinkFile( nItem ) == 0 ) {
			cstr.Format( "Error unlinking file #%i. (%s)", nItem, mass.error );
			MessageBox( cstr, NULL, MB_ICONWARNING | MB_OK );
			break;
		}

		//odstranim subor z listu
		for( i=nItem; i<mass.MassfInfo.files_count; i++ )
			memcpy( &FileInfo[ i ], &FileInfo[ i+1 ], sizeof( s_FileInfo ) );

		//musim odstranit aj zo select listu, lebo inak by som dostaval zle indexy
		m_list.DeleteItem( nItem );
		pos = m_list.GetFirstSelectedItemPosition();

	} ;

	UpdateData( false );

	// resort
	sort = sort_displayed;
	sort_displayed = sort_undefined;
	FillListSorted( sort );

	m_info = cstr;

	GetDlgItem( IDC_STATICinfo )->ShowWindow( true );
	m_progress.ShowWindow( false );
}

void CUnmasswDlg::OnBUTTONdelFile() 
{

	if ( ReopenFileForWriting() == 0 )
		return;

	MessageBox( "Unsupported yet" );
/*
delete
*/


}

void CUnmasswDlg::OnBUTTONcreateArchive() 
{
	CString			filter, cstr, ext, cstr2;
	int				i, j, l, type;
	FILE			*f;
	CChArchType		ChooseArchType;

	CloseArchive();

	filter = "";
	for( i=0; i<mass.massftypes_count; i++ ) {

		if (( mass.Archive[ i ]->GetFlags() & CMassArchive::ma_flag_create_archive ) == 0 )
			continue;

		cstr.Format( "%s", 
			mass.Archive[ i ]->GetIdent() );

		ChooseArchType.data.Add( i );
		ChooseArchType.strings.Add( cstr );

	}

	if ( ChooseArchType.DoModal() == IDCANCEL )
		return;

	type = ChooseArchType.choice;
	if ( type == CB_ERR ) {
		MessageBox( "No type chosen" );
		return;
	}

	filter.Format( "%s|%s||", mass.Archive[ type ]->GetIdent(), 
		mass.TypeExtToWinDlgExt( type ) );


	CFileDialog		fd( true, mass.GetTypeFirstExt( type ), "file name", 
						OFN_OVERWRITEPROMPT, filter, this );

	i = fd.DoModal();
	if ( i == IDOK ) {

		f = fopen( fd.GetPathName().GetBuffer(0), "rb" );
		if ( f != NULL ) {
			fclose( f );

			l = MessageBox( "File already exists, overwrite ?", NULL, MB_YESNO );

			if ( l == IDNO )
				return;
		}

		i = mass.CreateNewArchive( fd.GetPathName().GetBuffer(0), type );
	
		if ( i == 0 ) {
			m_info = mass.error;
			UpdateData( false );
			MessageBox( mass.error, "Error creating archive", MB_ICONEXCLAMATION );
			return;
		}

//		MessageBox( "Archive created." );

		OpenArchive( fd.GetPathName().GetBuffer(0) );

	}
}

void CUnmasswDlg::CloseArchive()
{

	mass.Close();

	GetDlgItem( IDC_BUTTONaddFile	)->EnableWindow( false );
	GetDlgItem( IDC_BUTTONaddDir	)->EnableWindow( false );
	GetDlgItem( IDC_BUTTONunlinkFile)->EnableWindow( false );
	GetDlgItem( IDC_BUTTONdelFile	)->EnableWindow( false );

//	GetDlgItem( IDC_BUTTONcreateArchive	)->EnableWindow( true );
	
	GetDlgItem( IDC_BUTTONopen )->SetWindowText( BUTTON_OPEN_STRING );

	UpdateData( false );

	getcwd( OpenDir, MaxPathLength );

	m_info = "Purging list";
	UpdateData( false );

	m_list.DeleteAllItems();

	m_info = "Purging file info";
	UpdateData( false );

	if ( FileInfo != NULL ) {
		free( FileInfo );
		FileInfo = NULL;
	}
//	FileInfo.RemoveAll();

	if ( InListPos != NULL ) {
		free( InListPos );
		InListPos = NULL;
	}

	ArchiveOpened = 0;

	m_info = "";
	UpdateData( false );
}

int CUnmasswDlg::OpenArchive( char* filename )
{
	int		i, l;

	m_info = "Opening file";
	UpdateData( false );

	if ( ! mass.Open( filename ) ) {
		MessageBox( "Unknown file format...", "oops" );
		m_info2 = "Unsupported format...";
		return 0;
	}

	FileInfo = ( s_FileInfo* ) 
		malloc( sizeof( s_FileInfo ) * mass.MassfInfo.files_count );

	InListPos = (unsigned long*) 
		malloc( sizeof( unsigned long ) * mass.MassfInfo.files_count );

	if (( FileInfo == NULL ) || ( InListPos == NULL )) {
//		if ( InListPos == NULL ) {
		MessageBox( "Out of memory" );
		EndDialog( -1 );
		return 0;
	}

	m_info2.Format( "type: %s, files: %lu",
		mass.GetTypeIdentString( mass.MassfInfo.type ), 
		mass.MassfInfo.files_count );

	OutputPath.Format( "%s%s", mass.MassfInfo.filedir, 
		mass.MassfInfo.filename );

	m_DirButton.SetWindowText( OutputPath.GetBuffer(0) );

	m_SelTypes.ResetContent();					// selection types
	m_SelTypes.SetItemData( m_SelTypes.AddString( "*" ), -1 );
	// data budu ukazovat do listu na subor toho isteho typu

//		GetDlgItem( IDC_STATICinfo )->ShowWindow( false );
	m_progress.ShowWindow( true );

	m_info = "Loading file list";
	UpdateData( false );

	NoExtInCombo = 0;

	//prednahratie vsetkych zaznamov

	for( l=0; l<mass.MassfInfo.files_count; l++ ) {

		mass.ReadRecords();

		if ( (l+1) % 500 == 0 ) {
			m_progress.SetPos( l * 100 / mass.MassfInfo.files_count );
			UpdateData( false );
		}

	}

	for( l=0; l<mass.MassfInfo.files_count; l++ ) {

//			if ( l == 0 )
//				mass.ReadRec( 0 );
//			else
//				mass.ReadRec( -1 );
		mass.ReadRec( l );
/*
		memcpy( FileInfo[l].FileRec.name, mass.FileRec.name,
					FileNameWithPathMaxLen );
		FileInfo[l].FileRec.name[ FileNameWithPathMaxLen-1 ] = 0;
		FileInfo[l].FileRec.offset = mass.FileRec.offset;
		FileInfo[l].FileRec.size   = mass.FileRec.size;
		FileInfo[l].FileRec.flag   = mass.FileRec.flag;
		mass.FileRec.type[ TypeMaxLen-1 ] = 0;
		memcpy( FileInfo[l].FileRec.type, mass.FileRec.type, TypeMaxLen );
*/
//			FileInfo.Add( &mass.FileRec );

		NewFileIntoList( l );

		//put info about where am i in progress, often
		if ( (l+1) % 500 == 0 ) {
			m_progress.SetPos( l * 100 / mass.MassfInfo.files_count );
			UpdateData( false );
		}

	}

	m_progress.ShowWindow( false );

	m_info = "Displaying list";
	UpdateData( false );

	sort = sort_unsorted;
	sort_displayed = sort_undefined;
	FillListSorted( sort );

	m_info.Format( "name: [%s]", mass.MassfInfo.filenm );

//		GetDlgItem( IDC_STATICinfo )->ShowWindow( true );

	//vyberiem z ext listu '*'
	for( i=0; i<m_SelTypes.GetCount(); i++ )
		if ( m_SelTypes.GetItemData( i ) == -1 ) {
			m_SelTypes.SetCurSel( i );
			break;
		}

	if ( mass.MassfInfo.flags & CMassArchive::ma_flag_add_file )
		GetDlgItem( IDC_BUTTONaddFile )->EnableWindow( true );
	if ( mass.MassfInfo.flags & CMassArchive::ma_flag_add_file )
		GetDlgItem( IDC_BUTTONaddDir	)->EnableWindow( true );
	if ( mass.MassfInfo.flags & CMassArchive::ma_flag_unlink_file )
		GetDlgItem( IDC_BUTTONunlinkFile)->EnableWindow( true );
	if ( mass.MassfInfo.flags & CMassArchive::ma_flag_delete_file )
		GetDlgItem( IDC_BUTTONdelFile	)->EnableWindow( true );
	if ( mass.MassfInfo.flags & CMassArchive::ma_flag_create_archive )
		GetDlgItem( IDC_BUTTONcreateArchive	)->EnableWindow( true );

	ArchiveOpened = 1;
	GetDlgItem( IDC_BUTTONopen )->SetWindowText( BUTTON_CLOSE_STRING );

	UpdateData( false );

	if ( mass.MassfInfo.flags & 
		( CMassArchive::ma_flag_add_file | 
		CMassArchive::ma_flag_unlink_file | 
		CMassArchive::ma_flag_delete_file )) {

		MessageBox(
"Watch out !\n\
All changes are done real-time, so back-up your original files before changes !\n\
Although it should work, mistakes may happen and files might get damaged by accident.\n\
You have been warned !\n",
			"Be careful", MB_OK | MB_ICONEXCLAMATION );
	}

	return 1;
}

void CUnmasswDlg::OnCancel() 
{
	// Escape key does nothing
//	CDialog::OnCancel();
}

void CUnmasswDlg::OnClose() 
{
	// Closing program does OnCancel
	CDialog::OnClose();
	CDialog::OnCancel();
}
