
#include "cutout_ostream.hpp"
#include "cutout.hpp"
#include "mcutout.hpp"
#include "my_assert.hpp"

#include <iomanip> // setw
#include <iostream>
#include <vector>

using namespace std;


std::string to_string(skysystem ss)
{
   string str;
   switch(ss)
   {
      case skysystem::GALACTIC: str = "GALACTIC"; break;
      case skysystem::ICRS: str = "ICRS"; break;
      case skysystem::NONE: str = "NONE"; break;
   }
   my_assert(!str.empty(), __FILE__,__LINE__, "unrecognized value of skysystem type");
   return str;
}

std::string to_string(area ss)
{
   string str;
   switch(ss)
   {
      case area::CIRCLE: str = "CIRCLE"; break;
      case area::RECT: str = "RECT"; break;
      case area::RANGE: str = "RANGE"; break;
      case area::POLYGON: str = "POLYGON"; break;
   }
   my_assert(!str.empty(), __FILE__,__LINE__, "unrecognized value of sky area type");
   return str;
}

std::string to_string(specsystem ss)
{
   string str;
   switch(ss)
   {
      case specsystem::NONE: str = "NONE"; break;
      case specsystem::VELO_LSRK: str = "VELO_LSRK"; break;
      case specsystem::WAVE_Barycentric: str = "WAVE_Barycentric"; break;
   }
   my_assert(!str.empty(), __FILE__,__LINE__, "unrecognized value of specsystem type");
   return str;
}

std::string to_string(timesystem ss)
{
   string str;
   switch(ss)
   {
      case timesystem::NONE: str = "NONE"; break;
      case timesystem::MJD_UTC: str = "MJD_UTC"; break;
   }
   my_assert(!str.empty(), __FILE__,__LINE__, "unrecognized value of timesystem type");
   return str;
}


std::ostream& operator<<( std::ostream &out, struct position const& p)
{
   string shape_ostring;

   switch(p.shape)
   {
      case area::CIRCLE:
         shape_ostring = to_string(p.circ.lon) + ", " + to_string(p.circ.lat) + "; " + to_string(p.circ.radius);
         break;
      case area::RANGE:
         shape_ostring = to_string(p.rng.lon1) + " .. " + to_string(p.rng.lon2) + "; "
            + to_string(p.rng.lat1) + " .. "+ to_string(p.rng.lat2);
         break;
      case area::RECT:
         my_assert(false, __FILE__,__LINE__, "area::RECT is not valid for struct position");
         break;
      case area::POLYGON:
         {
            std::string poly_lon_str = "";
            for(double dbl : p.poly.lon) { poly_lon_str += " " + to_string(dbl); }
            std::string poly_lat_str = "";
            for(double dbl : p.poly.lat) { poly_lat_str += " " + to_string(dbl); }
            shape_ostring = " lon(" + poly_lon_str + ") lat(" + poly_lat_str +")";
         }
         break;
   }

   out << to_string(p.shape) << " " << shape_ostring;

   return out;
}

std::ostream& operator<<( std::ostream &out, struct coordinates const& p)
{

   std::string pol_str = "";
   for(string str : p.pol) { pol_str += " " + str; }

   std::string poly_lon_str = "";
   for(double dbl : p.p_lon_deg) { poly_lon_str += " " + to_string(dbl); }
   std::string poly_lat_str = "";
   for(double dbl : p.p_lat_deg) { poly_lat_str += " " + to_string(dbl); }

   bool is_poly = (p.shape == area::POLYGON);


   out << to_string(p.skysys) << " : (" << p.lon_deg << ", " << p.lat_deg << ") "
      << to_string(p.shape) <<  " : ("
      << (is_poly ? poly_lon_str : to_string(p.dlon_deg)) << ", "
      << (is_poly ? poly_lat_str : to_string(p.dlat_deg)) << ") "
      << to_string(p.specsys) << " [km/s] : (" << p.vl_kmps << ", " << p.vu_kmps << ") "
//      << "POS(" << p.pos << ") "
//      << "BAND(" << to_string(p.bandsys) << "; " << p.band_value[0]  << ", " << p.band_value[1] << ") "
      << "TIME(" << to_string(p.timesys) << "; " << p.time_value[0]  << ", " << p.time_value[1] << ") "
      << "POL(" << pol_str << ")";
   return out;
}



