//  This may look like C code, but it is really -*- C++ -*-

//  ------------------------------------------------------------------
//  The Goldware Library
//  Copyright (C) 1990-1999 Odinn Sorensen
//  ------------------------------------------------------------------
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Library General Public License for more details.
//
//  You should have received a copy of the GNU Library General Public
//  License along with this program; if not, write to the Free
//  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
//  MA 02111-1307, USA
//  ------------------------------------------------------------------
//  $Id$
//  ------------------------------------------------------------------
//  WildCat! 4.x messagebase engine.
//  ------------------------------------------------------------------

#include <gdbgerr.h>
#include <gmemdbg.h>
#include <gdbgtrk.h>
#include <gmowcat.h>


//  ------------------------------------------------------------------

void WCatArea::refresh()
{

    GFTRK("WCatRefresh");

    // Create new base record or read the existing one
    if(data->fhix != -1)
    {
        if(filelength(data->fhix) < sizeof(WCatBase))
        {
            data->base.recsize = sizeof(WCatIdx);
            data->base.active = 0;
            data->base.nextmsgno = 1;
            lseekset(data->fhix, 0);
            write(data->fhix, &data->base, sizeof(WCatBase));
        }
        else
        {
            lseekset(data->fhix, 0);
            read(data->fhix, &data->base, sizeof(WCatBase));
        }
    }

    int32_t ixnum = (filelength(data->fhix)-sizeof(WCatBase)) / sizeof(WCatIdx);

    // Are there any msgs?
    if(ixnum)
    {

        // Read the index file
        data->idx = (WCatIdx*)throw_realloc(data->idx, (uint)(ixnum*sizeof(WCatIdx)));
        lseekset(data->fhix, sizeof(WCatBase));
        read(data->fhix, data->idx, (uint)(ixnum*sizeof(WCatIdx)));
    }

    GFTRK(0);
}


//  ------------------------------------------------------------------

void WCatArea::raw_scan(int __keep_index, int __scanpm)
{

    GFTRK("WCatRawScan");

    WCatData* _was_data = data;
    if(_was_data == NULL)
    {
        data = wcatdata;
        wide = wcatwide;
    }

    int _wasopen = isopen;
    if(not _wasopen)
    {
        if(ispacked())
        {
            const char* newpath = Unpack(path());
            if(newpath == NULL)
                packed(false);
            set_real_path(newpath ? newpath : path());
        }
        isopen++;
    }

    // Load the lastread
    dword _lastread = 0;
    int _fh = ::sopen(AddPath(real_path(), ".lrd"), O_RDONLY|O_BINARY, WideSharemode, S_STDRD);
    if(_fh != -1)
    {
        lseekset(_fh, wide->userno, sizeof(dword));
        read(_fh, &_lastread, sizeof(dword));
        ::close(_fh);
    }

    // Open WildCat! files for scanning unless they are already open
    if(not _wasopen)
    {

        data->idx = NULL;
        data->base.recsize = 0;
        data->base.active = 0;
        data->base.nextmsgno = 0;

        // Open index file
        data->fhix = ::sopen(AddPath(real_path(), ".ix"), O_RDONLY|O_BINARY, WideSharemode, S_STDRD);
        if(data->fhix != -1)
        {

            // Allocate index buffer and read from file
            refresh();

            // Close index file
            ::close(data->fhix);
            data->fhix = -1;
        }
        if(ispacked())
        {
            CleanUnpacked(real_path());
        }
        isopen--;
    }

    uint _active = 0;
    uint _lastread_reln = 0;
    uint _lastreadfound = 0;

    if(data->base.active)
    {

        // (Re)allocate message index
        if(__keep_index)
            Msgn->Resize((uint)data->base.active);

        // Variables for the loop
        uint _msgno;
        uint32_t* _msgndxptr = Msgn->tag;
        WCatIdx* _ixptr = data->idx;
        uint  _totalmsgs = data->base.active;
        uint _firstmsgno = _totalmsgs ? _ixptr->msgno : 0;
        uint _lastmsgno = 0;

        // Fill message index
        while(_active < _totalmsgs)
        {

            _active++;
            _msgno = (_ixptr++)->msgno;
            if(not _firstmsgno)
                _firstmsgno = _msgno;
            if(__keep_index)
                *_msgndxptr++ = _msgno;

            // Get the lastread
            if((_msgno >= _lastread) and (_lastread_reln == 0))
            {
                _lastreadfound = _msgno;
                _lastread_reln = (uint)(_active - (_msgno != _lastread ? 1 : 0));
            }

            // Store last message number
            _lastmsgno = _msgno;
        }

        // If the exact lastread was not found
        if(_active and (_lastreadfound != _lastread))
        {

            // Higher than highest or lower than lowest?
            if(_lastread > _lastmsgno)
                _lastread_reln = _active;
            else if(_lastread < _firstmsgno)
                _lastread_reln = 0;
        }
    }

    // Update area data
    Msgn->SetCount(_active);
    lastread = _lastread_reln;
    lastreadentry = _lastreadfound;

    // Scan for personal mail
    if(__scanpm)
    {
        // Not implemented yet
    }

    // Free index buffer if just counting
    if(not __keep_index or __scanpm)
        throw_release(data->idx);

    if(_was_data == NULL)
    {
        data = NULL;
        wide = NULL;
    }

    GFTRK(0);
}


//  ------------------------------------------------------------------

void WCatArea::scan()
{

    GFTRK("WCatScan");

    raw_scan(true);

    GFTRK(0);
}


//  ------------------------------------------------------------------

void WCatArea::scan_area()
{

    GFTRK("WCatScanArea");

    raw_scan(false);

    GFTRK(0);
}


//  ------------------------------------------------------------------

void WCatArea::scan_area_pm()
{

    GFTRK("WCatScanArea*M");

    raw_scan(true, true);
    Msgn->Reset();

    GFTRK(0);
}


//  ------------------------------------------------------------------
