/*

    AKDtree.h: Adaptive K-D tree (Friedman) stored on disk

    6.10.2001

    Copyright (C) 2001 by Josef Pelikan, MFF UK Prague
        http://cgg.ms.mff.cuni.cz/~pepca/

    VUCAKO Bench is Open Source software (see http://www.opensource.org/
    for description what Open Source is); you may distributed it and/or
    modify it under the terms of GNU General Public License as published
    by the Free Software Foundation; either version 2, or (at your option)
    any later version.

    This program 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
    General Public License for more details.

    A copy of the GNU General Public License is available as
    `/usr/doc/copyright/GPL' in the Debian GNU/Linux distribution or on
    the World Wide Web at http://www.gnu.org/copyleft/gpl.html.  You can
    also obtain it by writing to the Free Software Foundation, Inc., 59
    Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#ifndef _AKDTREE_H
#define _AKDTREE_H

//-----------------------------------------------------------
//  Virtual NBlock pool:

    // size of one NBlock (in 32-bit integer items):
#define NBlockSize       1024
    // size of one NBlock (in bytes):
#define ByteBlockSize    (NBlockSize*sizeof(int32))

#ifndef MaxFileName
#  define MaxFileName     512
#endif

#define MinPoolSize        16

class NBlockPool {

protected:

    char fn[MaxFileName];
    FILE *f;

    int32 *pool;                            // array of fetched NBlocks
    int size;                               // pool size (number of NBlocks)
    int32 *fetched;                         // NBlocks fetched in memory (-1 for not used item)
    bool *changed;                          // change mask
    unsigned *accessed;                     // serial number of the last access
    unsigned serial;                        // actual serial number
    int *locked;                            // lock count for fetched NBlocks
    int used;                               // number of used NBlocks (disk file size)

    void syncBuffer ( int b );
    int32 *fetchBlock ( int32 i );
    int releaseBuffer ();
    int getFreeBuffer ();

public:

    NBlockPool ( const char *fileName, int poolSize );

    int32 *getBlock ( int32 i );

    void changeBlock ( int32 i );

    int32 *newBlock ( int32 &i );

    void sync ();

    void close ();

    ~NBlockPool ();

    unsigned reads, writes, flushes;        // statistics

    };

//-----------------------------------------------------------
//  Adaptive K-D tree:

#define DefaultPoolSize    64

#define RecordsInBlock      8
#define BlockUsed           0
#define BlockXmin           1
#define BlockXmax           2
#define BlockYmin           3
#define BlockYmax           4
#define BlockSumX           5
#define BlockSumXX          6
#define BlockSumY           7
#define BlockSumYY          8
#define BlockRecord0       10

#define RecordSize          2
#define RecordX             0
#define RecordY             1

#define NodesInBlock      256
#define NodeSize            4
#define NodeFlags           0
#  define NodeFlagX    0x0001
#define NodeDiv             1
#define NodeLeft            2
#define NodeRight           3

#define RootNode            0
#define NodeNull            0

class AKDtree {

protected:

    NBlockPool pool;
    int32 lastNode;

    int32 newBucket ( int32 **ptr =NULL );
    int32 newNode ( int32 flags, int32 div, int32 left, int32 right, int32 **n =NULL );
    void findLastNode ( int32 node );
    bool searchNode ( int32 node, int32 x, int32 y );
    bool searchBlock ( int32 block, int32 x, int32 y );
    bool insertNode ( int32 node, int32 x, int32 y );
    bool insertIntoBucket ( int32 &ptr, int32 x, int32 y );
    int32 splitBucket ( int32 *b, int32 &flags, int32 &div );

    unsigned inner, leaf, hits;

public:

    AKDtree ( const char *fileName, int32 divX, int poolSize =DefaultPoolSize );

    bool search ( int32 x, int32 y );

    bool insert ( int32 x, int32 y );

    bool remove ( int32 x, int32 y );

    int findNearest ( int32 x, int32 y, int n, int32 *result );

    void getStat ( unsigned *stat );
        // reads, writes, flushes, inner nodes, leaf nodes, number of hits

    void close ();

    ~AKDtree ();

    };

#endif
