// vim600:fdm=marker
#include "cygwin.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "md4.h"
#ifdef __cplusplus
	}
#endif

#include "donkey.h"
#include "misc.h"
#include "sFile.h"
#include "sGui.h"
#include "sSource.h"
#include "sTag.h"
#include "misc.h"

#include "protocol.h"
#include "opcodes.h"

#ifdef FASTHASH
bool fast_hash = 1;
#else
bool fast_hash = 0;
#endif

int    sFile::count      = 0;
int    sFile::count_complete  = 0;
sFile *sFile::first_file = NULL;

void printTree(tRange_Map *tree) {{{
	log(1,"printTree: size: %d\n", tree->size());
	if (tree->size() > 0) {
		for (tRange_Map::iterator iter = tree->begin(); iter != tree->end();iter++) {
			log(1,"  (%12d %12d (%12d) %6d %lld)\n", iter->second->von,
				iter->second->bis, iter->second->bis - iter->second->von + 1,
				iter->second->stat, iter->second->since);
			}
  		}
	else if (tree->begin() != tree->end()) 
		log(1, "\07printTree: begin != end !! \n");
	log(1,"printTreeEnd:\n");
	}}}
void checkTree(tRange_Map *tree) {{{
	log(1,"checkTree:begin\n");
	tRange_Map::iterator iter = tree->begin();
	tRange_Map::iterator prev_iter = tree->begin();
	if (tree->size() > 0) {
		while (iter != tree->end()) {
			prev_iter = iter;
			iter++;
			if (iter != tree->end()) {
				if (prev_iter->second->bis+1 != (iter->second->von)) {
	  				log(1,"checkTree:INCONSISTENT Tree!!! %d %d\n", 
						prev_iter->second->bis, iter->second->von);
					printTree(tree);
					abort();
					}
      				}
			}
		}
	else if (tree->begin() != tree->end()) 
		log(1, "\07checkTree: begin != end !! \n");  
	log(1,"checkTree:end\n");
	}}}
const dtype *Change_Range (tRange_Map *tree, const dtype *N) {{{
	static	dtype B;

	ASSERT(N != NULL);
	if (tree->size() == 0) {{{				// first Block in the DB ?
		dtype *add = reinterpret_cast<dtype*>(MALLOC(sizeof(dtype)));
		memcpy(add, N, sizeof(dtype));
		assert(add->von <= add->bis);
		(*tree)[add->von] = add;
		return add;
		}}}
	tRange_Map::iterator it1 = tree->lower_bound(N->von);
	if (it1 == tree->end()) it1--;
	ASSERT(it1 != tree->end());
	ASSERT(it1->second != NULL);
	if (it1->second->von > N->bis) {
	  if (it1 == tree->begin()) {
	    log(1,"HLDEBUG: if it1->seco... size: Warning: NOT decrementing %d %d\n", it1->second->von, it1->second->bis);
	    abort();
	  } 
	  else {
	    it1--;
	  }
	}

	//printTree(tree);
	// check whether the new range is completely inside
	// NOTE: won't expand towards beginning/end
	if ((it1->second->von <= N->von) && 
	    (it1->second->bis >= N->bis) && 
	    (it1->second->stat == N->stat)) {
	  B.von = it1->second->von;
	  B.bis = it1->second->bis;
	  B.stat = it1->second->stat;
	  B.since = it1->second->since;
	} 
	else if (it1->second->von < N->von && it1->second->bis > N->bis) {{{ 
		dtype *ins = reinterpret_cast<dtype*>(MALLOC(sizeof(dtype)));
		memcpy(ins, it1->second, sizeof(dtype));
		ins->von   = N->bis + 1;
		(*tree)[ins->von] = ins;

		it1->second->bis = N->von - 1;
		ASSERT(it1->second->bis >= it1->second->von);

		ins = reinterpret_cast<dtype*>(MALLOC(sizeof(dtype)));
		ins->von   = N->von;
		ins->bis   = N->bis;
		ins->stat  = N->stat;
		ins->since = currentTime;
		(*tree)[ins->von] = ins;

		B.von = N->von;
		B.bis = N->bis;
		B.stat = N->stat;
		B.since = N->since;
	}}}
	else {
	  // the range is not embedded, so, it might span 2 or more ranges
	  tRange_Map::iterator it2;
	  
	  B.von = N->von;
	  B.bis = N->bis;
	  B.stat = N->stat;
	  B.since = N->since;
	  it1 = tree->upper_bound(B.von);
	  //log(1, "Change_Range: finding lower bound...\n");
	  //if (it1 != tree->end())
	  //  log(1,"Change_Range: start at %d %d %d\n",
	  //	it1->second->von,it1->second->bis,it1->second->stat);
	  while (it1 != tree->begin()) {
	    it1--;
	    if (it1->second->stat != B.stat) {
	      if (it1->second->bis < B.von) {
		it1++;
		break;
	      }
	      if (it1->second->von == B.von) {
		while (it1 != tree->begin()) {
		  it1--;
		  if (it1->second->stat != B.stat) {
		    it1++;
		    break;
		  }
		}
		break;
	      }
	      else {
		break;
	      }
	    }
	  }
	  ASSERT(it1 != tree->end()); // there would be a gap in the tree
	  //log(1, "Change_Range: lower bound at %d\n", it1->second->von);
	  if ((it1->second->stat != B.stat) && (B.von > it1->second->von)) {
	    it1->second->bis = B.von-1;
	    it1++;
 	  }
	  else if ((it1->second->stat != B.stat) && 
		   (B.von == it1->second->von) &&
		   (B.bis < it1->second->bis)) {
	    dtype *tmp;
	    tmp = it1->second;
	    tmp->von = B.bis+1;
	    tree->erase(it1);
	    (*tree)[tmp->von] = tmp;	      
	  }   
	  else {
	    if (it1->second->von < B.von)
	      B.von = it1->second->von;
	    if (B.bis < it1->second->bis)
	      B.bis = it1->second->bis;
	    it2 = it1;
	    it2++;
	    free(it1->second);
	    it1->second = NULL;
	    tree->erase(it1);
	    it1 = it2;
	  }
	  // printTree(tree);
	  
	  //log(1, "Change_Range: finding upper bound...\n");	  
	  while (it1 != tree->end()) {
	    if  ((it1->second->stat != B.stat) && (it1->second->bis > B.bis))
	      break;
	    else {
	      if (it1->second->bis > B.bis)
		B.bis = it1->second->bis;
	      it2 = it1;
	      it2++;
	      free(it1->second);
	      it1->second = NULL;
	      tree->erase(it1);	   
	      it1 = it2;
	    }  
	  }
	  //if (it1 != tree->end())
	  //  log(1, "Change_Range: upper bound at %d\n", it1->second->von);
	  //else
	  //  log(1, "Change_Range: no upper bound\n");

	  //printTree(tree);
	  if (it1 != tree->end()) {
	    if ((it1->second->bis > B.bis) && (it1->second->stat != B.stat)) {
	      dtype *tmp;
	      tmp = it1->second;
 	      tmp->von = B.bis+1; 
	      tree->erase(it1);
	      (*tree)[tmp->von] = tmp;	      
	    }
	    //else {
	    //  log(1, "errororr2\n");
	    //}
	  }

	  dtype *ins = reinterpret_cast<dtype*>(MALLOC(sizeof(dtype)));
	  ins->von   = B.von;
	  ins->bis   = B.bis;
	  ins->stat  = B.stat;
	  ins->since = currentTime;
	  (*tree)[ins->von] = ins;
	}

 	//printTree(tree);
	//checkTree(tree);	

	return &B;
	}}}

const dtype *inside_Range (tRange_Map *tree, size_t inside) {{{
	if (tree->empty()) return NULL;
	//printTree(tree);

	tRange_Map::iterator it = tree->lower_bound(inside);
	if (it == tree->end()) {
	  it--;
	}
	if (it->second->von > inside) {
	  if (it == tree->begin()) {
	    abort();
	  } 
	  else {
	    it--;
	  }
	}
	bool OK = (it->second->von <= inside && inside <= it->second->bis);
	if (OK) return it->second;
	ASSERT(OK);
	return NULL;
	}}}

void sFile::Init(void) {{{
	this->tree		= new tRange_Map();
	this->pause		= 0;
	this->part_defekt	= NULL;
	this->ul_last   	= 0;
    	this->dl_last   	= 0;
    	this->ul_count  	= 0;
    	this->dl_count  	= 0;
    	this->ul_rate   	= 0.0;
    	this->dl_rate   	= 0.0;
    	this->search_count 	= 0;
	this->compress_failed 	= 0;
	this->transfered 	= 0;
	this->downloads  	= 0;
	this->publish_next 	= 0;
	this->fd_in 		= -1 ;
	this->name		= NULL;
	this->temp		= NULL;
	this->part_count	= 0;
	this->part_hash  	= NULL;
	this->part_status 	= NULL;
	this->part_sources	= NULL;
	this->it		= tree->end();
	next_file  = NULL;
	count++;
	if (first_file == NULL) first_file = this;
	else {{{
		class sFile *akt = first_file;
		while (akt->next_file != NULL) akt=akt->next_file;
		akt->next_file = this;
		}}}
	}}}
void sFile::Init2 (void) {{{
	force_met = currentTime;
	if (this->part_status == NULL) {
		this->part_status  = reinterpret_cast<uint8_t*>(MALLOC ((part_count+7)/8));
		bzero (part_status , (part_count+7)/8);
		}
	if (this->part_defekt == NULL) {
		this->part_defekt  = reinterpret_cast<uint8_t*>(MALLOC ((part_count+7)/8));
		bzero (part_defekt , (part_count+7)/8);
		}
	this->part_sources = reinterpret_cast<size_t *>(MALLOC (part_count * sizeof(size_t)));
	bzero (part_sources, part_count * sizeof(size_t));
	}}}
bool sFile::Metfile_load(unsigned char *buf, size_t len, const char *dir) {{{
	if (buf == NULL) return false;
	if (dir == NULL) return false;
	uint8_t  version 	= GET_U1 (&buf, &len);
	time_t   date    	= GET_U4 (&buf, &len);
	char dateiname[512];
	strftime(dateiname, 512, "%Y.%m.%d %H:%M.%S", gmtime(&date));
	GET_HASH (&buf, &len, hash);
	printf("Version vom %s for %s\n", dateiname, hash_bin2hex(hash));
	part_count = GET_U2 (&buf, &len);
	if (part_count != 0) {
		part_hash = reinterpret_cast<tHash *>(MALLOC (part_count * sizeof (tHash)));
		memcpy(part_hash, buf, part_count * 16);
		buf += part_count * 16;
		len -= part_count * 16;
		}
	class sTag *tag = parse_tag (buf, &len);
	if (tag == NULL) return false;
	if (tag->name != NULL) {{{
		if (name != NULL) free(name);
		name = tag->name;
		tag->name = NULL;
		}}}
	if (0 != tag->size	 ) size = tag->size;
	if (0 != tag->transfered ) transfered = tag->transfered;
	if (0 != tag->dl_prio    ) dl_prio    = tag->dl_prio;
	if (0 != tag->corrupt_len) {
		if (tag->corrupt_len == (part_count+7)/8) {
			if (this->part_defekt != NULL) free (this->part_defekt);
			this->part_defekt = tag->corrupt_dat;
			tag->corrupt_dat = NULL;
			tag->corrupt_len = 0;
			}
		}
	dtype d;
	d.since = 0;
	d.von 	= 0;
	d.bis 	= size - 1;
	d.stat  = BLOCK_RECIVE;
	Change_Range(tree, &d);
	if (0 != tag->temp       ) {{{
		temp = STRDUP (tag->temp);
		snprintf(dateiname, 512, "%s%c%s", dir, dir_delim, tag->temp);
		if (all_done   ) fd_in = FD_open (dateiname, O_RDONLY|O_BINARY);
		else if (fd_in == -1) fd_in = FD_open (dateiname, O_RDWR|O_BINARY);
		if (fd_in != -1) ftruncate(fd_in, size);
		}}}
	for (tGap_map::iterator gap = tag->gap_map.begin(); gap != tag->gap_map.end(); gap++) {{{
		d.von 	= (*gap).second.von;
		d.bis 	= (*gap).second.bis - 1;
		if (d.von > size && d.bis > size) continue;
		if (d.bis >= size) d.bis = size - 1;
		if (d.von > d.bis ) d.von = d.bis;
		d.stat  = 0;
		Change_Range(tree, &d);
		}}}
	delete tag;
	if (part_count == 0) part_count = (size + PARTSIZE - 1) / PARTSIZE;
	ASSERT (version == 0xE0);
	if (part_count != (size + PARTSIZE - 1) / PARTSIZE) {
		printf("%u != %u\n", part_count, (size + PARTSIZE - 1) / PARTSIZE);
		printf("Size %9u\n", size);
		printf("Hash %s\n", hash_bin2hex(hash));
		}
	ASSERT (part_count == (size + PARTSIZE - 1) / PARTSIZE);
	return true;
	}}}
sFile     ::sFile (const char *met, const char *dir) {{{
	Init ();
	this->all_done = (0 != strcmp(dir, incoming));
	size_t LEN = 0;
	unsigned char *BUF = file (met, &LEN);
	if (BUF == NULL) return;
	Metfile_load (BUF, LEN, dir);
	free (BUF);
	Init2 ();
	if (fd_in == -1) {
//		printf("failed sFile::sFile (%s , %s)\n", met, dir);
		return;
		}
	if (!all_done) {
		this->status = HASHING;
		ASSERT(fd_in != -1);
		fastCheck    (0, size - 1);
		printf("DONE <%s>[%9u]: ", hash_bin2hex(hash), size);
		size_t i = 0;
		for (i = 0; i < partCount(); i++) printf("%c", (partStatus(i)?'1':'0'));
		printf("\n");
		printf("BAD  <%s>[%9u]: ", hash_bin2hex(hash), size);
		for (i = 0; i < partCount(); i++) printf("%c", (partDefekt(i)?'1':'0'));
		printf("\n");
		if (this->status != ALL_DONE) this->status = NAME_KNOWN;
		}
	else	{
		for(uint32_t i=0; i < partCount(); i++) partStatus(i, true, true);
		this->status = ALL_DONE;
		count_complete++;
		}
	char dateiname[512];
	snprintf(dateiname, 512, "%s%c%s.part.met", control, dir_delim, hash_bin2hex(hash));
	if (0 != strcmp(met, dateiname)) rename(met, dateiname);
//	for (tRange_Map::iterator it2 = tree->begin(); it2 != tree->end(); it2++) {
//		printf("c =>   %9u - %9u - %4u\n", it2->second->von, it2->second->bis, it2->second->stat);
//		}
	}}}
sFile     ::sFile (const unsigned char HASH[16], const char *NAME, unsigned int SIZE, const char *dir) {{{
	Init();
	this->all_done 		= (0 != strcmp(dir, incoming));
	this->size   	 	= SIZE;
	this->part_count 	= (size + PARTSIZE - 1) / PARTSIZE;
	this->name   	 	= STRDUP (NAME);
	this->temp		= STRDUP (NAME);
	this->status 		= NAME_KNOWN;
	memcpy (this->hash, HASH, 16);
	Init2 ();
	log (1,"= ed2k://|file|%s|%u|%s|\n", this->name, this->size, hash_bin2hex (this->hash));
	Save (dir);
	if (part_hash == NULL) loadPartHash ();
    	size_t in_len = strlen(dir)+1+strlen(name)+1;
  	char *in_name = reinterpret_cast<char*>(alloca (in_len));
  	sprintf(in_name, "%s%c%s", dir, dir_delim, name);
	if (!all_done) {{{ // file not finished
	  	if (fd_in == -1) fd_in = FD_open (in_name, O_RDWR|O_BINARY);
	  	if (fd_in == -1) fd_in = FD_create (in_name, O_CREAT|O_RDWR|O_BINARY, 0600);
	  	if (SIZE > 1024 * 1024 * 10) ftruncate(fd_in, SIZE);
     	 	this->status = HASHING;
      		fastCheck    (0, size - 1);
      		if (this->status != ALL_DONE) this->status = NAME_KNOWN;
		}}}
	else  {{{		// file already completed
		if (fd_in == -1) fd_in = FD_open (in_name, O_RDONLY|O_BINARY);
	  	ASSERT ( fd_in >= 0 );
	  	for(uint32_t i=0; i < partCount(); i++) partStatus(i, true, true);
      		this->status = ALL_DONE;
	  	count_complete++;
		}}}
	printf("* ed2k://|file|%s|%u|%s|\n", this->name, this->size, hash_bin2hex (this->hash));
	if (1 == (pref.verbose & 1)) {{{
		printf("Status: ");
		for(uint32_t i=0; i < partCount(); i++) printf("%c", partStatus(i)?'1':'0');
		printf("\n");
		}}}
	GUI_LIST {{{
		if (!all_done) 	akt->GUI_new_download(this);
				akt->GUI_new_upload  (this);
		}}}
	}}}
sFile     ::~sFile (void) {{{
	if (first_file == this) 
		first_file = next_file;		// we are the first file
	else	{
		sFile *prev_file = first_file;
		while (prev_file->next_file != this && prev_file->next_file != NULL)
			prev_file = prev_file->next_file;
		ASSERT (prev_file != NULL);
		ASSERT (prev_file->next_file == this);
		prev_file->next_file = prev_file->next_file->next_file;
		}
	tHash hash_set;
	bzero(hash_set, 16);
	if (sSource::count > 0) {
		SOURCE_LIST if (akt->dl_file == this) akt->dlFile(hash_set);
		}
	PartMet_write ();

	for (tRange_Map::iterator it_t = tree->begin(); it_t != tree->end(); it_t++) free(it_t->second);
	tree->clear();
	delete tree;

	{ GUI_LIST akt->GUI_removeDownload (hash); }
	if (name        != NULL) Free2 (name);
	if (temp        != NULL) Free2 (temp);
	if (part_hash   != NULL) Free2 (part_hash);
	if (part_status != NULL) Free2 (part_status);
	if (part_defekt != NULL) Free2 (part_defekt);
	if (part_sources!= NULL) free  (part_sources);
	if (fd_in != -1) FD_close (fd_in );
	count--;
	}}}
void         sFile::PartMet_write   (void) {{{
	char dateiname0[512];
	char dateiname1[512];
	char dateiname2[512];
	snprintf(dateiname0, 512, "%s%c%s.part.set", control, dir_delim, hash_bin2hex (hash));
	snprintf(dateiname1, 512, "%s%c%s.part.met", control, dir_delim, hash_bin2hex (hash));
	snprintf(dateiname2, 512, "%s%c%s.part.old", control, dir_delim, hash_bin2hex (hash));
	int fd = FD_create (dateiname0, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0600);
	if (fd == -1) return;

	assert(part_defekt != NULL);
	force_met = currentTime;
	size_t	tagCount = 5;

	size_t len, LEN = len = 40960;
	unsigned char *buf, *BUF = buf = reinterpret_cast<unsigned char*>(alloca(LEN));
	ADD_U1(&buf, &len, 0xE0);
	ADD_U4(&buf, &len, currentTime);
	ADD_HASH(&buf, &len, hash);
	if (havePartHash()) {{{
		ADD_U2(&buf, &len, part_count);
		for (size_t i = 0; i < part_count; i++) {
			ADD_HASH(&buf, &len, *getPartHash(i));
			}
		}}}
	else	ADD_U2(&buf, &len, 0);
	unsigned char *tag_pos = buf;
	size_t tag_len = len;
	ADD_U4     (&buf, &len, 0);			// changed later
	if (name != NULL) { add_strTag (&buf, &len, FT_FILENAME	, name); tagCount++; }
	add_intTag (&buf, &len, FT_FILESIZE	, size);
	add_intTag (&buf, &len, FT_TRANSFERED	, transfered);	
	if (name != NULL) { add_strTag (&buf, &len, FT_PARTFILENAME	, temp); tagCount++; }
	add_intTag (&buf, &len, FT_DLPRIOTITY	, 1);		// TODO
	add_intTag (&buf, &len, FT_STATUS	, 0);		// evtl TODO
	add_bobTag (&buf, &len, "corrupt", reinterpret_cast<char*>(part_defekt), (part_count+7)/8);
	size_t gap_idx = 0;
	for (it = tree->begin(); it != tree->end(); it++) {{{
		if (it->second->stat == BLOCK_RECIVE || it->second->stat == BLOCK_VERIFY) continue;
		char tag[20];
		snprintf(tag, 20, "%c%u",  9, gap_idx);
		add_intTag(&buf, &len, tag, it->second->von);
		snprintf(tag, 20, "%c%u", 10, gap_idx);
		add_intTag(&buf, &len, tag, it->second->bis+1);
		gap_idx++;
		tagCount += 2;
		}}}
	ADD_U4     (&tag_pos, &tag_len, tagCount);
	size_t to_write = LEN - len;
	FD_WRITE2 (fd, BUF, to_write);
	ASSERT(fd != -1); close (fd);
	remove(dateiname2);
	if (0 != rename(dateiname1, dateiname2)) {
		if (errno != 2)
			printf("sFile 277 met -> old failed %4i %s\n", errno, strerror(errno));
		}
	if (0 != rename(dateiname0, dateiname1)) {
		printf("sFile 280 set -> met failed %4i %s\n", errno, strerror(errno));
		abort();
		return;
		}
	}}}
int          sFile::Save            (const char *dir) {{{
	char dateiname[512];
	snprintf(dateiname, 512, "%s%c%s.part.met", control, dir_delim, hash_bin2hex (hash));
	size_t	LEN;
	unsigned char *BUF = file (dateiname, &LEN);
	if (BUF != NULL) {
		Metfile_load (BUF, LEN, dir);
		free (BUF);
		}
	dtype *r = reinterpret_cast<dtype*>(MALLOC(sizeof(dtype)));
	r->since = currentTime;
	r->stat = (all_done)?BLOCK_VERIFY:0;
	r->von = 0;
	r->bis = size - 1;
	assert(r->von <= r->bis);
	(*tree)[r->von] = r;
	return 0;
	}}}
void         sFile::Pause           (int p) {{{
	if (pause == p ) return ;
	pause = p;
	tHash zero;
	bzero (zero, 16);
	if ( pause != 1 ) return;
	SOURCE_LIST 			// remove current dl sources
		if (this == akt->dl_file ) 
			akt->dlFile(zero); // it only interest if WE are the dlFile not what file it is
	}}}
bool         sFile::loadPartHash    (void) {{{
	if(part_hash!=NULL) return true;
	size_t tmp_len = strlen(control)+1+32+5+1;
	char *tmp_name = reinterpret_cast<char*>(alloca (tmp_len));
	sprintf(tmp_name, "%s%c%s.hash", control, dir_delim, hash_bin2hex (hash));
	int fd = FD_open (tmp_name, O_RDONLY|O_BINARY);
	if (fd<0) return false;
	part_hash = reinterpret_cast<tHash *>(MALLOC (part_count * sizeof (tHash)));
        MD4_CTX ctx;
        MD4Init   (&ctx);
	if(!FD_READ2 (fd, reinterpret_cast<unsigned char*>(part_hash), sizeof(tHash) * part_count)) assert(0);
	for (uint32_t i = 0; i < part_count; i++) {
		MD4Update (&ctx, reinterpret_cast<unsigned char*>(getPartHash(i)), sizeof(tHash));
		}
	ASSERT(fd_in != -1); FD_close (fd);
	uint8_t hash_test[16];
	hash_test[0]=0;
	MD4Final  (hash_test, &ctx);
	memcmp (hash_test, hash, 16);
//	if ( hash_test[0] == 0 ) ASSERT(0);
	//if ( 0 == (memcmp (hash_test, hash, 16)) ) ASSERT(0);
	printf("Part hash %32s succesfully loaded\n", hash_bin2hex (hash) );
	return true;
	}}}
bool         sFile::savePartHash    (tHash *hashset) {{{
	if (part_hash != NULL) return false;
	part_hash = reinterpret_cast<tHash*>(MALLOC(part_count * sizeof(tHash)));
	memmove (part_hash, hashset, part_count * sizeof(tHash));
	return true;
	}}}
tHash*       sFile::getPartHash     (uint32_t i) const {{{
static  tHash hash_tmp;
	memcpy(hash_tmp, hash, 16);
	if (Size()<PARTSIZE) return &hash_tmp;
	ASSERT (part_hash!=NULL && i<part_count);
	return part_hash+i; 
	}}}
void         sFile::set_Completed       () {{{
	status = ALL_DONE;
	all_done = true;
	for(uint32_t i=0; i < partCount(); i++) partStatus(i, true, true);
	}}}
void         sFile::partStatus      (uint32_t idx, bool set, bool mark) {{{
	ASSERT( idx < part_count);
	dtype r;
	r.von   = idx * PARTSIZE;
	r.bis   = r.von + PARTSIZE - 1;
	if (r.bis >= size) r.bis = size - 1;
	r.stat  = (set)?BLOCK_VERIFY:0;
	r.since = currentTime;
	if (set || mark) Change_Range (tree, &r);
	int pos = idx / 8;
	int off = idx & 7;
	partDefekt(idx, !set);
	uint8_t mask = 0xff ^ (1 << off);
	uint8_t flag = (set)? (1 << off) : 0;
	part_status [pos] = (part_status [pos] & mask) | flag;
	}}}
bool         sFile::partStatus      (uint32_t idx) const {{{
	if (idx >= part_count) {
		printf("sFile::partStatus(%u) => part_count=%u\n", idx, part_count);
		abort();
		}
	ASSERT( idx < part_count);
	ASSERT (part_status != NULL);
	const dtype *check = inside_Range (tree, idx*PARTSIZE);
	int pos = idx / 8;
	uint8_t off = (idx & 7);
	uint8_t flag = (1 << off);
	bool ok = (part_status [pos] & flag) != 0;
	bool Assert = (ok && (check->stat == BLOCK_VERIFY || check->stat == BLOCK_RECIVE)) || (!ok && check->stat != BLOCK_VERIFY);
	if (!Assert) {
		printf("ok %i\n", ok);
		printf("check->stat %i\n", check->stat);
		abort();
		}
	return  (part_status [pos] & flag) != 0;
	}}}
void         sFile::partDefekt      (uint32_t idx, bool set) {{{
	ASSERT( idx < part_count);
	int pos = idx / 8;
	int off = idx & 7;
	if (idx >= part_count) return;
	uint8_t mask = 0xff ^ (1 << off);
	uint8_t flag = (set)? (1 << off) : 0;
	part_defekt [pos] = (part_defekt [pos] & mask) | flag;
	}}}
bool         sFile::partDefekt      (uint32_t idx) const {{{
	ASSERT (part_defekt != NULL);
	ASSERT( idx < part_count);
	int pos = idx / 8;
	uint32_t off = idx & 7;
	if (idx >= part_count) return 0;
	uint8_t flag = (1 << off);
	return  (part_defekt [pos] & flag) != 0;
	}}}

// Functions that take care of part Status
int          sFile::checkPart       (uint32_t akt_part, bool mark) {{{
	if (partStatus(akt_part)) return 1;
	if (status == HASHING && fast_hash) {
		if (partDefekt (akt_part)) return false;
		partStatus(akt_part, true, true);
		return 1;
		}
	ASSERT (fd_in != -1);
	if(!havePartHash()) return 0;
	size_t len = PARTSIZE;
	if (len + akt_part * PARTSIZE > Size()) {
		if (Size() <= akt_part * PARTSIZE) return 0;
		len = Size() - akt_part * PARTSIZE;
		}
	if (akt_part >= part_count) return 0;
	unsigned char *map = reinterpret_cast<unsigned char*>(MALLOC (len));
	FD_LSEEK (fd_in, akt_part * PARTSIZE, SEEK_SET);
	if(!FD_READ2 (fd_in, map, len)) assert(0);
	bool ok = false;
	if (map != NULL) {{{
		MD4_CTX      ctx;
		MD4Init   (&ctx);
		MD4Update (&ctx, map, len);
		uint8_t tmp_hash[16];
		MD4Final (tmp_hash, &ctx);
		if (0 == memcmp (getPartHash (akt_part), tmp_hash, 16)) ok = true;
		Free2 (map);
		}}}
	if (!ok) {{{
		partStatus(akt_part,  false, mark);
		return 0;
		}}}

	partStatus(akt_part, true, true);
	size_t OK_cnt = 0;
	for (unsigned int i = 0; i < part_count; i++) if (partStatus(i)) OK_cnt++;
	if (OK_cnt != part_count) return 1;

	/* dl finished. Rename control* and incoming* */
	this->set_Completed() ;
	count_complete++ ;
        printf("Moving finished file %s to %s/ . YIHAA :)\n", this->name, completed );
	GUI_LIST { 
		akt->GUI_removeDownload(this->hash);
		akt->GUI_shareFiles();
		}
	char *dateiname_neu = reinterpret_cast<char*>(alloca (strlen (completed) + 1 + strlen (this->name) + 1));
        char *dateiname_alt = reinterpret_cast<char*>(alloca (strlen (incoming ) + 1 + strlen (this->name) + 1));
        /* Perhaps need to escape special chars ? */ 
        sprintf (dateiname_neu, "%s%c%s", completed, dir_delim, this->name);
        sprintf (dateiname_alt, "%s%c%s", incoming, dir_delim, this->name);

	if ( rename(dateiname_alt,dateiname_neu) != 0 ) {
		printf("ERROR moving completed file %s to %s [%s]\n", dateiname_alt, dateiname_neu, strerror(errno) );
//		ASSERT(0);
		}
	return 1; 
	}}}
void         sFile::fastCheck       (size_t VON, size_t BIS) {{{
	ASSERT(fd_in != -1);
	if(!havePartHash() ) return;		// we can not check anything
	uint32_t VON_PART = VON / PARTSIZE;
	uint32_t BIS_PART = BIS / PARTSIZE;
	for (uint32_t d_check = VON_PART; d_check <= BIS_PART; d_check++)
		if (partDefekt (d_check) && BIS-VON > 5000) {
			if (checkPart (d_check, false)) printf("ICH used\n");
			}
	transfered = 0;
	unsigned not_checked = 0;
	tRange_Map::iterator it1 = tree->begin();
	if (it1 == tree->end()) return;
	dtype akt;
	do {
		ASSERT(it1->second != NULL);
		memcpy(&akt, it1->second, sizeof(dtype));
		if (!running) return;
		if (akt.bis >= size) {
			printf("akt.bis %i\n", akt.bis);
			printf("size    %u\n", size);
			abort();
			}
		ASSERT (akt.bis <  size);
		if (akt.von > akt.bis) printf("akt.von , akt.bis = %9u - %9u\n", akt.von , akt.bis);
		ASSERT (akt.von <= akt.bis);		// Check that there is no "defekt" entry
		if (akt.stat == BLOCK_RECIVE) {		// Only care about recived blocks
			ASSERT(akt.bis >= akt.von);
			transfered += (akt.bis - akt.von + 1);	// Add the transfered byte
			while (true) {
				while (akt.von > not_checked * PARTSIZE) not_checked++;
				if ((akt.von + 0 <= (not_checked + 0) * PARTSIZE && not_checked * PARTSIZE < size) &&
				    (akt.bis + 1 >= (not_checked + 1) * PARTSIZE || akt.bis + 1 >= size)) {{{
					if (!running) return;
					if (! partStatus(not_checked)) {		// check it one per runtime
						if (!checkPart (not_checked, true)) {
							transfered -= PARTSIZE;
							}
						}
					not_checked ++;
					}}}
				else break;
				}
			}
		it1 = tree->upper_bound(akt.bis);
		} while (it1 != tree->end());
//	printf("%32s Transfered %i\n", hash_bin2hex(hash), transfered);
	}}}
int          sFile::recvPart        (off_t VON, size_t BIS, const unsigned char *data) {{{
	if (fd_in < 0) {
		printf("\nERROR: %s -> fd_in < 0\n", __PRETTY_FUNCTION__);
		return 0;
		}
	assert(tree->size() > 0);
	size_t von = VON;
	const unsigned char *save = data;
	if (VON < 0 || von > BIS) {
		printf("\nERROR: %s -> von<0 or von>=bis\n", __PRETTY_FUNCTION__);
		return 0;
		}

	tRange_Map::iterator it_rec = tree->lower_bound(VON);
	if (it_rec == tree->end()) it_rec--;
	if (it_rec->second->von > von) it_rec--;
	
	if ( (it_rec->second->stat == BLOCK_RECIVE || it_rec->second->stat == BLOCK_VERIFY) // do not overwrite recived or verifyed bloicks
		&& it_rec->second->von <= von && it_rec->second->bis > von) {
		// Do not overwrite postfix of recived data
		save = save - von + it_rec->second->bis;
		von = it_rec->second->bis;
		}
	it_rec++;
	if (it_rec != tree->end()) {{{
		if ((it_rec->second->stat == BLOCK_RECIVE 
			|| it_rec->second->stat == BLOCK_VERIFY) // do not overwrite recived or verifyed bloicks
		    && it_rec->second->von < BIS)  {
			// Do not overwrite prefix of recived data
			BIS = it_rec->second->von - 1;
			}
		}}}
	if (von >= BIS) {{{
		if (protocol_logLevel < 8) printf("\nINFO doppelt RECV\n");
		return 0;
		}}}

	FD_LSEEK  (fd_in, von, SEEK_SET);
	int len = von - BIS;
	const unsigned char *zero = save;
	while (len > 0) {
		len--;
		if (*zero != 0) break;
		zero++;
		}
	if (len == 0) {
		printf("\nSpeicher verweigert zero block\n");
		return 1;
		}
	log (1, "RECV %9u-%9u\n", von, BIS);
	size_t do_write = BIS - von;
	FD_WRITE2  (fd_in, save, do_write);
	this->dl_count   += do_write;
	this->transfered += do_write;
	dtype r;
	r.von   = von;
	r.bis   = BIS - 1;
	r.stat  = BLOCK_RECIVE;
	const dtype *res = Change_Range (tree, &r);
	if (res->stat == BLOCK_RECIVE) {
		size_t block = res->von / 9728000;
		VON = block * 9728000;
		BIS = VON   + 9728000 - 1;
		if ((res->von <= VON && (res->bis >= BIS || res->bis + 1 == size)) || transfered >= size) 
			fastCheck(r.von, r.bis);
		}
	if (force_met+60<currentTime) PartMet_write();
	return 1;
	}}}
// Functions need to iterate thorugh all parts
const dtype* sFile::firstBlock      (void) {{{
	it = tree->begin();
	if (it == tree->end()) {
		ASSERT(tree->size() == 0);
		return NULL;
		}
	if (it->second->stat < BLOCK_RECIVE && it->second->since + 30*60 < currentTime) {
		it->second->stat = 0;
		it->second->since = currentTime;
		}
	return it->second;
	}}}
const dtype* sFile:: nextBlock      (void) {{{
	if (it == tree->end()) return NULL;
	assert(it->second != NULL);
	it++;
	if (it == tree->end()) return NULL;
	assert(it->second != NULL);
	if (it->second->stat < BLOCK_RECIVE && it->second->since + 60 < currentTime) {
		it->second->stat  = 0;
		it->second->since = currentTime;
		}
	return it->second;
	}}}
// functions needed for gui
void         sFile::calcRate        (time_t diff) {{{
	double ul,dl,d;
	ul = this->ul_count - ul_last;
	dl = this->dl_count - dl_last;
	if (diff == 0) diff = 1;
	d = diff;
	ul_rate = ul_rate * (1.0 - akt_rate_weight) + (ul / d) * akt_rate_weight;
	dl_rate = dl_rate * (1.0 - akt_rate_weight) + (dl / d) * akt_rate_weight;
	if(ul_last!=ul_count || dl_last!=dl_count) {
		if ((currentTime % 60) == 0) log (1, "dt: %2li, dc(%8.2f / %8.2f) , rate(%8.2f / %8.2f)kb/s, c(%10u / %10u)\n",
				diff, dl, ul, dl_rate,ul_rate,this->dl_count,this->ul_count);
		ul_last = ul_count;
		dl_last = dl_count;
		}
	}}}
sFile *forHash (const uint8_t *hash) {{{ // return file that match hash or NULL (unsafe)
	FILE_LIST if (0 == memcmp (hash, akt->hash,sizeof(hash))) return akt;
	return NULL;
	}}}

