/*
 * (C) Copyright 1996-2012 ECMWF.
 * 
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. 
 * In applying this licence, ECMWF does not waive the privileges and immunities 
 * granted to it by virtue of its status as an intergovernmental organisation nor
 * does it submit to any jurisdiction.
 */


/// @author Simon Smart
/// @author Baudouin Raoult
/// ECMWF Dec 03

#ifndef eckit_sql_SQLDatabase_H
#define eckit_sql_SQLDatabase_H

#include <map>
#include <memory>

#include "eckit/filesystem/PathName.h"
#include "eckit/sql/SchemaAnalyzer.h"
#include "eckit/sql/SQLTable.h"


namespace eckit {
namespace sql {

//----------------------------------------------------------------------------------------------------------------------

// Forward declarations

class SQLStatement;
namespace expression { class SQLExpression; }

typedef std::map<std::string, std::set<std::string> > Links;
typedef std::map<std::string, std::shared_ptr<expression::SQLExpression>> Variables;


//----------------------------------------------------------------------------------------------------------------------

class SQLDatabase {
public:
    SQLDatabase(const std::string& name = "default");
	virtual ~SQLDatabase(); 

// -- Methods
    void open();
    void close();

    /// Access SQLTables in DB
    bool hasTable(const std::string& name) const;
    SQLTable& table(const std::string& name);
    SQLTable& defaultTable();
    std::vector<std::reference_wrapper<SQLTable>> implicitTables();

//    SQLTable& openDataHandle(eckit::DataHandle&);
//    SQLTable& openDataStream(std::istream&, const std::string& delimiter);

    void addTable(SQLTable* table);
    void addImplicitTable(SQLTable* table);

	void setLinks(const Links&);
	void setLinks() { setLinks(links_); }

	void addLinks(const Links& ls) { links_.insert(ls.begin(), ls.end()); }
	Links& links() { return links_; }

    const std::string& name() const { return name_; }

    std::shared_ptr<expression::SQLExpression> getVariable(const std::string&) const;
    void setVariable(const std::string&, std::shared_ptr<expression::SQLExpression>);

	Variables& variables() { return variables_; }

    SchemaAnalyzer& schemaAnalyzer() { return schemaAnalyzer_; }

    void setIncludePath(const std::string& includePath);
    const std::vector<eckit::PathName>& includePath() const { return includePath_; }

protected:
	Links links_;
    std::map<std::string, std::unique_ptr<SQLTable>> tablesByName_;
    std::vector<std::unique_ptr<SQLTable>> implicitTables_;

    std::vector<eckit::PathName> includePath_;

	Variables variables_;
	std::string name_;
    SchemaAnalyzer schemaAnalyzer_;

private:
// No copy allowed
	SQLDatabase(const SQLDatabase&);
	SQLDatabase& operator=(const SQLDatabase&);

	void loadIOMAP();
	void loadDD();
	void loadFLAGS();

// -- Friends
    friend std::ostream& operator<< (std::ostream& s, const SQLDatabase& p)
	{ 
        s << "[SQLDatabase@" << &p << " tables: ";
        for (const auto& it : p.tablesByName_) {
            s << it.first << ",";
        }

        s << "]";
        return s; 
    }
};

//----------------------------------------------------------------------------------------------------------------------

} // namespace sql 
} // namespace eckit 

#endif // eckit_sql_SQLDatabase_H
