/**************************************************************

senddumpfiles.h (C-Munipack project)
Function that packs crash dump files
Copyright (C) 2008 David Motl, dmotl@volny.cz

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

**************************************************************/

#include <gtk/gtk.h>

#include "senddumpfiles.h"
#include "main.h"

#ifdef _MSC_VER

#include <Windows.h>
#include <zip.h>

/*********************************************************************
   The following code is based on the sample code minizip.c
   That comes with the minizip library.
   See http://www.winimage.com/zLibDll/minizip.html
*/

#define WRITEBUFFERSIZE (16384)
#define MAXFILENAME (256)

static uLong filetime(const gchar *f, tm_zip *tmzip, uLong *dt)
{
	int ret = 0;
	FILETIME ftLocal;
	HANDLE hFind;
	WIN32_FIND_DATAA ff32;

	char *lpath = g_locale_from_utf8(f, -1, NULL, NULL, NULL);
	hFind = FindFirstFileA(lpath,&ff32);
	if (hFind != INVALID_HANDLE_VALUE) {
		FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
        FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
        FindClose(hFind);
        ret = 1;
	}
	g_free(lpath);
	return ret;
}

static bool zipFiles(const gchar *zipfile, const gchar *basedir, gchar **files, int nfile, GError **error)
{
    int size_buf = WRITEBUFFERSIZE;
    void *buf = (void*)g_malloc(size_buf);
    if (buf==NULL) {
		g_set_error(error, g_AppError, ZIP_INTERNALERROR, "Error allocating memory");
        return false;
    }

	char *zipfile_lpath = g_locale_from_utf8(zipfile, -1, NULL, NULL, NULL);
    zipFile zf = zipOpen(zipfile_lpath, 0);
	g_free(zipfile_lpath);
    if (zf == NULL) {
        g_set_error(error, g_AppError, ZIP_ERRNO, "error opening zip file");
		g_free(buf);
        return false;
    }

	int err = ZIP_OK;
    for (int i=0; i<nfile && err==ZIP_OK; i++) {
        const gchar* filenameinzip = files[i];
		gchar *fullpath = g_build_filename(basedir, filenameinzip, NULL);

		zip_fileinfo zi;
		memset(&zi, 0, sizeof(zip_fileinfo));
        filetime(fullpath,&zi.tmz_date,&zi.dosDate);

		/* The path name saved, should not include a leading slash. */
		/*if it did, windows/xp and dynazip couldn't read the zip file. */
		const gchar *savefilenameinzip = filenameinzip;
		while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' )
			savefilenameinzip++;
        /**/
		gchar *lpath = g_locale_from_utf8(savefilenameinzip, -1, NULL, NULL, NULL);
        err = zipOpenNewFileInZip3(zf,lpath,&zi,
			NULL,0,NULL,0,NULL,Z_DEFLATED,Z_DEFAULT_COMPRESSION,0,
			-MAX_WBITS,DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0);
		g_free(lpath);
        if (err == ZIP_OK) {
            FILE *fin = open_file(fullpath, "rb");
            if (fin) {
				int size_read;
				do {
					size_read = (int)fread(buf,1,size_buf,fin);
					if (size_read < size_buf && feof(fin)==0) {
						g_set_error(error, g_AppError, err, "Failed to read the file %s", filenameinzip);
						err = ZIP_ERRNO;
					} else if (size_read>0) {
						err = zipWriteInFileInZip (zf,buf,size_read);
						if (err != ZIP_OK)
							g_set_error(error, g_AppError, err, "Failed to write the file %s", zipfile);
					}
				} while (size_read>0 && err==ZIP_OK);
				fclose(fin);
			} else {
				g_set_error(error, g_AppError, err, "Failed to open the file %s", filenameinzip);
				err=ZIP_ERRNO;
			}
		}
		if (err < 0) {
			g_set_error(error, g_AppError, err, "Failed to create the file %s", zipfile);
            err=ZIP_ERRNO;
		}
        else {
            err = zipCloseFileInZip(zf);
            if (err!=ZIP_OK) {
				g_set_error(error, g_AppError, err, "Failed to create zip file %s", zipfile);
				g_free(buf);
				zipClose(zf,NULL);
				return false;
			}
        }
		g_free(fullpath);
	}
    g_free(buf);

	int errclose = zipClose(zf,NULL);
    if (errclose != ZIP_OK) {
        g_set_error(error, g_AppError, errclose, "Failed to create the file %s", zipfile);
		return false;
	}
	return true;
}

/*********************************************************************
   End of code based on the sample code minizip.c
**********************************************************************/

static GList *scanDir(const gchar *dirpath, const gchar *relpath=NULL, GList *list=NULL)
{
	GDir *dir = g_dir_open(dirpath, 0, NULL);
	if (dir) {
		// First process files in current directory
		const gchar *filename = g_dir_read_name(dir);
		while (filename) {
			gchar *filepath = g_build_filename(dirpath, filename, NULL);
			if (g_file_test(filepath, G_FILE_TEST_IS_REGULAR)) {
				gchar *ext = GetFileExtension(filename);
				if (StrCaseCmp0(ext, "xml")==0 || StrCaseCmp0(ext, "dmp")==0) 
					list = g_list_prepend(list, (relpath ? g_build_filename(relpath, filename, NULL) : g_strdup(filename)));
				g_free(ext);
			}
			g_free(filepath);
			filename = g_dir_read_name(dir);
		}
		// Go to subdirectories 
		g_dir_rewind(dir);
		filename = g_dir_read_name(dir);
		while (filename) {
			gchar *filepath = g_build_filename(dirpath, filename, NULL);
			if (g_file_test(filepath, G_FILE_TEST_IS_DIR)) {
				gchar *rpath = (relpath ? g_build_filename(relpath, filename, NULL) : g_strdup(filename));
				list = scanDir(filepath, rpath, list);
				g_free(rpath);
			}
			g_free(filepath);
			filename = g_dir_read_name(dir);
		}
		g_dir_close(dir);
	}
	return list;
}

bool haveDumpFiles()
{
	GList *files = scanDir(crashRptPath());
	if (files) {
		g_list_foreach(files, (GFunc)g_free, NULL);
		g_list_free(files);		
		return true;
	}
	return false;
}

bool zipDumpFiles(const gchar *fpath, GError **error)
{
	GList *files = scanDir(crashRptPath());
	if (files) {
		int count = g_list_length(files), i = 0;
		char **list = (char**)g_malloc(count*sizeof(char*));
		for (GList *ptr=files; ptr!=NULL; ptr=ptr->next) 
			list[i++] = g_locale_from_utf8((gchar*)ptr->data, -1, NULL, NULL, NULL);

		char *bpath = g_locale_from_utf8(crashRptPath(), -1, NULL, NULL, NULL);
		bool retval = zipFiles(fpath, bpath, list, count, error);
		g_free(bpath);

		for (int i=0; i<count; i++)
			g_free(list[i]);
		g_free(list);

		return retval;
	}
	return false;
}

#endif
