/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include <math.h>
#include <sstream>
#include <fstream>
#include <cstdio>
#include <MvOdb.h>

using namespace std;

#include <odc/Reader.h>
#include <odc/Writer.h>
#include <odc/Select.h>
#include <odc/core/MetaData.h>
#include <odc/api/ColumnType.h>


//using namespace odb;


//This include must come after the oda includes, otherwise
//compilation fails!!
#include "MvScanFileType.h"

const int intMissingValue   = -2147480000;
const int floatMissingValue = -2.14748e+09;

static map<odc::api::ColumnType, MvOdbColumn::OdbColumnType> typeMap;

void MvOdbColumn::setName(string s)
{
    name_ = s;

    shortName_      = name_;
    std::size_t pos = name_.find("@");
    if (pos != string::npos) {
        shortName_ = name_.substr(0, pos);
    }
}

void MvOdbColumn::addToStats(float val)
{
    num_++;

    if (val == floatMissingValue)
        return;

    if (min_ > val) {
        min_ = val;
    }
    if (max_ < val) {
        max_ = val;
    }
    avg_ += val;
    std_ += val * val;
}

void MvOdbColumn::addToStats(double val)
{
}

void MvOdbColumn::compStats()
{
    if (num_ > 0) {
        avg_ /= num_;
        std_ = sqrt(std_ / num_ - avg_ * avg_);
    }
}

void MvOdbColumn::setLoaded(bool flag)
{
    if (!flag)
        unload();

    loaded_ = flag;
}

void MvOdbColumn::unload()
{
    fval_.clear();
    ival_.clear();
    sval_.clear();
    dval_.clear();
    loaded_ = false;
}

int MvOdbColumn::rowNum() const
{
    if (!loaded_)
        return -1;

    if (fval_.size() > 0)
        return fval_.size();
    if (ival_.size() > 0)
        return ival_.size();
    if (sval_.size() > 0)
        return sval_.size();
    if (dval_.size() > 0)
        return dval_.size();
    return -1;
}


//=============================
//
// MvAbstratcOdb
//
//=============================

MvAbstractOdb::MvAbstractOdb(string path, string sourcePath, string query, OdbVersion version) :
    path_(path),
    sourcePath_(sourcePath),
    query_(query),
    version_(version),
    chunkSize_(0),
    currentChunk_(0),
    nbRowsInChunk_(0)
{
    //init();
}

MvAbstractOdb::MvAbstractOdb(string path, OdbVersion version) :
    path_(path),
    version_(version)
{
    //init();
}

MvAbstractOdb::~MvAbstractOdb()
{
    for (vector<MvOdbColumn*>::iterator it = column_.begin(); it != column_.end(); it++) {
        delete *it;
    }
}

void MvAbstractOdb::detectOdbVersion()
{
    struct stat buf;

    const char* fname = path_.c_str();

    if (stat(fname, &buf) < 0) {
        version_ = UnknownVersion;
        return;
    }

    switch (buf.st_mode & S_IFMT) {
        case S_IFDIR:
            version_ = VersionOld;
            break;
            ;

        case S_IFREG:
            if (ScanFileType(fname) == "ODB_DB")
                version_ = VersionNew;
            else
                version_ = UnknownVersion;

            break;

        default:
            version_ = UnknownVersion;
    }
}

//=============================
//
// MvOdb
//
//=============================

#ifdef METVIEW_ODB_NEW

MvOdb::MvOdb(string path, string sourcePath, string query) :
    MvAbstractOdb(path, sourcePath, query, VersionNew)
{
    init();
}

MvOdb::MvOdb(string path) :
    MvAbstractOdb(path, VersionNew)
{
    init();
}

MvOdb::~MvOdb()
{
}

void MvOdb::init()
{
    if (version_ != VersionNew)
        return;

    headerIsRead_ = false;
    rowNum_       = -1;

    if (typeMap.empty() == true) {
        typeMap[odc::api::IGNORE]   = MvOdbColumn::None;
        typeMap[odc::api::INTEGER]  = MvOdbColumn::Int;
        typeMap[odc::api::REAL]     = MvOdbColumn::Float;
        typeMap[odc::api::STRING]   = MvOdbColumn::String;
        typeMap[odc::api::BITFIELD] = MvOdbColumn::Bitfield;
        typeMap[odc::api::DOUBLE]   = MvOdbColumn::Double;
    }

    //odb_start();
    //odc_initialise_api();
}

void MvOdb::readMetaData()
{
    if (headerIsRead_)
        return;

    //string SELECT  = "select * from \"" + path_ + "\";";

    //ODA oda("");
    odc::Reader oda(path_);
    //int row=0;

    //odb::Reader::iterator end = oda.end();
    odc::Reader::iterator beg = oda.begin();
    //Columns

    //ODA::iterator it = oda.begin();
    //MetaData cols=oda.begin()->columns();

    //rowNum_=0;

    //size_t n = beg.columns().size();

    for (odc::core::MetaData::const_iterator it = beg->columns().begin(); it != beg->columns().end(); ++it) {
        MvOdbColumn* acol = new MvOdbColumn;

        //if(rowNum_==0)
        //	rowNum_=(*it)->noRows();

        string s = (*it)->name();

        //cout << s << endl;

        acol->setName(s);
        if (typeMap.find((*it)->type()) != typeMap.end()) {
            acol->setType(typeMap[(*it)->type()]);
        }


        if (acol->type() == MvOdbColumn::Bitfield) {
            int pos = 0;
            for (unsigned int i = 0; i < (*it)->bitfieldDef().first.size(); i++) {
                string name = (*it)->bitfieldDef().first.at(i);
                int size    = (*it)->bitfieldDef().second.at(i);
                acol->addBitfieldMember(new MvOdbBitfieldMember(name, pos, size));
                pos += size;
            }
        }

        column_.push_back(acol);
    }

    //int colNum=column_.size();

    /*rowNum_=0;
	for (ODA::iterator it = oda.begin(); it != end; ++it)
	{
		rowNum_++;
	}*/

    //        for (ODA::select_iterator it = oda.select(SELECT);
    //                it != oda.selectEnd() ; ++it, ++row)
    //        {

    /*for (ODA::iterator it = oda.begin(); it != end; ++it)
	{

		for(int i=0; i < colNum; i++)
		{
			if(column_[i]->type() == MvOdaColumn::Float || column_[i]->type() == MvOdaColumn::Int)
			{
					
				column_[i]->addToStats(it->data(i));
			}
		}
        }

	for(int col=0; col < column_.size(); col++)
	{
		column_[col]->compStats();
		cout << column_[col]->name() << " " << column_[col]->type() << endl;
		cout << " " << column_[col]->min() << " " <<  column_[col]->max() << " " <<
                column_[col]->avg() << " " << column_[col]->std() << endl;
	}*/

    headerIsRead_ = true;
}

void MvOdb::generateStats(int column)
{
    int col = column;

    odc::Reader oda(path_);

    odc::Reader::iterator end = oda.end();
    for (odc::Reader::iterator it = oda.begin(); it != end; ++it) {
        if (column_[col]->type() == MvOdbColumn::Float || column_[col]->type() == MvOdbColumn::Int) {
            column_[col]->addToStats((*it)[col]);
        }
    }

    column_[col]->compStats();
}

int MvOdb::totalSizeInMb()
{
    float mb = 1048576;

    int rowNum = this->rowNum();

    size_t intSize    = sizeof(int);
    size_t floatSize  = sizeof(float);
    size_t doubleSize = sizeof(double);

    float totalSize = 0.;

    for (unsigned int i = 0; i < column_.size(); i++) {
        if (column_[i]->type() == MvOdbColumn::Int) {
            totalSize += (rowNum * intSize) / mb;
        }
        else if (column_[i]->type() == MvOdbColumn::Float) {
            totalSize += (rowNum * floatSize) / mb;
        }
        else if (column_[i]->type() == MvOdbColumn::Double) {
            totalSize += (rowNum * doubleSize) / mb;
        }
        else if (column_[i]->type() == MvOdbColumn::String) {
            totalSize += (rowNum * 8) / mb;
        }
        else {
            totalSize += (rowNum * floatSize) / mb;
        }
    }

    return static_cast<int>(totalSize);
}

int MvOdb::rowNum()
{
    if (rowNum_ != -1)
        return rowNum_;

    readMetaData();
    for (unsigned int i = 0; i < column_.size(); i++) {
        if (column_[i]->isLoaded()) {
            return column_[i]->rowNum();
        }
    }


    odc::Reader oda(path_);

    //Create iterator
    odc::Reader::iterator it = oda.begin();

    int i = 0;
    for (; it != oda.end(); ++it) {
        i++;
    }

    rowNum_ = i;

    return rowNum_;
}

int MvOdb::columnNum()
{
    readMetaData();
    return column_.size();
}

const vector<MvOdbColumn*>& MvOdb::columns()
{
    readMetaData();
    return column_;
}

int MvOdb::findColumn(string cname)
{
    readMetaData();
    for (unsigned int i = 0; i < column_.size(); i++) {
        if (cname == column_[i]->name()) {
            return i;
        }
    }

    return -1;
}

bool MvOdb::hasColumn(const string& cname)
{
    readMetaData();

    //We try with the full column name
    for (unsigned int i = 0; i < column_.size(); i++) {
        if (cname == column_[i]->name()) {
            return true;
        }
    }

    //If there is no match we try without the @tablename suffix

    string shortName = cname;
    std::size_t pos  = cname.find("@");
    if (pos != string::npos) {
        shortName = cname.substr(0, pos);
    }

    //We try with the full column name
    for (unsigned int i = 0; i < column_.size(); i++) {
        if (shortName == column_[i]->shortName()) {
            return true;
        }
    }

    return false;
}


const MvOdbColumn* MvOdb::loadColumn(int pos, bool reload)
{
    readMetaData();

    if (pos < 0 || pos >= static_cast<int>(column_.size()))
        return 0;

    if (reload) {
        column_[pos]->unload();
    }
    else if (column_[pos]->isLoaded()) {
        return column_[pos];
    }

    string sval;

    odc::Reader oda(path_);

    //Create iterator
    odc::Reader::iterator it = oda.begin();

    //Jump to the given chunk
    if (chunkSize_ != 0) {
        int i = 0;
        for (; it != oda.end() && i < chunkSize_ * currentChunk_; ++it, i++) {
        }

        if (column_[pos]->type() == MvOdbColumn::String) {
            i = 0;
            for (; it != oda.end() && i < chunkSize_; ++it, i++) {
                column_[pos]->addStringData((*it).string(pos));
            }
        }
        else if (column_[pos]->type() == MvOdbColumn::Int) {
            i = 0;
            for (; it != oda.end() && i < chunkSize_; ++it, i++) {
                column_[pos]->addIntData(static_cast<int>((*it)[pos]));
            }
        }
        else if (column_[pos]->type() == MvOdbColumn::Float || column_[pos]->type() == MvOdbColumn::Bitfield) {
            i = 0;
            for (; it != oda.end() && i < chunkSize_; ++it, i++) {
                column_[pos]->addFloatData((*it)[pos]);
            }
        }
        else if (column_[pos]->type() == MvOdbColumn::Double) {
            i = 0;
            for (; it != oda.end() && i < chunkSize_; ++it, i++) {
                column_[pos]->addDoubleData((*it)[pos]);
            }
        }
    }
    //No chunks are used for load
    else {
        if (column_[pos]->type() == MvOdbColumn::String) {
            for (; it != oda.end(); ++it) {
                column_[pos]->addStringData((*it).string(pos));
            }
        }
        else if (column_[pos]->type() == MvOdbColumn::Int) {
            for (; it != oda.end(); ++it) {
                column_[pos]->addIntData(static_cast<int>((*it)[pos]));
            }
        }
        else if (column_[pos]->type() == MvOdbColumn::Float || column_[pos]->type() == MvOdbColumn::Bitfield) {
            for (; it != oda.end(); ++it) {
                column_[pos]->addFloatData((*it)[pos]);
            }
        }
        else if (column_[pos]->type() == MvOdbColumn::Double) {
            for (; it != oda.end(); ++it) {
                column_[pos]->addDoubleData((*it)[pos]);
            }
        }
    }

    column_[pos]->setLoaded(true);

    return column_[pos];
}

const MvOdbColumn* MvOdb::loadColumn(string cname, bool reload)
{
    int colPos = findColumn(cname);
    return loadColumn(colPos, reload);
}

void MvOdb::unloadColumn(int pos)
{
    readMetaData();

    if (pos < 0 || pos >= static_cast<int>(column_.size()))
        return;

    column_[pos]->unload();
}

void MvOdb::unloadColumn(string cname)
{
    int colPos = findColumn(cname);
    unloadColumn(colPos);
}

void MvOdb::loadAllColumns()
{
    readMetaData();

    unloadAllColumns();

    string sval;

    odc::Reader oda(path_);

    //Create iterator
    odc::Reader::iterator it = oda.begin();

    //Jump to the given chunk
    if (chunkSize_ != 0) {
        int i = 0;
        for (; it != oda.end() && i < chunkSize_ * currentChunk_; ++it, i++) {
        }

        i = 0;
        for (; it != oda.end() && i < chunkSize_; ++it, i++) {
            for (int pos = 0; pos < static_cast<int>(column_.size()); pos++) {
                if (column_[pos]->type() == MvOdbColumn::String) {
                    column_[pos]->addStringData((*it).string(pos));
                }
                else if (column_[pos]->type() == MvOdbColumn::Int) {
                    column_[pos]->addIntData(static_cast<int>((*it)[pos]));
                }
                else if (column_[pos]->type() == MvOdbColumn::Double) {
                    column_[pos]->addDoubleData((*it)[pos]);
                }
                else {
                    column_[pos]->addFloatData((*it)[pos]);
                }
            }
        }
    }
    //No chunks are used for load
    else {
        for (; it != oda.end(); ++it) {
            for (int pos = 0; pos < static_cast<int>(column_.size()); pos++) {
                if (column_[pos]->type() == MvOdbColumn::String) {
                    column_[pos]->addStringData((*it).string(pos));
                }
                else if (column_[pos]->type() == MvOdbColumn::Int) {
                    column_[pos]->addIntData(static_cast<int>((*it)[pos]));
                }
                else if (column_[pos]->type() == MvOdbColumn::Double) {
                    column_[pos]->addDoubleData((*it)[pos]);
                }
                else {
                    column_[pos]->addFloatData((*it)[pos]);
                }
            }
        }
    }

    for (int pos = 0; pos < static_cast<int>(column_.size()); pos++)
        column_[pos]->setLoaded(true);
}

void MvOdb::unloadAllColumns()
{
    readMetaData();

    for (int pos = 0; pos < static_cast<int>(column_.size()); pos++)
        column_[pos]->unload();
}


const MvOdbColumn* MvOdb::column(int pos)
{
    readMetaData();

    if (pos < 0 || pos >= static_cast<int>(column_.size()))
        return 0;

    return column_[pos];
}

const MvOdbColumn* MvOdb::column(string cname)
{
    int colPos = findColumn(cname);
    return column(colPos);
}

void MvOdb::setCurrentChunk(int chunk)
{
    if (chunkSize_ <= 0 || chunk < 0)
        return;

    if (currentChunk_ != chunk) {
        currentChunk_ = chunk;
        for (unsigned int i = 0; i < column_.size(); i++) {
            unloadColumn(i);
        }
    }

    int num = rowNum();
    if ((chunk + 1) * chunkSize_ < num) {
        nbRowsInChunk_ = chunkSize_;
    }
    else if (chunk * chunkSize_ < num) {
        nbRowsInChunk_ = num - chunk * chunkSize_;
    }
}

void MvOdb::setChunkSize(int chunkSize)
{
    if (chunkSize < 0)
        return;

    if (chunkSize_ != chunkSize) {
        chunkSize_ = chunkSize;
        for (unsigned int i = 0; i < column_.size(); i++) {
            unloadColumn(i);
        }
    }
}

bool MvOdb::retrieveToFile(string query, string inFile, string outFile)
{
    //odb_start();

    string SELECT;

    //Find "where" statement in query
    std::string wd = query;
    std::transform(wd.begin(), wd.end(), wd.begin(), ::tolower);

    string::size_type wherePos = wd.find("where");
    if (wherePos != string::npos) {
        SELECT = query.substr(0, wherePos) + " " +
                 " from \"" + inFile + "\"" +
                 query.substr(wherePos) + ";";
    }
    else {
        SELECT = query + " from \"" + inFile + "\";";
    }

    //cout << "Select: " << SELECT << endl;

    odc::Writer<> writer(outFile);
    odc::Writer<>::iterator outit = writer.begin();

    odc::Select oda(SELECT);
    odc::Select::iterator it  = oda.begin();
    odc::Select::iterator end = oda.end();

    if ((it != end) == false) {
        return false;
    }

    outit->pass1(it, end);

    return true;
}

bool MvOdb::toGeopoints(string outFile, string geoType)
{
    map<string, unsigned int> colNumForGeoType;
    colNumForGeoType["GEO_STANDARD"]  = 6;
    colNumForGeoType["GEO_XYV"]       = 3;
    colNumForGeoType["GEO_XY_VECTOR"] = 7;
    colNumForGeoType["GEO_XY_POLAR"]  = 7;

    //Check geopoints format
    if (colNumForGeoType.find(geoType) == colNumForGeoType.end()) {
        return false;
    }

    //Initialize oda
    //odb_start();
    odc::Reader oda(path_);

    //Create iterator
    odc::Reader::iterator it = oda.begin();

    //Columns
    vector<string> colName;
    for (odc::core::MetaData::const_iterator itc = it->columns().begin(); itc != it->columns().end(); ++itc) {
        string s = (*itc)->name();
        colName.push_back(s);
    }

    if (colName.size() < colNumForGeoType[geoType]) {
        marslog(LOG_EROR, "Less columns (%d) in the retrieval than expected (%d) for output format %s",
                colName.size(), colNumForGeoType[geoType], geoType.c_str());
        return false;
    }

    //Write data into a geopoints file

    //=======================
    // GEO_STANDARD
    //=======================

    if (geoType == "GEO_STANDARD") {
        FILE* fp = fopen(outFile.c_str(), "w+");
        if (fp == 0) {
            return false;
        }

        fprintf(fp, "#GEO\n");
        fprintf(fp, "lat      long       level          date      time        value\n");

        fprintf(fp, "#DB_INFO\n");
        fprintf(fp, "DB_SYSTEM: ODB\n");

        fprintf(fp, "DB_COLUMN: %s;%s;%s;%s;%s;%s\n",
                colName[0].c_str(),
                colName[1].c_str(),
                colName[2].c_str(),
                colName[3].c_str(),
                colName[4].c_str(),
                colName[5].c_str());

        /*fprintf(fp,"DB_COLUMN_ALIAS: %s;%s;%s;%s;%s;%s\n",
			odb["lat"].colNickname().c_str(),
			odb["lon"].colNickname().c_str(),
			levAlias.c_str(),
			dateAlias.c_str(),
			timeAlias.c_str(),
			odb["value"].colNickname().c_str());*/

        fprintf(fp, "DB_PATH: %s \n", sourcePath_.c_str());
        fprintf(fp, "DB_QUERY_BEGIN \n%s \nDB_QUERY_END\n", query_.c_str());

        fprintf(fp, "#DATA\n");

        unsigned int row = 0;
        for (; it != oda.end(); ++it, row++) {
            fprintf(fp, "%.3f  %.3f  %.3f ",
                    (*it)[0], (*it)[1], (*it)[2]);

            fprintf(fp, "%8d ", static_cast<int>((*it)[3]));

            char s[16];
            sprintf(s, "%06d ", static_cast<int>((*it)[4]));
            fprintf(fp, "%.4s ", s);

            fprintf(fp, "%.8f\n", (*it)[5]);
        }

        fclose(fp);
    }

    //=======================
    // GEO_XYV
    //=======================

    else if (geoType == "GEO_XYV") {
        FILE* fp = fopen(outFile.c_str(), "w+");
        if (fp == 0) {
            return false;
        }

        fprintf(fp, "#GEO\n");
        fprintf(fp, "#FORMAT XYV\n");
        fprintf(fp, "x/long       y/lat       value\n");

        fprintf(fp, "#DB_INFO\n");
        fprintf(fp, "DB_SYSTEM: ODB\n");

        fprintf(fp, "DB_COLUMN: %s;%s;%s\n",
                colName[1].c_str(),
                colName[0].c_str(),
                colName[2].c_str());

        fprintf(fp, "DB_PATH: %s \n", sourcePath_.c_str());
        fprintf(fp, "DB_QUERY_BEGIN \n%s \nDB_QUERY_END\n", query_.c_str());

        fprintf(fp, "#DATA\n");

        unsigned int row = 0;
        for (; it != oda.end(); ++it, row++) {
            fprintf(fp, "%.3f  %.3f  %.8f\n",
                    (*it)[1], (*it)[0], (*it)[2]);
        }

        fclose(fp);
    }

    //=======================
    // GEO_STANDARD
    //=======================

    if (geoType == "GEO_XY_VECTOR" || geoType == "GEO_POLAR_VECTOR") {
        FILE* fp = fopen(outFile.c_str(), "w+");
        if (fp == 0) {
            return false;
        }

        if (geoType == "GEO_XY_VECTOR") {
            fprintf(fp, "#GEO\n");
            fprintf(fp, "#FORMAT XY_VECTOR\n");
            fprintf(fp, " lat        lon height      date        time        u       v\n");
        }
        else if (geoType == "GEO_POLAR_VECTOR") {
            fprintf(fp, "#GEO\n");
            fprintf(fp, "#FORMAT POLAR_VECTOR\n");
            fprintf(fp, " lat        lon height      date        time        speed       dir\n");
        }

        fprintf(fp, "#DB_INFO\n");
        fprintf(fp, "DB_SYSTEM: ODB\n");

        fprintf(fp, "DB_COLUMN: %s;%s;%s;%s;%s;%s;%s\n",
                colName[0].c_str(),
                colName[1].c_str(),
                colName[2].c_str(),
                colName[3].c_str(),
                colName[4].c_str(),
                colName[5].c_str(),
                colName[6].c_str());

        fprintf(fp, "DB_PATH: %s \n", sourcePath_.c_str());
        fprintf(fp, "DB_QUERY_BEGIN \n%s \nDB_QUERY_END\n", query_.c_str());

        fprintf(fp, "#DATA\n");

        unsigned int row = 0;
        for (; it != oda.end(); ++it, row++) {
            fprintf(fp, "%.3f  %.3f  %.3f ",
                    (*it)[0], (*it)[1], (*it)[2]);

            fprintf(fp, "%8d ", static_cast<int>((*it)[3]));

            char s[16];
            sprintf(s, "%06d ", static_cast<int>((*it)[4]));
            fprintf(fp, "%.4s ", s);

            fprintf(fp, "%.3f %.3f\n", (*it)[5], (*it)[6]);
        }

        fclose(fp);
    }


    return true;
}

#endif

//=============================
//
// MvOldOdb
//
//=============================

#ifdef METVIEW_ODB_OLD

MvOldOdb::MvOldOdb(string path, string sourcePath, string query) :
    MvAbstractOdb(path, sourcePath, query, VersionOld)
{
    init();
}

MvOldOdb::MvOldOdb(string path) :
    MvAbstractOdb(path, VersionOld)
{
    init();
}

MvOldOdb::~MvOldOdb()
{
}

void MvOldOdb::init()
{
    if (version_ != VersionOld)
        return;

    headerIsRead_ = false;
    rowNum_       = -1;
}

void MvOldOdb::readMetaData()
{
}

void MvOldOdb::generateStats(int /*column*/)
{
}

int MvOldOdb::rowNum()
{
    return rowNum_;
}

int MvOldOdb::columnNum()
{
    readMetaData();
    return column_.size();
}

const vector<MvOdbColumn*>& MvOldOdb::columns()
{
    readMetaData();
    return column_;
}

int MvOldOdb::findColumn(string cname)
{
    readMetaData();

    for (int i = 0; i < static_cast<int>(column_.size()); i++) {
        if (cname == column_[i]->name()) {
            return i;
        }
    }

    return -1;
}

const MvOdbColumn* MvOldOdb::loadColumn(int /*pos*/, bool /*reload*/)
{
    readMetaData();
    return 0;
}

const MvOdbColumn* MvOldOdb::loadColumn(string cname, bool reload)
{
    int colPos = findColumn(cname);
    return loadColumn(colPos, reload);
}

void MvOldOdb::unloadColumn(int pos)
{
    readMetaData();

    if (pos < 0 || pos >= static_cast<int>(column_.size()))
        return;

    column_[pos]->unload();
}

void MvOldOdb::unloadColumn(string cname)
{
    int colPos = findColumn(cname);
    unloadColumn(colPos);
}

const MvOdbColumn* MvOldOdb::column(int pos)
{
    readMetaData();

    if (pos < 0 || pos >= static_cast<int>(column_.size()))
        return 0;

    return column_[pos];
}

const MvOdbColumn* MvOldOdb::column(string cname)
{
    int colPos = findColumn(cname);
    return column(colPos);
}

/*void MvOldOdb::retrieveToFile(string query, string inFile,string outFile)
{
}*/

bool MvOldOdb::toGeopoints(string /*outFile*/, string /*geoType*/)
{
    return false;
}


#endif

//=============================
//
// MvOdbFactory
//
//=============================

MvAbstractOdb* MvOdbFactory::make(string path, string sourcePath, string query)
{
    //We suppose it is an ODB
    string type = MvOdbType(path.c_str(), false);

    if (type == "ODB_NEW") {
#ifdef METVIEW_ODB_NEW
        return new MvOdb(path, sourcePath, query);
#else
        return 0;
#endif
    }
    else if (type == "ODB_OLD") {
#ifdef METVIEW_ODB_OLD
        return new MvOldOdb(path);
#else
        return 0;
#endif
    }
    else {
        return 0;
    }
}
