#ifndef _OCTTREE_H
#define _OCTTREE_H
#include"image.h"
 

/// Maximum octree reduction level
static const int O_MaxDepth = 7;

// Number of quantized colors
static const int O_NumColor = 256;

class OctNode           // Octree node
{                       	
  private:
    int level;          // Node level
    BOOL leaf_flag;     // Leaf flag
    BOOL mark_flag;     // Marked flag
    DWORD count;        // Pixel count
    
	ImgRGBColor sum;

    int index;          // Color palette index
    int children;       // Number of child nodes
    OctNode *pchild[8]; // Children node pointers
    OctNode *pnext;     // Next reducible node pointer
    OctNode *pprev;     // Previous reducible node pointer

    int TestBit(BYTE val, int index)
    { return ((val & (1 << index)) > index) ? 1 : 0; }

  public:
    OctNode( int node_level, BOOL leaf )
    {
      int i;    // Loop index

      level = node_level;
      leaf_flag = leaf;
      mark_flag = FALSE;
      count = 0L;
      index = 0;
      children = 0;
      sum=0;

      for (i=0;i<8;i++) pchild[i]=NULL;

      pnext=pprev=NULL;
    };

    BOOL     IsLeaf()   { return leaf_flag; }
    BOOL     IsMark()   { return mark_flag; }    
    DWORD    GetCount() { return count; }
    ImgRGBColor GetColor() { return sum/count; }
    int      GetIndex() { return index; }
    int      GetLevel() { return level; }

    // Determine child node according to color
    int FindChild( ImgRGBColor &c )
    {
      int index;    // Child node pointer index

      // Determine child node pointer index
      index = TestBit((unsigned char)c.r, O_MaxDepth - level) << 2 |
          TestBit((unsigned char)c.g, O_MaxDepth - level) << 1 |
          TestBit((unsigned char)c.b, O_MaxDepth - level);

      return index;
    }

    OctNode *GetChild( int i ) { return pchild[i]; }
    OctNode *GetNext() { return pnext; }
    OctNode *GetPrev() { return pprev; }
    int GetNumChild() { return children; }

    // Add RGB color to node
    void AddColor( ImgRGBColor &c ) { sum+=c; count++; }
    void DecNumChild() { children--; }
    void IncNumChild() { children++; }
    void SetChild( int i, OctNode *pc ) { pchild[i] = pc; }
    void SetIndex( int i ) { index = i; }
    void SetLeaf( BOOL flag ) { leaf_flag = flag; }
    void SetMark( BOOL flag ) { mark_flag = flag; }
    void SetNext( OctNode *pn ) { pnext = pn; }
    void SetPrev( OctNode *pn ) { pprev = pn; }
};

class OctQuant          // Octree color quantization
{
  private:
    int leaf_level;     // Leaf level
    int num_leaf;       // Number of leaf nodes

    // Reducible node list pointers
    OctNode *prnl[O_MaxDepth +1];

  protected:
    int height;         // Bitmap height
    int width;          // Bitmap width
    int max_color;      // Maximum number of colors

    OctNode *proot;     // Octree root node pointer

	Image *image;
	BYTE  *newdata,*olddata;

    BOOL InsertNode( OctNode *, ImgRGBColor & );

    OctNode *MakeNode( int level )
    {
      BOOL leaf;    // Leaf node flag
      leaf=(level>=leaf_level)?TRUE:FALSE;
      if (leaf == TRUE) num_leaf++;
	  return new OctNode(level,leaf);
    }

    OctNode *GetReducible();

    // Quantize color
    int QuantizeColor( OctNode *pn, ImgRGBColor &c )
    {
      int c_index;      // Child node pointer index
	if ((pn->IsLeaf()==TRUE) || pn->GetLevel()==leaf_level) return pn->GetIndex();
    c_index=pn->FindChild(c);
    if(!pn->GetChild(c_index)) return pn->GetIndex();
    return QuantizeColor(pn->GetChild(c_index), c);
    }

    void DeleteNode( OctNode * );
    void DeleteTree() { DeleteNode(proot); }
    void FillPalette( OctNode *, int * );

    // Add node to reducible list
    void MakeReducible( OctNode *pn )
    {
      int level;        // Node level
      OctNode *phead;   // List head node
      
      level = pn->GetLevel();
      phead = prnl[level];
      pn->SetNext(phead);
      if (phead != NULL)
        phead->SetPrev(pn);
      prnl[level] = pn;

      pn->SetMark(TRUE);
    }
    
    void ReduceTree();

  public:
    OctQuant()
    {
      int i;    // Loop index

      width = height = 0;
      num_leaf = 0;
      max_color = O_NumColor;
      leaf_level = O_MaxDepth + 1;

      // Clear the reducible node list pointers
      for (i = 0; i < leaf_level; i++) prnl[i] = NULL;
      // Clear the color palette
      proot = NULL;
    }

    BOOL BuildTree();  
    BOOL MapColors();
    BOOL Quantize(Image *img);
  
};
	
#endif


