#ifndef sfile_h
#define sfile_h

#include "cygwin.h"
#include "misc.h"
#include "cVerify.h"
#include "cED2K.h"

const dtype *Change_Range (tRange_Map *tree, const dtype *N);
const dtype *inside_Range (tRange_Map *tree, size_t inside);

#define FILE_LIST	for (sFile *akt = sFile::first_file; akt != NULL; akt = akt->next_file)
typedef enum {
	NAME_KNOWN,
	HASHING,
	SOURCE_SEEK,
	SOURCE_KNOWN,
	ALL_DONE
	} eFile_status;

class sFile {
	public:
static	int		 count;			/* total number of current files */
static	int		 count_complete;	/* total number of completed/shared files */
static  class sFile	*first_file;
	class sFile	*next_file;
	tHash	  	 hash;
	time_t		 publish_next;
	time_t		 force_met;
	size_t		 publish_count;
	size_t		*part_sources;
	
	size_t  	 part_count;	// Will becomedeprecated
	tHash	  	*part_hash;

	uint8_t	  	*part_status;	// Will be replaced by transfered
	uint8_t		*part_defekt;	// Will be replaced by defekt


	class cED2K	*ed2k;
	tRange_Map	*validated;	// List of Blocks that are correct
	tRange_Map	*recived;	// List of Blocks that need not to be requested
	tRange_Map	*defekt;	// List of Blocks that are transfered but defekt (ICH)

	private:
	void		 PartMet_write (void);
	char	 	*name;
	char		*temp;
	size_t		 ul_count;
	size_t		 dl_count;
	size_t		 ul_last;
	size_t		 dl_last;
	double		 ul_rate;
	double		 dl_rate;
	int 		 pause;
	unsigned	 dl_prio;
	unsigned	 ul_prio;
	void		 Init  (void);
	void		 Init2 (void);
	bool		 Metfile_load(unsigned char *buf, size_t len, const char *dir);
	public:
	int		 fd_in;
	unsigned	 downloads;		// count the dl_hash in sources, updated by changes of dl_hash in sSources
	size_t		 transfered;
	unsigned int 	 size;
	eFile_status	status;			// faster without extra Call
	unsigned 	 compress_failed;
	tRange_Map::iterator it;
	tRange_Map	 *tree;
	unsigned long	 search_count;
private:
	bool		 all_done;		/* file is already completed/ALL_DONE ? */
public:
const	dtype*		firstBlock	(void); // change "iter"
const	dtype*		 nextBlock	(void); // change "iter"
		 sFile (class sFile&) { assert(0); }
	 	 sFile (const unsigned char hash[16], const char *name, unsigned int size, const char *dir);
		 sFile (const char *met, const char *dir);
		~sFile (void);
	const dtype 	       *Change_range 	(const dtype *N) { return Change_Range(tree, N); }
	size_t			ulCount		(void) const { return ul_count; }
	size_t			dlCount		(void) const { return dl_count; }
	size_t			Size 		(void) const { return size; }
	int    			Pause		(void) const { return pause; }
	bool 			get_Completed	(void) const { return all_done; }
	void 			set_Completed	(void);
	unsigned		ulPrio		(void) const { return ul_prio; }
	unsigned		dlPrio		(void) const { return dl_prio; }
	void			ulPrio		(unsigned p) { ul_prio  = p; }
	void			dlPrio		(unsigned p) { dl_prio  = p; }
	size_t			partCount	(void) const { return part_count; }
	const char *		Name 		(void) const { return name; }
	double			ulRate		(void) const { return ul_rate; }
	double			dlRate		(void) const { return dl_rate; }
	void			calcRate	(time_t diff);

	bool			havePartHash	(void) const { return part_hash != NULL || size <= 9728000; }
	bool			loadPartHash	(void);
	bool			savePartHash	(tHash *hashset);
	tHash*			 getPartHash	(uint32_t i) const;
const	tHash*			listPartHash	(void) const { return part_hash;   }

	bool 			partStatus	(uint32_t idx) const;
	bool 			partDefekt	(uint32_t idx) const;
	void			partStatus	(uint32_t idx, bool set, bool mark);
	void			partDefekt	(uint32_t idx, bool set);
const	uint8_t*		listPartStatus	(void) const { return part_status; }
const	uint8_t*		listPartDefekt	(void) const { return part_defekt; }

	int			checkPart	(uint32_t part, bool mark);
	void			fastCheck	(size_t von, size_t bis);
	int			recvPart	(off_t von, size_t bis, const unsigned char *data);

	void			Status		(eFile_status s) { status = s; }
	void			ulCount		(unsigned int cnt) { ul_count += cnt; }
	int			Save 		(const char *dir);
	void            	Pause       	(int     p);
friend	sFile *sFile_load            		(const char *name);
	};
sFile *forHash (const uint8_t *hash); // return file that match hash or NULL
#endif
