
/**********************************************************//**
 **
 ** @file data/Store/std_sink.h
 **
 ** Copyright (C) 2010  Xpace, LLC.  All rights reserved.
 **
 **************************************************************/


#include <map>

#include "data/sink.h"
#include "data/store/scursor.h"

#include "data/classtree.h"
#include "data/compress/compress.h"
#include "data/store/std_structure.h"

#ifndef XPACE_STD_SINK_H
#define XPACE_STD_SINK_H

namespace Xpace
{
  // ================================ SINK ====================

  class stdSink : public Sink, public Configurable
  {
  public:
    stdSink
      (const Configuration&);

    virtual ~stdSink
      ()
    { 
       close(); 
    }

    virtual bool child
      (const Element* element,
       BytesRef content = BytesRef());
    virtual bool child
      (const elementWithID* element,
       BytesRef content = BytesRef());

    virtual bool continued
      (BytesRef content);

    virtual bool sibling
      (const Element* element,
       BytesRef content = BytesRef());
    virtual bool sibling
      (const elementWithID* element,
       BytesRef content = BytesRef());

    virtual bool parent
      (BytesRef content = BytesRef());

    virtual uint getDepth
      ()
    { 
      return cur_ct_node.getDepth(); 
    }

    virtual bool close
      ();

    class cantOpen : public Exception
    {
    public :
      cantOpen
        (const Exception reason) :
          Exception("Can't open Standard Sink.", reason)
      {
      }
    };

  private:
    void open_files
      ();

    void set_ct_node
      (const Element* elt);

    bool set_content_node
      (const Element* elt,
       const BytesRef& content);

    void write_page
      ();
    bool check_new_record
      (bool* done)
    {
      *done = false;
      if (cur_ct_node.getDepth() == 0) 
      {
        #ifndef NDEBUG
        status_records.push_back(status_list.size());
        #endif

        // signal a new record
        cur_structure->endRecord();
        node_list.push_back(node(cur_structure));

        if ((++rec_num & (page_size - 1)) == 0)
          write_page();
        else if (rec_num == max_recs)
        {
          write_page();
          *done = true;
        }

        return true;
      }
      return false;
    }

    #ifndef NDEBUG
    std::vector<uint> status_records;
    #endif

  // public only for a template decl
  public:
    struct ct_info
    {
      ct_info
        () :
          dataEncoder(0),
          structureEncoder(0),
          nodeSet(false)
          #ifndef NDEBUG
          , dataDecoder(0),
          structureDecoder(0)
          #endif
      {
      }
      encoder* dataEncoder;
      stdEncodeStructure* structureEncoder;
      bool nodeSet;

      #ifndef NDEBUG
      decoder* dataDecoder;      
      stdDecodeStructure* structureDecoder;
      void* clientInfo;
      #endif
    };

  private:
    static const uint page_size;
    File dt, di, dd;
    classTreeNode<ct_info> cur_ct_node;
    BytePool pool;
    uint64 rec_num, max_recs;
    stdEncodeStructure* cur_structure;

    // buffer for record sizes
    std::vector<uint> record_sizes;

    // buffers for a page's structure and content
  #ifdef NDEBUG
    struct node
    {
      node
        (stdEncodeStructure* s = 0,
         encode* d = 0) :
          structureEncoder(s),
          dataEncoder(d)
      {
      };

      stdEncodeStructure* structureEncoder;
      encode* dataEncoder;  
    };

  #else
  public:
    struct node
    {
      node
        (stdEncodeStructure* es = 0,
         encode* ed = 0,
         stdDecodeStructure* sd = 0,
         decode* dd = 0) :
          structureEncoder(es),
          dataEncoder(ed),
          structureDecoder(sd),
          dataDecoder(dd)          
      {
      };

      stdEncodeStructure* structureEncoder;
      encode* dataEncoder;      
      stdDecodeStructure* structureDecoder;
      decode* dataDecoder;      
    };
  private:  
  #endif

    std::vector<node> node_list;

    // bit streams for writing
    MemBitStream records;    // record sizes
    MemBitStream headers;    // page headers - structure and content for each field
    MemBitStream content;    // compressed content

    #ifndef NDEBUG
    BytePool debug_pool, content_pool;
    std::vector<SCursor::SStatus> status_list;
    std::vector<BytesRef> content_list;
    std::vector<uint> record_list;
    #endif
  };
}

#endif
