/* 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: calpontdmlpackage.h 9210 2013-01-21 14:10:42Z rdempsey $
 *
 *
 ***********************************************************************/
/** @file */

#pragma once
#include <string>
#include <boost/uuid/uuid.hpp>

#include "bytestream.h"
#include "dmlpackage.h"
#include "dmltable.h"
#include "calpontselectexecutionplan.h"
#include "we_chunkmanager.h"
#define DML_PACKAGE_DEBUG

namespace dmlpackage
{
/** @brief abstract class that defines the general interface and
 * implemetation of a CalpontDMLPackage
 */
class CalpontDMLPackage
{
 public:
  /** @brief ctor
   */
  CalpontDMLPackage();

  /** @brief ctor
   *
   * @param schemaName the schema of the table being operated on
   * @param tableName the name of the table being operated on
   * @param dmlStatement the dml statement
   * @param sessionID the session id
   */
  CalpontDMLPackage(std::string schemaName, std::string tableName, std::string dmlStatement, int sessionID);

  /** @brief dtor
   */
  virtual ~CalpontDMLPackage();

  /** @brief write a CalpontDMLPackage to a ByteStream
   *
   * @param bytestream the ByteStream to write to
   */
  virtual int write(messageqcpp::ByteStream& bytestream) = 0;

  /** @brief read a CalpontDMLPackage from a ByteStream
   *
   * @param bytestream the ByteStream to read from
   */
  virtual int read(messageqcpp::ByteStream& bytestream) = 0;

  /** @brief build a CalpontDMLPackage from a string buffer
   *
   * @param buffer the row buffer
   * @param columns the number of columns in the buffer
   * @param rows the number of rows in the buffer
   */
  virtual int buildFromBuffer(std::string& buffer, int columns, int rows) = 0;

  /** @brief build a CalpontDMLPackage from a parsed SqlStatement
   *
   * @param sqlStatement the parsed SqlStatement
   */
  virtual int buildFromSqlStatement(SqlStatement& sqlStatement) = 0;

  /** @brief build a CalpontDMLPackage from valuelist built from mysql table fields
   *
   * @param tableValuesMap  the value list for each column in the table
   * @param colNameList the column name for each column
   * @param columns number of columns in the table
   * @param rows  number of rows to be touched
   */
  virtual int buildFromMysqlBuffer(ColNameList& colNameList, TableValuesMap& tableValuesMap, int columns,
                                   int rows, NullValuesBitset& nullValues) = 0;

  /** @brief get the table object
   */
  DMLTable* get_Table()
  {
    return fTable;
  }

  /** @brief set the DML statement (the parsed statement)
   *
   * @param statement the dml statement to set
   */
  void set_DMLStatement(const std::string& statement)
  {
    fDMLStatement = statement;
  }

  /** @brief get the DML statement (the parsed statement)
   */
  const std::string get_DMLStatement() const
  {
    return fDMLStatement;
  }

  /** @brief set the SQL statement (the original SQL statement)
   *
   * @param statement the SQL statement to set (the original SQL statement with quotes)
   */
  void set_SQLStatement(const std::string& statement)
  {
    fSQLStatement = statement;
  }

  /** @brief get the SQL statement (the original SQL statement)
   */
  const std::string get_SQLStatement() const
  {
    return fSQLStatement;
  }

  /** @brief get the logging flag
   */
  bool get_Logging() const
  {
    return fLogging;
  }

  /** @brief set the logging flag
   *
   * @param logging the logging flag to set
   */
  void set_Logging(bool logging)
  {
    fLogging = logging;
  }

  /** @brief get the logending flag
   */
  bool get_Logending() const
  {
    return fLogending;
  }

  /** @brief set the logending flag
   *
   * @param logending the logending flag to set
   */
  void set_Logending(bool logending)
  {
    fLogending = logending;
  }

  /** @brief get the isFromCol flag
   */
  bool get_IsFromCol() const
  {
    return fIsFromCol;
  }

  /** @brief set the update column from column flag
   *
   * @param logging the logging flag to set
   */
  void set_IsFromCol(bool isFromCol)
  {
    fIsFromCol = isFromCol;
  }
  /** @brief set the Table name
   *
   * @param tableName the name to set
   */
  void set_TableName(std::string& tableName)
  {
    fTableName = tableName;

    if (fTable != nullptr)
      fTable->set_TableName(tableName);
  }

  /** @brief get the Table name
   */
  const std::string get_TableName() const
  {
    return fTableName;
  }

  /** @brief set the Schema name
   *
   * @param the schema to set
   */
  void set_SchemaName(std::string& schemaName)
  {
    fSchemaName = schemaName;

    if (fTable != nullptr)
      fTable->set_SchemaName(schemaName);
  }

  /** @brief get the Schema name
   */
  const std::string get_SchemaName() const
  {
    return fSchemaName;
  }

  /** @brief set the timezone
   *
   * @param the timezone to set
   */
  void set_TimeZone(const long timeZone)
  {
    fTimeZone = timeZone;
  }

  /** @brief get the timezone
   */
  long get_TimeZone() const
  {
    return fTimeZone;
  }

  /** @brief does this dml statement have a filter
   */
  bool HasFilter() const
  {
    return fHasFilter;
  }
  void HasFilter(bool hasFilter)
  {
    fHasFilter = hasFilter;
  }

  /** @brief get the filter  statement
   */
  const std::string get_QueryString() const
  {
    return fQueryString;
  }

  /** @brief set the sessionID associated with this package
   */
  void set_SessionID(int sessionID)
  {
    fSessionID = sessionID;
  }

  /** @brief get the sessionID associated with this package
   */
  int get_SessionID() const
  {
    return fSessionID;
  }

  /** @brief set the transaction ID associated with this package
   */
  void set_TxnID(execplan::CalpontSystemCatalog::SCN txnID)
  {
    fTxnId = txnID;
  }

  /** @brief get the transaction ID associated with this package
   */
  execplan::CalpontSystemCatalog::SCN get_TxnID() const
  {
    return fTxnId;
  }
  /** @brief set the chunkmanager associated with this package
   */
  void set_ChunkManager(WriteEngine::ChunkManager* cm)
  {
    fCM = cm;
  }

  /** @brief get the chunkmanager associated with this package
   */
  WriteEngine::ChunkManager* get_ChunkManager() const
  {
    return fCM;
  }

  /** @brief get the ExecutionPlan associated with this package
   */
  boost::shared_ptr<messageqcpp::ByteStream> get_ExecutionPlan()
  {
    return fPlan;
  }

  bool get_isInsertSelect()
  {
    return fIsInsertSelect;
  }
  void set_isInsertSelect(const bool isInsertSelect)
  {
    fIsInsertSelect = isInsertSelect;
  }

  bool get_isBatchInsert()
  {
    return fIsBatchInsert;
  }
  void set_isBatchInsert(const bool isBatchInsert)
  {
    fIsBatchInsert = isBatchInsert;
  }

  bool get_isCacheInsert()
  {
    return fIsCacheInsert;
  }
  void set_isCacheInsert(const bool isCacheInsert)
  {
    fIsCacheInsert = isCacheInsert;
  }

  bool get_isAutocommitOn()
  {
    return fIsAutocommitOn;
  }
  void set_isAutocommitOn(const bool isAutocommitOn)
  {
    fIsAutocommitOn = isAutocommitOn;
  }

  bool get_isWarnToError()
  {
    return fIsWarnToError;
  }
  void set_isWarnToError(const bool isWarnToError)
  {
    fIsWarnToError = isWarnToError;
  }

  uint32_t getTableOid()
  {
    return fTableOid;
  }
  void setTableOid(const uint32_t tableOid)
  {
    fTableOid = tableOid;
  }

  void uuid(const boost::uuids::uuid& uuid)
  {
    fUuid = uuid;
  }
  const boost::uuids::uuid& uuid() const
  {
    return fUuid;
  }

 protected:
  void initializeTable();

  std::string fSchemaName;
  long fTimeZone;
  std::string fTableName;
  std::string fDMLStatement;
  std::string fSQLStatement;
  std::string fQueryString;
  int fSessionID;
  boost::uuids::uuid fUuid;
  execplan::CalpontSystemCatalog::SCN fTxnId;
  boost::shared_ptr<messageqcpp::ByteStream> fPlan;
  DMLTable* fTable;
  bool fHasFilter;
  bool fLogging;
  bool fLogending;
  bool fIsFromCol;
  std::string StripLeadingWhitespace(std::string value);
  bool fIsInsertSelect;
  bool fIsBatchInsert;
  bool fIsCacheInsert;
  bool fIsAutocommitOn;
  bool fIsWarnToError;
  uint32_t fTableOid;
  WriteEngine::ChunkManager* fCM;
};
}  // namespace dmlpackage
