#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;
}