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

#ifndef MvOdb_H
#define MvOdb_H

#include <iostream>
#include <map>
#include <vector>
#include <list>
#include <assert.h>

//#include <Metview.h>
//#include "MvObs.h"

using namespace std;


class MvOdbBitfieldMember
{
public:
	MvOdbBitfieldMember(string name,int pos, int size) : name_(name), 
						       pos_(pos), 
					               size_(size) {}
	string name() {return name_;}
	int pos() {return pos_;}
	int size() {return size_;}

private:						   
	string name_;
	int pos_;
	int size_;
};


class MvOdbColumn
{
public:
	enum OdbColumnType {None, Int, Float, String, Bitfield, Double};

	MvOdbColumn() : type_(None), num_(0), min_(1.0e+08), max_(-1.0e+08), loaded_(false) {};
	void addToStats(float);
	void addToStats(double);
	void compStats();

	string name() const {return name_;}
	string shortName() const {return shortName_;}
	OdbColumnType type() const {return type_;}
	string unit() {return unit_;}
	const  vector<MvOdbBitfieldMember*>& bitfield() {return bitfield_;}
	int bitfieldNum() {return bitfield_.size();}

	float  min()  {return min_;}
	float  max()  {return max_;}
	float  avg()  {return avg_;}
	float  std()  {return std_;}
	
	void   setName(string);
	void   setType(OdbColumnType s) {type_=s;}
	void   setUnit(string s) {unit_=s;}
	void   addBitfieldMember(MvOdbBitfieldMember* b) {bitfield_.push_back(b);};
	
	void unload();
	bool isLoaded() const {return loaded_;}
	void setLoaded(bool);
	void addStringData(string s) {sval_.push_back(s);}
	void addFloatData(float f) {fval_.push_back(f);}
	void addDoubleData(double d) {dval_.push_back(d);}
	void addIntData(int i) {ival_.push_back(i);}
	const vector<double>& doubleData() const {return dval_;}
	const vector<float>& floatData() const {return fval_;}
	const vector<int>& intData() const {return ival_;}
	const vector<string>& stringData() const {return sval_;}
	int rowNum() const;	


private:
	string name_;
	string shortName_;
	OdbColumnType type_;			
	string unit_;
	vector<MvOdbBitfieldMember*> bitfield_;

	int    num_;
	float  min_;
	float  max_;
	float  avg_;
	float  std_;
	
	bool loaded_;
	vector<float> fval_;
	vector<int>    ival_;
	vector<string> sval_;
	vector<double> dval_;
};


class MvAbstractOdb
{ 
public:
	enum OdbVersion {UnknownVersion,VersionOld,VersionNew};

	MvAbstractOdb(string,OdbVersion);
	MvAbstractOdb(string,string,string,OdbVersion);
	virtual ~MvAbstractOdb();

	virtual void init()=0;	  	

	string path() {return path_;}
	string query()    {return query_;}
	OdbVersion version() {return version_;}
	int chunkSize() {return chunkSize_;}
	int currentChunk() {return currentChunk_;}
	int nbRowsInChunk() {return nbRowsInChunk_;}

	virtual void setChunkSize(int i) {chunkSize_=i;}
	virtual void setCurrentChunk(int i) {currentChunk_=i;}

	virtual int totalSizeInMb()=0;
	virtual int rowNum()=0;
	virtual int columnNum()=0;
	virtual const MvOdbColumn* column(string)=0;
	virtual const MvOdbColumn* column(int)=0;
	virtual const vector<MvOdbColumn*>& columns()=0	;
	virtual const MvOdbColumn* loadColumn(string,bool reload=false)=0;
	virtual const MvOdbColumn* loadColumn(int,bool reload=false)=0;
	virtual void  unloadColumn(string)=0;
	virtual void  unloadColumn(int)=0;
	virtual void  loadAllColumns()=0;
	virtual void  unloadAllColumns()=0;

	virtual void generateStats(int)=0;
	virtual bool toGeopoints(string,string)=0;
	virtual bool hasColumn(const string&)=0;

protected:			
	virtual void readMetaData()=0;
	virtual int findColumn(string)=0;
	void detectOdbVersion();
	
	string path_;
	string sourcePath_;
	string query_;
	vector<MvOdbColumn*> column_;
	int rowNum_;
	bool headerIsRead_;
	
	OdbVersion version_;

	int chunkSize_;
	int currentChunk_;
	int nbRowsInChunk_;
};

#ifdef METVIEW_ODB_NEW
class MvOdb : public MvAbstractOdb
{ 
public:
	MvOdb(string);
	MvOdb(string,string,string);
	~MvOdb();

	void init();	  	

	void  setChunkSize(int);	
	void  setCurrentChunk(int);

	int     totalSizeInMb();
	int 	rowNum();
	int 	columnNum();
	const MvOdbColumn* 	column(string);
	const MvOdbColumn* 	column(int);
	const vector<MvOdbColumn*>& columns();
	const MvOdbColumn* 	loadColumn(string,bool reload=false);
	const MvOdbColumn* 	loadColumn(int,bool reload=false);
	void  unloadColumn(string);
	void  unloadColumn(int);
	void  loadAllColumns();
	void  unloadAllColumns();
	
	void generateStats(int);
	bool toGeopoints(string,string);	
	static void retrieveToFile(string,string,string);
	
	bool hasColumn(const string&);

protected:			
	void readMetaData();
	int  findColumn(string);
};
#endif

#ifdef METVIEW_ODB_OLD
class MvOldOdb : public MvAbstractOdb
{ 
public:
	MvOldOdb(string);
	MvOldOdb(string,string,string);
	~MvOldOdb();

	void 	init();	  	

	int     totalSizeInMb() {return 0;}
	int 	rowNum();
	int 	columnNum();
	const MvOdbColumn* 	column(string);
	const MvOdbColumn* 	column(int);
	const vector<MvOdbColumn*>& columns();
	const MvOdbColumn* 	loadColumn(string,bool reload=false);
	const MvOdbColumn* 	loadColumn(int,bool reload=false);
	void  unloadColumn(string);
	void  unloadColumn(int);
	void  loadAllColumns() {};
	void  unloadAllColumns() {};

	void 	generateStats(int);
	bool 	toGeopoints(string,string);
	
	bool hasColumn(const string&) {return false;}	

protected:			
	void readMetaData();
	int  findColumn(string);
};
#endif

class MvOdbFactory
{
public:	
	MvOdbFactory() {};
	static MvAbstractOdb*  make(string path,string sourcePath=string(),string query=string());
};








/*
class MvOdb
{ 
public:
	enum OdbVersion {UnknownVersion,Version1,Version2};

	MvOdb(string);
	MvOdb(string,string,string);
	~MvOdb();
	void init();	  	

	string path() {return path_;}
	string query()    {return query_;}
	int rowNum();
	int columnNum() {readMetaData(); return column_.size();}

	void generateStats(int);
	void toGeopoints(string,string);

	const vector<MvOdbColumn*>& columns() {readMetaData(); return column_;}
	
	const MvOdbColumn* loadColumn(string);
	const MvOdbColumn* loadColumn(int);
	const MvOdbColumn* column(string);
	const MvOdbColumn* column(int);
	void  unloadColumn(string);
	void  unloadColumn(int);	

	OdbVersion version() {return version_;}

	static void retrieveToFile(string,string,string);

protected:			
	void readMetaData();
	int findColumn(string);
	void detectOdbVersion();
	
	int rowNum_;
	string path_;
	string sourcePath_;
	string query_;
	vector<MvOdbColumn*> column_;
	bool headerIsRead_;

	OdbVersion version_;


};
*/



#endif
