/***************************** 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;

#ifdef METVIEW_ODB_NEW

#ifdef ODB_ECKIT
    #include <odb_api/ColumnType.h>
    #include <odb_api/Reader.h>
    #include <odb_api/Writer.h>
    #include <odb_api/Select.h>
#else
    #include <odb_api/odblib/odb_api.h>
#endif

using namespace odb;

extern "C" {
#ifdef ODB_ECKIT
    #include <odb_api/odbcapi.h>
#else
    #include <odb_api/odblib/odbcapi.h>
#endif
}

#endif

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

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

#ifdef METVIEW_ODB_NEW
static map<odb::ColumnType,MvOdbColumn::OdbColumnType> typeMap;
#endif

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[odb::IGNORE]=MvOdbColumn::None;
		typeMap[odb::INTEGER]=MvOdbColumn::Int;
		typeMap[odb::REAL]=MvOdbColumn::Float;
		typeMap[odb::STRING]=MvOdbColumn::String;
		typeMap[odb::BITFIELD]=MvOdbColumn::Bitfield;
		typeMap[odb::DOUBLE]=MvOdbColumn::Double;
	}

	odb_start();
	
}

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

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

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

	//odb::Reader::iterator end = oda.end();
	odb::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(odb::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;

	odb::Reader oda(path_);

	odb::Reader::iterator end = oda.end();
	for (odb::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();
		}
	}
	

	odb::Reader oda(path_);

	//Create iterator
	odb::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;

    	odb::Reader oda(path_);

	//Create iterator
	odb::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;

    	odb::Reader oda(path_);

	//Create iterator
	odb::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;

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

	odb::Select oda(SELECT);
	odb::Select::iterator it = oda.begin();
	odb::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();
    	odb::Reader oda(path_);

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

	//Columns
	vector<string> colName;
	for(odb::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[7];
			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[7];
			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;
	}
}

