#help_index "DolDoc/Bin"

CDocBin *DocBinFindNum(CDoc *haystack_doc, I64 needle_num)
{
	CDocBin *b = haystack_doc->bin_head.next;

	while (b != &haystack_doc->bin_head)
	{
		if (b->num == needle_num)
			return b;
		b = b->next;
	}

	return NULL;
}

CDocBin *DocBinFindTag(CDoc *haystack_doc, U8 *needle_tag)
{
	CDocBin *b;

	if (needle_tag)
	{
		b = haystack_doc->bin_head.next;
		while (b != &haystack_doc->bin_head)
		{
			if (b->tag && !StrCompare(b->tag, needle_tag))
				return b;
			b = b->next;
		}
	}
	return NULL;
}

U0 DocBinsValidate(CDoc *doc)
{
	Bool		 unlock = DocLock(doc);
	CDocBin		*b, *b1;
	CDocEntry	*doc_e, *doc_e2;
	I64			 renum_num = 0;

	b = doc->bin_head.next;
	while (b != &doc->bin_head)
	{
		b->use_count	= 0;
		b->tmp_use_count= 0;
		b->renum_num	= -1;
		Free(b->tag);
		b->tag			= NULL;
		b = b->next;
	}
	doc_e = doc->head.next;
	while (doc_e != doc)
	{
		doc_e2 = doc_e->next;
		if (doc_e->de_flags & DOCEF_HAS_BIN)
		{
			if (b = doc_e->bin_data = DocBinFindNum(doc, doc_e->bin_num))
			{
				if (doc_e->de_flags & DOCEF_BIN_PTR_LINK)
					b->tmp_use_count = I32_MAX;
				if (!b->use_count++)
					b->renum_num = ++renum_num;
				doc_e->bin_num = b->renum_num;
				if (!b->tag && doc_e->de_flags & DOCEF_TAG && doc_e->tag && *doc_e->tag)
					b->tag = StrNew(doc_e->tag, doc->mem_task);
			}
			else
			{
				RawPrint(3000, "Bin Not Found");
				doc_e->type		= doc_e->de_flags = 0;
				doc_e->type_u8	= DOCT_ERROR;
			}
		}
		doc_e = doc_e2;
	}

	b = doc->bin_head.next;
	doc->cur_bin_num = 1;
	while (b != &doc->bin_head)
	{
		b1 = b->next;
		if (!b->use_count)
		{
			QueueRemove(b);
			Free(b->data);
			Free(b);
		}
		else
		{
			b->num = b->renum_num;
			if (b->num >= doc->cur_bin_num)
				doc->cur_bin_num = b->num + 1;
		}
		b = b1;
	}
	if (unlock)
		DocUnlock(doc);
}

U0 DocBinDel(CDoc *doc, CDocBin *b)
{
	if (doc && b && b->use_count)
	{
		b->use_count--;
		if (!b->use_count)
		{
			QueueRemove(b);
			Free(b->tag);
			Free(b->data);
			Free(b);
		}
	}
	else
		RawPrint(3000, "DocBinDel");
}

I64 DocBinPtrReset(CDoc *doc, CDocEntry *doc_e)
{
	U8		*st, *st2;
	CDoc	*doc2;
	CDocBin	*tmpb, *tmpb2;
	I64		 i, bin_num = 0;

	if (doc_e->de_flags & DOCEF_HAS_BIN && doc_e->bin_ptr_link && StrLen(doc_e->bin_ptr_link))
	{
		bin_num = doc_e->bin_num;
		st = StrNew(doc_e->bin_ptr_link);
		st2 = StrNew(st);
		StrLastRemove(st, ",", st2);
		i = Str2I64(st2);
		if (i > 0 || *st2)
		{
			doc2 = DocRead(st);
			if (i > 0 && (tmpb2 = DocBinFindNum(doc2, i)) || i == 0 && (tmpb2 = DocBinFindTag(doc2, st2)))
			{
				i = 1;
				if (bin_num > 0)
				{
					if (tmpb = DocBinFindNum(doc, bin_num))
					{
						i = tmpb->use_count;
						DocBinDel(doc, tmpb);
					}
				}
				else
					bin_num = doc->cur_bin_num++;

				tmpb = MAllocIdent(tmpb2, doc->mem_task);
				tmpb->use_count	= i;
				tmpb->data		= MAllocIdent(tmpb2->data, doc->mem_task);
				tmpb->num		= bin_num;
				doc_e->bin_data = tmpb;
				if (doc_e->de_flags & DOCEF_TAG && doc_e->tag && *doc_e->tag)
					tmpb->tag = StrNew(doc_e->tag, doc->mem_task);
				else
					tmpb->tag = NULL;
				QueueInsert(tmpb, doc->bin_head.last);
			}
			else
				bin_num = 0;
			DocDel(doc2);
		}
		else
			bin_num = 0;
		Free(st2);
		Free(st);
		doc_e->bin_num = bin_num;
	}
	return bin_num;
}
