/* Copyright (C) 2014 InfiniDB, Inc.

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; version 2 of
   the License.

   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.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   MA 02110-1301, USA. */

/******************************************************************************
 * $Id: objectreader.h 9633 2013-06-19 13:36:01Z rdempsey $
 *
 *****************************************************************************/

/** @file
 * class ObjectReader interface
 */

#pragma once

#include <exception>
#include <string>
#include <cstdint>

namespace messageqcpp
{
class ByteStream;
}

namespace execplan
{
class TreeNode;
class ParseTree;
class CalpontExecutionPlan;

/** @brief A class for creating execplan classes from ByteStreams.
 *
 * A class currently used for recreating execplan polymorphic classes
 * and dynamic objects from ByteStreams.
 */

class ObjectReader
{
 public:
  class UnserializeException : public std::exception
  {
   public:
    explicit UnserializeException(std::string) noexcept;
    ~UnserializeException() noexcept override;
    const char* what() const noexcept override;

   private:
    std::string fWhat;
  };

  /** @brief Enumerates classes supporting serialization
   *
   * This defines one constant for each class that supports
   * serialization.
   */
  enum CLASSID
  {
    ZERO,        // an appropriate initializer
    NULL_CLASS,  // to denote that some member is NULL

    /**** TreeNodes */
    TREENODE,
    TREENODEIMPL,
    RETURNEDCOLUMN,
    AGGREGATECOLUMN,
    GROUPCONCATCOLUMN,
    ARITHMETICCOLUMN,
    CONSTANTCOLUMN,
    ROLLUPMARKCOLUMN,
    FUNCTIONCOLUMN,
    ROWCOLUMN,
    WINDOWFUNCTIONCOLUMN,
    PSEUDOCOLUMN,

    SIMPLECOLUMN,
    SIMPLECOLUMN_INT1,
    SIMPLECOLUMN_INT2,
    SIMPLECOLUMN_INT4,
    SIMPLECOLUMN_INT8,
    SIMPLECOLUMN_UINT1,
    SIMPLECOLUMN_UINT2,
    SIMPLECOLUMN_UINT4,
    SIMPLECOLUMN_UINT8,
    SIMPLECOLUMN_DECIMAL1,
    SIMPLECOLUMN_DECIMAL2,
    SIMPLECOLUMN_DECIMAL4,
    SIMPLECOLUMN_DECIMAL8,

    FILTER,
    CONDITIONFILTER,
    EXISTSFILTER,
    SELECTFILTER,
    SIMPLEFILTER,
    SIMPLESCALARFILTER,

    OPERATOR,
    ARITHMETICOPERATOR,
    PREDICATEOPERATOR,
    LOGICOPERATOR,

    /**** /TreeNodes */

    PARSETREE,
    CALPONTSELECTEXECUTIONPLAN,
    CONSTANTFILTER,
    OUTERJOINONFILTER,

    /** UDAF SDK */
    MCSV1_CONTEXT,
    UDAFCOLUMN,

    /** ANALYZE TABLE */
    MCSANALYZETBLEXECUTIONPLAN,
  };

  typedef uint8_t id_t;  // expand as necessary

  /** @brief Creates a new TreeNode object from the ByteStream
   *
   * @param b The ByteStream to create it from
   * @return A newly allocated TreeNode
   */
  static TreeNode* createTreeNode(messageqcpp::ByteStream& b);

  /** @brief Creates a new ParseTree from the ByteStream
   *
   * @param b The ByteStream to create it from
   * @return A newly allocated ParseTree
   */
  static ParseTree* createParseTree(messageqcpp::ByteStream& b);

  /** @brief Creates a new CalpontExecutionPlan from the ByteStream
   *
   * @param b The ByteStream to create it from
   * @return A newly allocated CalpontExecutionPlan
   */
  static CalpontExecutionPlan* createExecutionPlan(messageqcpp::ByteStream& b);

  /** @brief Serialize() for ParseTrees
   *
   * This function effectively serializes a ParseTree.
   * @param tree The ParseTree to write out
   * @param b The ByteStream to write tree to
   */
  static void writeParseTree(const ParseTree* tree, messageqcpp::ByteStream& b);

  /** @brief Verify the type of the next object in the ByteStream
   *
   * @param b The ByteStream to read from
   * @param type The type it should be
   * @throw UnserializeException if the type does not match; this is a fatal error.
   */
  static void checkType(messageqcpp::ByteStream& b, const CLASSID type);
};

}  // namespace execplan
