// CDXResourceDlg.cpp : implementation file
//

#include "stdafx.h"
#include "CDXResource.h"
#include "CDXResourceDlg.h"
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>

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

#define BLOCK_SIZE 16384

typedef struct
{
	long	offset;
	char	name[13];
} FILEENTRY, *LPFILEENTRY;

/////////////////////////////////////////////////////////////////////////////
// CDXResourceDlg dialog

CDXResourceDlg::CDXResourceDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CDXResourceDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CDXResourceDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
}

void CDXResourceDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CDXResourceDlg)
		// NOTE: the ClassWizard will add DDX and DDV calls here
	DDX_Control(pDX, IDC_LIST, m_ListBox);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CDXResourceDlg, CDialog)
	//{{AFX_MSG_MAP(CDXResourceDlg)
	ON_BN_CLICKED(IDC_INSERT, OnInsert)
	ON_BN_CLICKED(IDC_DELETE, OnDelete)
	ON_BN_CLICKED(IDC_SAVE, OnSave)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDXResourceDlg message handlers

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

	// TODO: Add extra initialization here
	
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////

void CDXResourceDlg::OnInsert()
{
  CString Filter = "All Files (*.*)|*.*||";
	CFileDialog FileDlg(TRUE, "*.*", NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, Filter, NULL);

	if(FileDlg.DoModal() == IDOK)
	{
		m_ListBox.AddString(FileDlg.GetFileName());
		m_FileArray.Add(FileDlg.GetPathName());
	}
}

/////////////////////////////////////////////////////////////////////////////

void CDXResourceDlg::OnDelete()
{
	if(m_ListBox.GetCount() <= 0) return;
	m_FileArray.RemoveAt(m_ListBox.GetCurSel());
	m_ListBox.DeleteString(m_ListBox.GetCurSel());
}

/////////////////////////////////////////////////////////////////////////////

void CDXResourceDlg::OnSave() 
{
	int nfiles = m_ListBox.GetCount();
 	if(nfiles <= 0)
	{
		MessageBox("You need to add some files", "Error", MB_OK|MB_ICONEXCLAMATION);
		return;
	}

	CString Filter = "Wad Files (*.wad)|*.wad|All Files (*.*)|*.*||";
	CFileDialog FileDlg(FALSE, "*.wad", NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, Filter, NULL);

	if(FileDlg.DoModal() == IDOK)
	{
		int infile;
		int outfile;
		int inbytes;
		int outbytes;
		int allfiles = nfiles + 1;
		LPFILEENTRY pfe = NULL;

		// Open the output file
		outfile = open(FileDlg.GetPathName(), O_RDWR | O_BINARY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
		if(outfile < 1)
		{
			MessageBox("Unable to create output file", "Error", MB_OK | MB_ICONEXCLAMATION);
			return;
		}

		// Get space for the buffer
		char *buffer;
		buffer = new char[BLOCK_SIZE];
		if(buffer == NULL)
		{
			MessageBox("Out of memory", "Error", MB_OK | MB_ICONEXCLAMATION);
			return;
		}

		// Get space for the file header
		pfe = new FILEENTRY[allfiles];
		if(pfe == NULL)
		{
			MessageBox("Out of memory", "Error", MB_OK | MB_ICONEXCLAMATION);
			return;
		}

		// Fill the file header
		for(int i = 0; i < nfiles; i++)
		{
			pfe[i].offset = 0;
			m_ListBox.GetText(i, pfe[i].name);
		}

		// Write the number of files
		outbytes = write(outfile, &allfiles, sizeof(int));
		if(outbytes != sizeof(int))
		{
			MessageBox("Error writing to output file", "Error", MB_OK | MB_ICONEXCLAMATION);
			close(outfile);
			return;
		}

		// Write the file header
		outbytes = write(outfile, pfe, allfiles * sizeof(FILEENTRY));
		if(outbytes != (int)(allfiles * sizeof(FILEENTRY)))
		{
			MessageBox("Error writing to output file", "Error", MB_OK | MB_ICONEXCLAMATION);
			close(outfile);
			return;
		}

		for(i = 0; i < nfiles; i++)
		{
			// Save files offset
			pfe[i].offset = lseek(outfile, 0, SEEK_CUR);
			if(pfe[i].offset < 0)
			{
				MessageBox("Seek error on output file", "Error", MB_OK | MB_ICONEXCLAMATION);
				close(outfile);
				return;
			}

			// Open the input file
			infile = open(m_FileArray.GetAt(i), O_RDONLY | O_BINARY, 0);
			if(outfile < 1)
			{
				MessageBox("Unable to open input file", "Error", MB_OK | MB_ICONEXCLAMATION);
				close(outfile);
				return;
			}

			while(1)
			{
				inbytes = read(infile, buffer, BLOCK_SIZE );
				if(inbytes == 0) break;
				if(inbytes < 0)
				{
					MessageBox("Error reading input file", "Error", MB_OK | MB_ICONEXCLAMATION);
					close(infile);
					close(outfile);
					return;
				}
	
				outbytes = write(outfile, buffer, inbytes);
				if(inbytes != outbytes)
				{
					MessageBox("Error writing to output file", "Error", MB_OK | MB_ICONEXCLAMATION);
					close(infile);
					close(outfile);
					return;
				}

				if(inbytes < BLOCK_SIZE) break;
			}

			close(infile);
		}
	
		// Write the file end
		strcpy(pfe[i].name, "EOF");
		pfe[i].offset = lseek(outfile, 0, SEEK_CUR);

		// Seek to the start of the file
		long pos = lseek(outfile, sizeof(int), SEEK_SET);
		if(pos != sizeof(int))
		{
			MessageBox("Seek error on output file", "Error", MB_OK | MB_ICONEXCLAMATION);
			close(outfile);
			return;
		}

		// Re-write the file header with offsets
		outbytes = write(outfile, pfe, allfiles * sizeof(FILEENTRY));
		if(outbytes != (int)(allfiles * sizeof(FILEENTRY)))
		{
			MessageBox("Error writing final header to output file", "Error", MB_OK | MB_ICONEXCLAMATION);
			close(outfile);
			return;
		}

		close(outfile);
	}
}
