/* 
 * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
 *
 * 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 St, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */
#ifndef _DB_CONN_BE_H_
#define _DB_CONN_BE_H_

#include "grts/structs.db.mgmt.h"
#include "cppdbc.h"
#include <vector>
#include <map>

#include "wbpublic_public_interface.h"
#include "base/geometry.h"

class DbDriverParam;
class DbDriverParams;
class DbConnection;

enum ControlType {
  ctUnknown,
  ctLabel,
  ctDescriptionLabel,
  ctTextBox,
  ctKeychainPassword,
  ctCheckBox,
  ctNumericUpDown,
  ctButton,
  ctDirSelector,
  ctFileSelector,
  ctEnumSelector,
  ctText
};


class WBPUBLICBACKEND_PUBLIC_FUNC DbDriverParam
{
public:
  enum ParamType {
    ptUnknown,
    ptInt,
    ptString,
    ptPassword,
    ptKeychainPassword,
    ptBoolean,
    ptTristate,
    ptDir,
    ptFile,
    ptEnum,
    ptIntEnum,
    ptText,
    ptButton
  };

private:
  static ParamType decode_param_type(std::string type_name, std::string real_type);

  db_mgmt_DriverParameterRef _inner;
  ParamType _type;
  grt::ValueRef _value;

  DbDriverParam(const DbDriverParam&) {}
  DbDriverParam(
    const db_mgmt_DriverParameterRef &driver_param,
    const db_mgmt_ConnectionRef &stored_conn);
  DbDriverParam(const db_mgmt_DriverParameterRef &driver_param, const grt::ValueRef &value);

  ControlType get_control_type() const;

  friend class DbDriverParams;

public:
  const db_mgmt_DriverParameterRef & object() const { return _inner; }

  ParamType get_type() const { return _type; }
  grt::StringRef get_control_name() const;
  const grt::ValueRef & get_value() const { return _value; }
  const grt::StringRef get_value_repr() const { return _value.toString(); }
  void set_value(const grt::ValueRef &value);
  std::vector<std::pair<std::string, std::string> > get_enum_options();
};


class WBPUBLICBACKEND_PUBLIC_FUNC DbDriverParams
{
private:
  typedef std::vector<DbDriverParam *> Collection;
  typedef std::map<std::string, DbDriverParam *> String_index;

  Collection _collection;
  String_index _control_name_index;
  db_mgmt_DriverRef _driver;

  DbDriverParams(const DbDriverParams&) {}
  void free_dyn_mem();

  bool parameter_not_valid(const db_mgmt_DriverRef& driver, const std::string& param);

public:
  DbDriverParams() {}
  ~DbDriverParams() { free_dyn_mem(); }

  void init(
    const db_mgmt_DriverRef &driver,
    const db_mgmt_ConnectionRef &stored_conn,
    const boost::function<void (bool)> &suspend_layout,
    const boost::function<void ()> &begin_layout,
    const boost::function<void (DbDriverParam*, ControlType, const base::ControlBounds&,
      const std::string &)> &create_control,
    const boost::function<void ()> &end_layout,
    bool skip_schema=false,
    int first_row_label_width= 100,
    int hmargin= 10,
    int vmargin= 10);
  grt::DictRef get_params() const;
  std::string validate() const;

  size_t count() const { return _collection.size(); }
  DbDriverParam * get(std::string control_name);
};

class WBPUBLICBACKEND_PUBLIC_FUNC DbConnection
{
private:
  db_mgmt_ManagementRef _mgmt;
  DbDriverParams _db_driver_param_handles;
  db_mgmt_DriverRef _active_driver;
  db_mgmt_ConnectionRef _connection;
  bool _skip_schema;
  
  boost::function<void ()> _begin_layout;
  boost::function<void ()> _end_layout;
  boost::function<void (bool)> _suspend_layout;
  boost::function<void (DbDriverParam*, ControlType, const base::ControlBounds&,
    const std::string &)> _create_control;

  void init_dbc_connection(sql::Connection* dbc_conn, const db_mgmt_ConnectionRef& connectionProperties);

public:
  DbConnection(const db_mgmt_ManagementRef &mgmt, const db_mgmt_DriverRef &driver, bool skip_schema);
  
  ~DbConnection();
  grt::GRT * get_grt() const { return _mgmt.get_grt(); }
  
  void set_control_callbacks(
    const boost::function<void (bool)> &suspend_layout,
    const boost::function<void ()> &begin_layout,
    const boost::function<void (DbDriverParam*, ControlType, const base::ControlBounds&,
      const std::string &)> &create_control,
    const boost::function<void ()> &end_layout);

  DbDriverParams *get_db_driver_param_handles() { return &_db_driver_param_handles; }
  
  void update();
  void set_connection_and_update(const db_mgmt_ConnectionRef &connection);
  void set_connection_keeping_parameters(const db_mgmt_ConnectionRef &connection);
  db_mgmt_ConnectionRef get_connection();
  
  void save_changes();
  
  sql::ConnectionWrapper get_dbc_connection();
  db_mgmt_ManagementRef get_db_mgmt() { return _mgmt; }
  db_mgmt_DriverRef driver() { return _active_driver; }

  void set_driver_and_update(db_mgmt_DriverRef);

  bool test_connection();
  std::string validate_driver_params() const;
};

#endif /* _DB_CONN_BE_H_ */
