
#include "parse_surveys_csv.hpp"

#include <iostream>
#include <string>
#include <algorithm> // replace() needed

#include "SqlSurvey.hpp"

#include "io.hpp"

using namespace std;
using namespace survey_ns;



colmap<ColumnId,string> Survey::m_row
= {
   {name,               "name              varchar(24)     DEFAULT NULL"},
   {species,            "species           varchar(24)     DEFAULT NULL"},
   {transition,         "transition        varchar(32)     DEFAULT NULL"},
   {rest_frequency,     "rest_frequency    double precision DEFAULT NULL"},
   {restf_fits_unit,    "restf_fits_unit   varchar(8)      DEFAULT NULL"},
   {velocity_fits_unit, "velocity_fits_unit varchar(12)    DEFAULT NULL"},
   {storage_path,       "storage_path      varchar(1024)   DEFAULT NULL"},
   {file_filter,        "file_filter       varchar(255)    DEFAULT NULL"},
   {description,        "description       varchar(4096)   DEFAULT NULL"},
   {dataproduct_type,   "dataproduct_type  varchar"},
   {calib_level,        "calib_level       integer         NOT NULL"},
   {o_ucd,              "o_ucd             varchar"},
   {fitskey_facility_name,    "fitskey_facility_name     varchar(12)    DEFAULT NULL"},
   {fitskey_instrument_name,  "fitskey_instrument_name   varchar(12)    DEFAULT NULL"},
   {auth_policy,        "auth_policy    varchar(8)        NOT NULL"}
};




Survey::Survey(string tableName):tabName{tableName}
{
   LOG_trace(__func__);

   string firstField("survey_id SERIAL,");
   string primaryKey(", PRIMARY KEY (survey_id)");

   m_CREATE.clear();
   m_CREATE.append("DROP TABLE IF EXISTS " + tableName + "; ");
   m_CREATE.append("CREATE TABLE " + tableName + " (");
   m_CREATE.append(firstField);
   m_CREATE.append(m_row.concat_val_all());
   m_CREATE.append(primaryKey);
   m_CREATE.append(" )");
};



string Survey::getCREATE(void)
{
   return m_CREATE;
};


// INSERT into surveys table

string to_sqlstring2(string str) {return "\'" + str + "\'";}
// FIXME duplicate: exists in vlkb/datasets/SqlSchema_INSERT

string to_sql_values(survey surv)
{
   return "("
      + to_string(surv.survey_id) + ", "
      + to_sqlstring2(surv.name) + ", "
      + to_sqlstring2(surv.species) + ", "
      + to_sqlstring2(surv.transition) + ", "
      + to_string(surv.rest_frequency_Hz) + ", "
      + to_sqlstring2("") + ", "
      // FIXME NOT USED + to_sqlstring2(surv.restf_fits_unit) + ", "
      + to_sqlstring2(to_string(surv.velocity_fits_unit)) + ", "
      + to_sqlstring2(surv.storage_path) + ", "
      + to_sqlstring2(surv.file_filter) + ", "
      + to_sqlstring2(surv.description) + ", "
      + to_sqlstring2(to_string(surv.dataproduct_type)) + ", "
      + to_string(to_uint(surv.calib_level)) + ", "
      + to_sqlstring2(surv.o_ucd) + ", "
      + to_sqlstring2(surv.fitskey_facility_name) + ", "
      + to_sqlstring2(surv.fitskey_instrument_name) + ", "
      + to_sqlstring2(to_string(surv.auth_policy)) + " "
      "),";
}

string Survey::getINSERT(string surveysPathName)
{
   const bool skip_first_row = true;
   vector<survey> sub_surveys{parse_surveys(surveysPathName, skip_first_row)};

   string cmd_sql{"INSERT INTO " + tabName + " VALUES "};

   for(survey ssurv : sub_surveys)
      cmd_sql.append(to_sql_values(ssurv));
   cmd_sql.pop_back(); // removes last comma

   return cmd_sql;
}



std::string Survey::qry_SELECT_Attribs(int sid)
{
   return "SELECT " + m_row.concat_val_first_word()
      + " FROM surveys WHERE survey_id = " + to_string(sid);
}



string Survey::getStorageFilter(void)
{
   string storageFilter = storagePath + "/" + fileFilter;
   replace(storageFilter.begin(),storageFilter.end(),'%','*');// FIXME do in setFileFilter()
   return storageFilter;
}


string Survey::getObsCollection(void) const
{
   return survName +" "+ survSpecies +" "+ survTransition;
}








string Survey::colName(ColumnId cid)
{
   return m_row[cid].substr(0, m_row[cid].find(' '));
   // if no match found, find() returns string::npos -> end-of-the-string$
}


void Survey::handleResult(pqxx::result res)
{
   LOG_trace(__func__);

   for(auto row: res)
   {
      for (auto field: row) LOG_STREAM << field.c_str() << " ";
      LOG_STREAM << endl;

      // FIXME found no confirm in pqxx doc that col order in row
      // is the same as in list: SELECT list FROM...
      // use explicit string column names instead enum
      // FIXME 2 how to deal with empty SQL_fields ?
      // for now set some default: func as<>(d) returns d if field empty (=null)
      survName         = row[colName(name)      ].as<string>();
      survSpecies      = row[colName(species)   ].as<string>();
      survTransition   = row[colName(transition)].as<string>();

      restFrequency    = row[colName(rest_frequency)    ].as<double>(0.0);
      restFreqFitsUnit = row[colName(restf_fits_unit)   ].as<string>("");
      velocityFitsUnit = row[colName(velocity_fits_unit)].as<string>("");
      storagePath      = row[colName(storage_path)      ].as<string>();
      fileFilter       = row[colName(file_filter)       ].as<string>();
      survDescription  = row[colName(description)       ].as<string>();

      dataproductType = row[colName(dataproduct_type)].as<string>();
      calibLevel      = row[colName(calib_level)     ].as<int>();
      oUcd            = row[colName(o_ucd)           ].as<string>("");
      fitskeyFacilityName   = row[colName(fitskey_facility_name)].as<string>("");
      fitskeyInstrumentName = row[colName(fitskey_instrument_name)].as<string>("");
      authPolicy      = row[colName(auth_policy)     ].as<string>();

   }
}

