/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

// This file is a translation of the Java file iotdb-client/session/src/main/java/org/apache/iotdb/session/TableSessionBuilder.java

#ifndef IOTDB_TABLESESSIONBUILDER_H
#define IOTDB_TABLESESSIONBUILDER_H

#include "TableSession.h"
#include "AbstractSessionBuilder.h"

class TableSessionBuilder : public AbstractSessionBuilder {
  /*
        std::string host;
        int rpcPort;
        std::string username;
        std::string password;
        std::string zoneId;
        int fetchSize;
        std::string sqlDialect = "tree"; // default sql dialect
        std::string database;
    */
public:
  TableSessionBuilder* host(const std::string& host) {
    AbstractSessionBuilder::host = host;
    return this;
  }
  TableSessionBuilder* rpcPort(int rpcPort) {
    AbstractSessionBuilder::rpcPort = rpcPort;
    return this;
  }
  TableSessionBuilder* useSSL(bool useSSL) {
    AbstractSessionBuilder::useSSL = useSSL;
    return this;
  }

  TableSessionBuilder* trustCertFilePath(const std::string& trustCertFilePath) {
    AbstractSessionBuilder::trustCertFilePath = trustCertFilePath;
    return this;
  }

  TableSessionBuilder* username(const std::string& username) {
    AbstractSessionBuilder::username = username;
    return this;
  }
  TableSessionBuilder* password(const std::string& password) {
    AbstractSessionBuilder::password = password;
    return this;
  }
  TableSessionBuilder* zoneId(const std::string& zoneId) {
    AbstractSessionBuilder::zoneId = zoneId;
    return this;
  }
  TableSessionBuilder* fetchSize(int fetchSize) {
    AbstractSessionBuilder::fetchSize = fetchSize;
    return this;
  }
  TableSessionBuilder* database(const std::string& database) {
    AbstractSessionBuilder::database = database;
    return this;
  }
  TableSessionBuilder* nodeUrls(const std::vector<string>& nodeUrls) {
    AbstractSessionBuilder::nodeUrls = nodeUrls;
    return this;
  }
  std::shared_ptr<TableSession> build() {
    if (!AbstractSessionBuilder::nodeUrls.empty() &&
        (AbstractSessionBuilder::host != DEFAULT_HOST ||
         AbstractSessionBuilder::rpcPort != DEFAULT_RPC_PORT)) {
      throw IoTDBException(
          "Session builder does not support setting node urls and host/rpcPort at the same time.");
    }
    sqlDialect = "table";
    auto newSession = std::make_shared<Session>(this);
    newSession->open(false);
    return std::make_shared<TableSession>(newSession);
  }
};

#endif // IOTDB_TABLESESSIONBUILDER_H