/* ==========================================================================
* 작 성 자 : 이순규
* 작 성 일 : 2006.09.19
* 
* 내    용 : 파일 팩
* 주의사항 : 
*===========================================================================*/
#pragma once

#pragma warning( disable: 4819 )
#pragma warning( disable: 4996 )
#include "ZipArchive.h"
#include <atltime.h>

/// 파일 시간
class cFileTime : public CTime
{
public:
	cFileTime();
	cFileTime( time_t time );
	cFileTime( const FILETIME& time );

	const FILETIME& GetFileTime();

	void operator =( const cFileTime& that );

protected:
	FILETIME mFileTime;
};

/// 팩 안에 있는 파일의 정보
class cFileInPackInfo
{
	friend class cFilePack;

public:
	bool SetPathName( const cStringT& pathName );
	void SetWriteTime( const time_t& time );

	const cStringT& GetPathName() const;
	unsigned int GetSize() const;
	const cFileTime& GetWriteTime() const;
	bool IsDirectory() const;
	time_t GetUnixWriteTime();

private:
	void UpdateFromHeader();

private:
	/// 헤더
	CZipFileHeader mHeader;

	/// 이름
	cStringT mPathName;

	/// 시간
	cFileTime mWriteTime;
};

inline
time_t cFileInPackInfo::GetUnixWriteTime()
{
	return mHeader.GetTime();
}

inline
const cStringT& cFileInPackInfo::GetPathName() const
{
	return mPathName;
}

inline
unsigned int cFileInPackInfo::GetSize() const
{
	return (unsigned int)mHeader.m_uUncomprSize;
}

inline
const cFileTime& cFileInPackInfo::GetWriteTime() const
{
	return mWriteTime;
}

inline
bool cFileInPackInfo::IsDirectory() const
{
	return mHeader.IsDirectory();
}

/// 파일 팩
class cFilePack
{
public:
	/// 열기 모드
	enum eOpenMode
	{
		OPEN_READONLY = CZipArchive::zipOpenReadOnly,
		OPEN = CZipArchive::zipOpen,
		CREATE = CZipArchive::zipCreate
	};

public:
	cFilePack();
	~cFilePack();

	/// 열기
	bool Open( const cStringT& pathName, eOpenMode mode );

	/// 닫기
	void Close();

	/// 패스워드
	/// 파일 팩을 연 후, 파일을 생성하거나 추가하기 전에 사용한다.
	bool SetPassword( const charT* password = 0 );

	/// 파일 검색
	/// 파일 인덱스를 리턴한다. 실패하면 -1을 리턴한다.
	int FindFile( const cStringT& pathName, bool caseSensitive = false );

	/// 파일 삭제
	void DeleteFile( int index );
	void DeleteFiles( const tArray<int>& indexArray );

	/// 파일 이름 변경
	bool RenameFile( int index, const cStringT& newPathName );

	/// 파일 열기
	bool OpenFile( int index );

	/// 파일 닫기
	bool CloseFile();

	/// 파일 읽기
	/// OpenFile() 함수로 열려 있어야 한다.
	/// 성공하면 실제로 읽어들인 바이트 수를 리턴하고, 실패하면 0을 리턴한다.
	unsigned int ReadFile( void* buffer, unsigned int size );

	/// 새 파일 열기
	/// compressLevel : 압축 수준
	/// filePath : 해당 경로의 파일로부터 시간 정보와 속성을 가져온다.
	bool OpenNewFile( cFileInPackInfo& fi, int compressLevel = Z_NO_COMPRESSION, LPCTSTR filePath = 0 );

	/// 압축 파일 안의 파일 닫기
	bool CloseNewFile();

	/// 버퍼의 내용을 압축해서 저장
	/// OpenNewFile() 함수로 열려 있어야 한다.
	bool WriteNewFile( const void* buffer, unsigned int size );

	/// 내부 버퍼의 내용을 모두 저장소에 기록
	void Flush();

	/// 파일이 열렸는지를 리턴
	bool IsOpened();

	/// 파일 수를 리턴
	int GetNumFiles() const;

	/// 파일 정보를 리턴
	bool GetFileInfo( cFileInPackInfo* fi, int index ) const;

private:
	/// 압축 저장소
	CZipArchive mZip;
};

inline
bool cFilePack::SetPassword( const charT* password )
{
	return mZip.SetPassword( password );
}

inline
bool cFilePack::IsOpened()
{
	return !mZip.IsClosed();
}

inline
int cFilePack::GetNumFiles() const
{
	return mZip.GetCount();
}
