/*********************************************************************************************
 * Copyright 2004 - Volian Enterprises, Inc. All rights reserved.
 * Volian Enterprises - Proprietary Information - DO NOT COPY OR DISTRIBUTE
 * ------------------------------------------------------------------------------
 * $Workfile: ZipFuncs.cs $     $Revision: 2 $
 * $Author: Kathy $   $Date: 8/10/04 9:12a $
 *
 * $History: ZipFuncs.cs $
 * 
 * *****************  Version 2  *****************
 * User: Kathy        Date: 8/10/04    Time: 9:12a
 * Updated in $/LibSource/Utils
 * force copy for backup of zip file on checks (was crashing)
 * 
 * *****************  Version 1  *****************
 * User: Kathy        Date: 7/27/04    Time: 8:35a
 * Created in $/LibSource/Utils
 *********************************************************************************************/
using System;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using System.Collections.Specialized;
namespace Utils
{
	/// 
	/// Zip and UnZip functions.
	/// 
	public class ZipFuncs
	{
		[DllImport("Kernel32.DLL")]	public static extern uint GetDriveType(char[] lpRootPathName);
		private CDZipNET dzip;
		private CDUnZipNET duzip;
		private string _strZipPathAndFile; // full path and zip file name
		private bool _CancelZip;
		private bool _zipOnRemovable; // i.e. floppy disk
		private int _ArchiveType; // Full or Partial
		private string _strZipFileExcludeList; // what not to zip
		private string _strComment; // user's zip comment
		private string _strFilesToArchive; // what to zip up
		private string _strArcTitle; // user's archive title
		private string _strDestPath; // place to unzip to
		//#define DRIVE_UNKNOWN     0
		//#define DRIVE_NO_ROOT_DIR 1
		//#define DRIVE_REMOVABLE   2
		//#define DRIVE_FIXED       3
		//#define DRIVE_REMOTE      4
		//#define DRIVE_CDROM       5
		//#define DRIVE_RAMDISK     6
		private enum DriveType
		{
			DRIVE_UNKNOWN=0,
			DRIVE_NO_ROOT_DIR,
			DRIVE_REMOVABLE,
			DRIVE_FIXED,
			DRIVE_REMOTE,
			DRIVE_CDROM,
			DRIVE_RAMDISK
		}
		private enum ZipTypes
		{
			Full=0,
			Partial=1
		}
		// Contstructor for an existing Zip file
		public ZipFuncs(string iZipFile)
		{
			_strZipPathAndFile = iZipFile;
			SetupDestinationPath();
			_CancelZip = false;
			// populate local variables with Zip file's 
			// Title, Archive type, and Comment
			GetZipCommentInformation();
		}
		// Constructor for a new Zip file
		public ZipFuncs()
		{
			_strZipPathAndFile = "";
			_CancelZip = false;
		}
		//public properties
		public string strArcTitle
		{
			get { return _strArcTitle; }
			set {_strArcTitle = value.ToString(); }
		}
		public string strZipPathAndFile
		{
			get { return _strZipPathAndFile;}
			set 
			{ 
				_strZipPathAndFile = value.ToString();
				SetupDestinationPath();
				// populate local variables with Zip file's 
				// Title, Archive type, and Comment
				GetZipCommentInformation();
			}
		}
		public string strUnZipDestPath
		{
			get { return _strDestPath; }
			set
			{
				_strDestPath = value.ToString();
			}
		}
		public bool CancelZip
		{
			get { return _CancelZip;}
			set { _CancelZip = value; }
		}
		public bool zipOnRemovable
		{
			get { return _zipOnRemovable;}
			set { _zipOnRemovable = value;}
		}
		public int ArchiveType
		{
			get { return _ArchiveType;}
			set { _ArchiveType = value; }
		}
		public string strFilesToArchive
		{
			get { return _strFilesToArchive; }
			set { _strFilesToArchive = value.ToString(); }
		}
		public string strZipFileExcludeList
		{
			get { return _strZipFileExcludeList; }
			set { _strZipFileExcludeList = value.ToString(); }
		}
		public string strComment
		{
			get {return _strComment;}
			set 
			{
//				if (value == null)
//					_strComment = "";
//				else
					_strComment = (value == null)?"":value.ToString(); 
			}
		}
		public bool CreateNewZipFile()
		{
			return _GenerateZipFile(true);
		}
		public bool UpdateZipFile()
		{
			return _GenerateZipFile(false);
		}
		private bool _GenerateZipFile(bool NewFileFile)
		{
			StringBuilder cmntTxt = new StringBuilder();
			bool rtnval;
			ZipFuncsDlg zpDlg = new ZipFuncsDlg();
			dzip = new CDZipNET();
			_CancelZip = false;
			_zipOnRemovable = IsARemovableDisk();
			// Setup DynaZip
			// build comment field text
			cmntTxt.Append(_strArcTitle);
			cmntTxt.Append("\n");
			if (_ArchiveType == (int)ZipFuncs.ZipTypes.Partial)
			{
				// Do not recurse the sub directories when doing a partial archive
				cmntTxt.Append("PARTIAL\n");
				dzip.RecurseFlag = false;
			}
			else
			{
				cmntTxt.Append("FULL\n");
				dzip.RecurseFlag = true;
			}
			cmntTxt.Append(_strComment);
			dzip.AddCommentFlag = true;
			dzip.Comment = cmntTxt.ToString(); // zip file comment string
			// CompressionFactors 10 - 19 are not compatable with older zip programs
			// (i.e WinZip 7.0)
			dzip.CompressionFactor = 9; // maxium compression
			dzip.ExcludeFollowingFlag = true;
			dzip.ExcludeFollowing = _strZipFileExcludeList;
			dzip.ItemList = _strFilesToArchive;
			dzip.LargeZIPFilesFlag = true;
			dzip.ZIPFile = _strZipPathAndFile; // zip file name with full path
			
			// Is the target zip path on a removable dirve?
			if (_zipOnRemovable)
			{
				dzip.MultiVolumeControl = CDZipNET.MULTIVOLCONTROL.MV_USEMULTI;
			}
			else
			{
				dzip.MultiVolumeControl = CDZipNET.MULTIVOLCONTROL.MV_NONE;
			}
			// setup status bars
			dzip.MajorStatusFlag = true;
			dzip.MinorStatusFlag = true;
			dzip.ZipMajorStatus += new CDZipNET.OnZipMajorStatus(zpDlg.ZipMajorStatus_event);
			dzip.ZipMinorStatus += new CDZipNET.OnZipMinorStatus(zpDlg.ZipMinorStatus_event);
			_CancelZip = false;
			zpDlg.Show();
			// Do the Zip function
			if (!NewFileFile)
				dzip.ActionDZ = CDZipNET.DZACTION.ZIP_UPDATE; //update existing zip file
			else
				dzip.ActionDZ = CDZipNET.DZACTION.ZIP_ADD; // create new zip file
			rtnval = (zpDlg.DialogResult == System.Windows.Forms.DialogResult.OK);
			zpDlg.Dispose();
	
			// check for errors during the zip function.
			if (rtnval)
				rtnval = CheckZipErrorCode();
			// if we are zipping to a different location than the current procedure
			// set directory, we always want to return false so that this newly 
			// created zip file is not placed in the VE-PROMS tree.
			if (_zipOnRemovable || ZipFileNotInCurrentDirectory())
				rtnval = false;
			return rtnval;
		}
		// If there is a problem with the Zip file header, try to fix it.
		private bool FixZipFile()
		{
			bool rtnval;
			string ZipFileName = _strZipPathAndFile;
			string backupName = ZipFileName.Substring(0,ZipFileName.LastIndexOf(".")) + ".bku";
			_CancelZip = false;
			// save a copy of the zip file
			File.Copy(ZipFileName,backupName,true);
			dzip.FixFlag = true;
			dzip.ActionDZ = CDZipNET.DZACTION.ZIP_UPDATE;
			if (dzip.ErrorCode == CDZipNET.ZIPRESPONSE.ZE_FORM )
			{
				dzip.FixFlag = false;
				dzip.FixHarderFlag = true;
				dzip.ActionDZ = CDZipNET.DZACTION.ZIP_UPDATE;
				dzip.FixHarderFlag = false;
			}
			rtnval = (dzip.ErrorCode == 0); // 0 = success
			if (!rtnval)
			{
				// not successful, so restore from the backup file
				File.Copy(backupName,ZipFileName,true);
			}
			File.Delete(backupName); // delete the backup file
			return rtnval;
		}
		private bool CheckZipErrorCode()
		{
			bool rtnval;
			switch (dzip.ErrorCode)
			{
				case CDZipNET.ZIPRESPONSE.ZE_OK: // ZE_OK
					rtnval = true;
					break;
				case CDZipNET.ZIPRESPONSE.ZE_FORM: // ZE_FORM
				case CDZipNET.ZIPRESPONSE.ZE_TEST: // ZE_TEST
					// Internal organization of ZIP file is dammaged.
					// Try using the Fix function
					// note that you cannot do the fix on removable media
					if (!zipOnRemovable)
						rtnval = FixZipFile();
					else
						rtnval = false;
					break;
				case CDZipNET.ZIPRESPONSE.ZE_ABORT: // ZE_ABORT
					rtnval = false;
					break;
				default:
					rtnval = false;
					break;
			}
			return rtnval;
		}
		// If there is a problem with the Zip file header, try to fix it.
		private bool FixUnZipFile()
		{
			bool rtnval;
			string ZipFileName = _strZipPathAndFile;
			string backupName = ZipFileName.Substring(0,ZipFileName.LastIndexOf(".")) + ".bku";
			_CancelZip = false;
			dzip = new CDZipNET();
			dzip.ZIPFile = duzip.ZIPFile;
			// save a copy of the zip file
			File.Copy(ZipFileName,backupName,true);
			dzip.FixFlag = true;
			dzip.ActionDZ = CDZipNET.DZACTION.ZIP_UPDATE;
			if (dzip.ErrorCode == CDZipNET.ZIPRESPONSE.ZE_FORM)
			{
				dzip.FixFlag = false;
				dzip.FixHarderFlag = true;
				dzip.ActionDZ = CDZipNET.DZACTION.ZIP_UPDATE;
				dzip.FixHarderFlag = false;
			}
			rtnval = (dzip.ErrorCode == CDZipNET.ZIPRESPONSE.ZE_OK); // 0 = success
			dzip.Dispose();
			if (!rtnval)
			{
				// not successful, so restore from the backup file
				File.Copy(backupName,ZipFileName,true);
			}
			File.Delete(backupName); // delete the backup file
			return rtnval;
		}
		private bool CheckUnZipErrorCode()
		{
			bool rtnval;
			switch (duzip.ErrorCode)
			{
				case CDUnZipNET.UNZIPRESPONSE.UE_OK: // UE_OK
					rtnval = true;
					break;
				case CDUnZipNET.UNZIPRESPONSE.UE_STRUCT: // UE_STRUCT
					// Internal organization of ZIP file is dammaged.
					// Try using the Fix function
					rtnval = FixUnZipFile();
					break;
				case CDUnZipNET.UNZIPRESPONSE.UE_ABORT: // UE_ABORT
				case CDUnZipNET.UNZIPRESPONSE.UE_CANCEL: // UE_CANCEL
					rtnval = false;
					break;
				default:
					rtnval = false;
					break;
			}
			return rtnval;
		}
		public bool AddZipCommentInformation()
		{
			StringBuilder cmntTxt = new StringBuilder();
			dzip = new CDZipNET();
			_CancelZip = false;
			// Save the current attributes of the zip file, update zip file
			// and then restore attributes
			// - the zip file might be readonly
			System.IO.FileAttributes saveAttribs = File.GetAttributes(_strZipPathAndFile);
			File.SetAttributes(_strZipPathAndFile,FileAttributes.Normal);
			// add comment
			cmntTxt.Append(_strArcTitle);
			cmntTxt.Append("\n");
			if (_ArchiveType == (int)ZipTypes.Partial)
				cmntTxt.Append("PARTIAL\n");
			else
				cmntTxt.Append("FULL\n");
			cmntTxt.Append(_strComment);
			dzip.AddCommentFlag = true;
			dzip.Comment = cmntTxt.ToString();
			dzip.ZIPFile = _strZipPathAndFile; // zip file name with full path
			dzip.ActionDZ = CDZipNET.DZACTION.ZIP_ADD;
			File.SetAttributes(_strZipPathAndFile,saveAttribs);
			return CheckZipErrorCode();
		}
		public bool GetZipCommentInformation()
		{
			int x;
			string ZipComment;
			string strArcType;
			_CancelZip = false;
			if (!(File.Exists(_strZipPathAndFile)))
				return false; // !!! no zip file
			duzip = new CDUnZipNET();
			duzip.ZIPFile = _strZipPathAndFile; // zip file name with full path
			duzip.ActionDZ = CDUnZipNET.DUZACTION.UNZIP_GETCOMMENTSIZE;
			if (!CheckUnZipErrorCode())
				return false; // error
			if (duzip.ReturnCount <= 0)
				return false; // no comment informat
			duzip.ActionDZ = CDUnZipNET.DUZACTION.UNZIP_GETCOMMENT;
			ZipComment = duzip.ReturnString;
			x = ZipComment.IndexOf("\n");
			if (x < 0) return false; // nothing in comment
			_strArcTitle = ZipComment.Substring(0,x);
			ZipComment = ZipComment.Substring(x+1);
			x = ZipComment.IndexOf("\n");
			if (x > 0)
			{
				strArcType = ZipComment.Substring(0,x);
				if (strArcType.Equals("FULL"))
					_ArchiveType = (int)ZipTypes.Full;
				else
					_ArchiveType = (int)ZipTypes.Partial;
				_strComment = ZipComment.Substring(x+1);
			}
			else
			{
				// at this point, default to a full archive
				_ArchiveType = (int)ZipTypes.Full;
				// default to path and filename for the comment
				_strComment = _strZipPathAndFile;
			}
			return true;
		}
		private bool IsARemovableDisk()
		{
			uint DrvType;
			string tmp = _strZipPathAndFile.Substring(0,2);
			DrvType = GetDriveType(tmp.ToCharArray());
			return (DrvType.Equals((uint)DriveType.DRIVE_REMOVABLE));
		}
		private bool ZipFileNotInCurrentDirectory()
		{
			string curdir = Directory.GetCurrentDirectory();
			string tmpstr = _strZipPathAndFile.ToUpper();
			if (tmpstr.EndsWith(".ZIP"))
				tmpstr = tmpstr.Substring(0,tmpstr.LastIndexOf("."));
			return tmpstr.Equals(curdir);
		}
		public bool UnzipFromZipFile()
		{
			return _UnzipFromZipFile(true); // unzip from the archive
		}
		public bool TestTheZipFile()
		{
			return _UnzipFromZipFile(false); // test the archive
		}
		private bool _UnzipFromZipFile(bool ExtractFiles)
		{
			StringBuilder cmntTxt = new StringBuilder();
			bool rtnval;
			ZipFuncsDlg zpDlg = new ZipFuncsDlg();
			//			StringBuilder cmntTxt = new StringBuilder();
			//			VEO_Archive arc = (VEO_Archive) _CurObj;
			duzip = new CDUnZipNET();
			_zipOnRemovable = IsARemovableDisk();
			// Setup DynaZip
			// zip file name with full path
			duzip.ZIPFile = _strZipPathAndFile;
			//root of drive letter
//			duzip.Destination = Path.GetPathRoot(_strZipPathAndFile); 
			duzip.Destination = _strDestPath; 
			// what files to get from the zip file
			duzip.Filespec = "*.*"; // get all files
			//Replace - this combination of flags results in unzipping all files whether
			//          they were changed or not.
			duzip.FreshenFlag = false;
			duzip.UpdateFlag = false;
			// Make a reference to a single byte to avoid null access
			duzip.MemoryBlock = new Byte[1];
			// true = Overwrite non-read only files without asking
			duzip.OverwriteFlag = true;
			// true = proceed to unzip by traversing into folders
			duzip.RecurseFlag = true;
			duzip.UnzipSubOptions = CDUnZipNET.UNZIPSUBOPTION.USO_NONE;
			// set this option to allow the overwriting of ReadOnly Files.
			// this option only has meaning when the OverwriteFlag property
			// is set to true
			duzip.UnzipSubOptions |= CDUnZipNET.UNZIPSUBOPTION.USO_OVERWRITE_RO;
			// allow the MinorCancel event to respond to cancel requests
			duzip.UnzipSubOptions |= CDUnZipNET.UNZIPSUBOPTION.USO_MINORCANCEL;
			// debug
//			duzip.DiagnosticFlag = true;
//			duzip.UnzipSubOptions |= CDUnZipNET.UNZIPSUBOPTION.USO_LOGZIPRESULTS;
			// setup status bars
			duzip.MajorStatusFlag = true;
			duzip.MinorStatusFlag = true;
			duzip.MessageCallbackFlag = true;
			duzip.UnZipMajorStatus += new CDUnZipNET.OnUnZipMajorStatus(zpDlg.ZipMajorStatus_event);
			duzip.UnZipMinorStatus += new CDUnZipNET.OnUnZipMinorStatus(zpDlg.ZipMinorStatus_event);
			_CancelZip = false;
			zpDlg.Show(); // display the status dialog
			if (!ExtractFiles)
				duzip.TestFlag = true; // don't extract, only test each item in zip file
			// Do the UnZip function
			duzip.ActionDZ = CDUnZipNET.DUZACTION.UNZIP_EXTRACT;
			rtnval = (zpDlg.DialogResult == System.Windows.Forms.DialogResult.OK);
			zpDlg.Dispose();
	
			// check for errors during the unzip function.
			if (!CheckUnZipErrorCode())
					return false; // error
			if (duzip.ReturnCount <= 0)
				return false; // nothing unzipped
			return rtnval;
		}
		public StringCollection ZipFileContents()
		{
			StringCollection ZipFileList = new StringCollection();
			StringBuilder cmntTxt = new StringBuilder();
			duzip = new CDUnZipNET();
			_zipOnRemovable = false;
			// Setup DynaZip
			// zip file name with full path
			duzip.ZIPFile = _strZipPathAndFile;
			// what files to get from the zip file
			duzip.Filespec = "*.*"; // get all files
			//Replace - this combination of flags results in unzipping all files whether
			//          they were changed or not.
			duzip.FreshenFlag = false;
			duzip.UpdateFlag = false;
			// Make a reference to a single byte to avoid null access
			duzip.MemoryBlock = new Byte[1];
			_CancelZip = false;
			// Do the UnZip function
			duzip.ActionDZ = CDUnZipNET.DUZACTION.UNZIP_COUNTALLZIPMEMBERS;
			int numItems = duzip.ReturnCount;
			string str_tmpDate;
			string str_tmpFileName;
			for (int i=0;i 0)
			{
				// Adjust the destination path based on the full or partial
				// path in the zip file
				char [] trmchar = {'\\'};
				duzip.ActionDZ = CDUnZipNET.DUZACTION.UNZIP_GETNEXTNAMEDZIPINFO;
				str_tmpFileName = duzip.zi_FileName;
				// trim off the file name
				str_tmpFileName = str_tmpFileName.ToUpper();
				str_tmpFileName = str_tmpFileName.Substring(0,str_tmpFileName.LastIndexOf("PROC.INI"));
				// trim off any backslash
				str_tmpFileName = str_tmpFileName.TrimEnd(trmchar);
				str_tmpFileName = str_tmpFileName.ToUpper();
				if (str_tmpFileName.Length > 0)
				{
					if (strDestPath.LastIndexOf(str_tmpFileName) > 0)
						strDestPath = strDestPath.Substring(0,strDestPath.Length - str_tmpFileName.Length);
				}
			}
			_strDestPath = strDestPath;
			return;
		}
	}
}