/*
 * Copyright (c) 2005-2006 Tom N Harris <telliamed@whoopdedo.org>.
 *
 *     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.
 *
 *     A copy of the GNU General Public License can be found at
 *     http://www.gnu.org/
 *
 * Written by Tom N Harris.
 *
 */

#ifndef SETUP_INSTALLINFO_H
#define SETUP_INSTALLINFO_H

#include <string>
#include <vector>
#include <ext/hash_fun.h>
#include "string_hash_fun.h"

#include "win32.h"
#include "cString.h"

namespace Setup
{

class Installer;
class InstallCfg;

class InstallSoftware;

class InstallFile
{
	String m_source;
	String m_dest;
	bool m_readonly;

public:
	// UTF8 strings
	InstallFile(std::string const& __s, std::string const& __d, bool __r=false);
	InstallFile(std::string const& __s, bool __r=false);

	bool operator==(InstallFile const& _rhs) const
		{ return m_source == _rhs.m_source; }

	String const& id() const 
		{ return m_source; };

	bool SourceExists() const;
	bool FileExistsInDest(String const&) const;
	bool DestIsDirectory(String const&) const;
	bool DestIsReadOnly(String const&) const;
	bool CopyToDest(String const&) const;
	bool DeleteFromDest(String const&) const;

	static bool FileExists(String const&);

public:
	String const& Source() const { return m_source; };
	String const& Dest() const { return m_dest; };
	bool IsReadOnly() const { return m_readonly; };

};

class InstallDir
{
protected:
	enum CfgType
	{
		CfgAdd = 0,
		CfgPrefix = 1,
		CfgPostfix = -1
	};

private:
	String m_name;

	// utf-8 string, but really just us-ascii
	struct t_cfg : std::pair<std::string,CfgType>
	{
		t_cfg()
			: std::pair<std::string,CfgType>() { }
		t_cfg(std::string __s, CfgType __t)
			: std::pair<std::string,CfgType>(__s,__t) { }
		t_cfg(const t_cfg& __x)
			: std::pair<std::string,CfgType>(__x) { }

		bool operator==(const t_cfg& __x)
			{ return first == __x.first; };
		bool operator!=(const t_cfg& __x)
			{ return first != __x.first; };
		bool operator<(const t_cfg& __x)
			{ return first < __x.first; };
		bool operator>(const t_cfg& __x)
			{ return first > __x.first; };
	};
	std::vector<t_cfg> m_cfgs;

public:
	// UTF8 strings
	InstallDir(std::string const& __n);

	bool operator==(InstallDir const& _rhs) const
		{ return m_name == _rhs.m_name; }

	String const& id() const 
		{ return m_name; };

	// A directory cannot replace a file.
	bool FileExistsInDest(String const&) const;
	bool CreateDirectoryInDest(String const&) const;
	bool DeleteDirectoryFromDest(String const&, FILETIME const*) const;
	bool NeedsInstallCfg() const;
	void UpdateInstallCfg(InstallCfg&, String const&) const;

public:
	String const& Dest() const 
		{ return m_name; };
	std::size_t numCfgEntries() const 
		{ return m_cfgs.size(); };
	std::string const& getCfgEntry(std::size_t __n) const 
		{ return m_cfgs.at(__n).first; };
	CfgType getCfgEntryType(std::size_t __n) const
		{ return m_cfgs.at(__n).second; };

protected:
	void addCfgEntry(std::string const& __c, CfgType __t=CfgAdd);
	void addCfgEntry(InstallDir const& __d);

	friend class Installer;

};

class InstallTarget
{
	InstallSoftware const* m_software;

	// URI
	std::string m_id;
	// Localized strings
	String m_version;
	// Bitmap of games supported.
	int m_game;
	int m_installgames;

	std::vector<InstallFile> m_files;
	std::vector<InstallDir> m_dirs;
	// URIs of sofware we depend on
	std::vector<std::string> m_deps;

public:
	InstallTarget(InstallSoftware const& __s, std::string const& __i, std::string const& __v);
	InstallTarget(InstallSoftware const& __s, std::string const& __i, std::string const& __v, std::string const& __g);

	bool operator==(InstallTarget const& _rhs) const
		{ return m_id == _rhs.m_id; }

	std::string const& id() const 
		{ return m_id; };
	inline String const& name() const;
	String const& version() const 
		{ return m_version; };
	int gameId() const 
		{ return m_game; };

	std::size_t numFiles() const
		{ return m_files.size(); };
	InstallFile const& getFile(std::size_t __n) const
		{ return m_files.at(__n); };

	std::size_t numDirs() const
		{ return m_dirs.size(); };
	InstallDir const& getDir(std::size_t __n) const
		{ return m_dirs.at(__n); };

	std::size_t numDependencies() const
		{ return m_deps.size(); };
	std::string const& getDependency(std::size_t __n) const
		{ return m_deps.at(__n); };

protected:
	InstallDir* addDir(std::string const& __d);
	void addFile(std::string const& __s, bool __r);
	void addFile(std::string const& __s, std::string const& __d, bool __r);
	void addDependency(std::string const& __id);
	void removeDependency(std::string const& __id);
	void addGame(std::string const& __g);
	void addGame(int __g);

	int getInstallGames() const { return m_installgames; };
	void addInstallGames(int __g) { m_installgames |= __g; };
	void resetInstallGames() { m_installgames = 0; };

	friend class Installer;

private:
	InstallTarget();
};

class InstallSoftware
{
	// URI
	std::string m_id;

	// Localized strings
	String m_name;

	std::vector<std::string> m_targets;

public:
	InstallSoftware(std::string const& __id, std::string const& __nm);

	bool operator==(InstallSoftware const& _rhs) const
		{ return m_id == _rhs.m_id; }

	std::string const& id() const 
		{ return m_id; };

	String const& name() const 
		{ return m_name; };

	std::size_t numTargets() const
		{ return m_targets.size(); };
	std::string const& getTarget(std::size_t __n) const
		{ return m_targets.at(__n); };

protected:
	void addTarget(std::string const& __i);
	//InstallTarget* addTarget(std::string const& __i, std::string const& __v);
	//InstallTarget* addTarget(std::string const& __i, std::string const& __v, std::string const& __g);

	friend class Installer;
};

inline String const& InstallTarget::name() const 
	{ return m_software->name(); }

};

namespace __gnu_cxx
{

template<> struct hash<Setup::InstallSoftware>
{
	std::size_t operator()(const Setup::InstallSoftware& __s) const
		{ return __stl_hash_string(__s.id().c_str(), __s.id().size()); }
};

template<> struct hash<Setup::InstallTarget>
{
	std::size_t operator()(const Setup::InstallTarget& __t) const
		{ return __stl_hash_string(__t.id().c_str(), __t.id().size()); }
};

template<> struct hash<Setup::InstallFile>
{
	std::size_t operator()(const Setup::InstallFile& __f) const
		{ return __stl_hash_string(__f.id().c_str(), __f.id().size()); }
};

template<> struct hash<Setup::InstallDir>
{
	std::size_t operator()(const Setup::InstallDir& __d) const
		{ return __stl_hash_string(__d.id().c_str(), __d.id().size()); }
};

};

#endif
