// Copyright (C) 1999-2014
// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
// For conditions of distribution and use, see copyright notice in "copyright"

#include "coord.h"
#include "util.h"

Coord coord;

char* Coord::coordSystemStr_[] = {
  "data",
  "image",
  "physical",
  "amplifier",
  "detector",
  "wcs",
  "wcsa",
  "wcsb",
  "wcsc",
  "wcsd",
  "wcse",
  "wcsf",
  "wcsg",
  "wcsh",
  "wcsi",
  "wcsj",
  "wcsk",
  "wcsl",
  "wcsm",
  "wcsn",
  "wcso",
  "wcsp",
  "wcsq",
  "wcsr",
  "wcss",
  "wcst",
  "wcsu",
  "wcsv",
  "wcsw",
  "wcsx",
  "wcsy",
  "wcsz",
  "wcs0"
};

char* Coord::skyFrameStr_[] = { 
  "fk4",
  "fk4-no-e",
  "fk5",
  "icrs",
  "galactic",
  "supergalactic",
  "ecliptic",
  "helioecliptic",
  "gappt"
};

char* Coord::skyFormatStr_[] = { 
  "degrees",
  "sexagesimal",
};

char* Coord::skyDistStr_[] = {
  "degrees",
  "arcmin",
  "arcsec"
};

void Coord::listCoordSystem(ostream& str, CoordSystem sys, SkyFrame sky, 
		     int wcs, int wcsequ)
{
  switch (sys) {
  case IMAGE:
    str << "image";
    return;
  case PHYSICAL:
    str << "physical";
    return;
  case DETECTOR:
    str << "detector";
    return;
  case AMPLIFIER:
    str << "amplifier";
    return;
  default:
    {
      if (wcs)
	if (sys == WCS0)
	  str << "wcs0" << ';';
	else if (sys == WCS && !wcsequ)
	  str << "wcs" << ';';
	else if (sys > WCS  && !wcsequ)
	  str << "wcs" << (char)(sys-WCS+'`') << ';';
      
      if (wcsequ) {
	switch (sky) {
	case FK4:
	  str << "fk4";
	  return;
	case FK4_NO_E:
	  str << "fk4-no-e";
	  return;
	case FK5:
	  str << "fk5";
	  return;
	case ICRS:
	  str << "icrs";
	  return;
	case GALACTIC:
	  str << "galactic";
	  return;
	case SUPERGALACTIC:
	  str << "supergalactic";
	  return;
	case ECLIPTIC:
	  str << "ecliptic";
	  return;
	case HELIOECLIPTIC:
	  str << "helioecliptic";
	  return;
	}
      }
    }
  }
}

void Coord::listDistSystem(ostream& str, CoordSystem sys, SkyDist format, int wcsequ)
{
  switch (sys) {
  case IMAGE:
    str << "image";
    return;
  case PHYSICAL:
    str << "physical";
    return;
  case DETECTOR:
    str << "detector";
    return;
  case AMPLIFIER:
    str << "amplifier";
    return;
  default:
    if (wcsequ)
      switch (format) {
      case DEGREE:
	str << "degrees";
	return;
      case ARCMIN:
	str << "arcmin";
	return;
      case ARCSEC:
	str << "arcsec";
	return;
      }
    else {
      str << "pixels";
      return;
    }
  }
}

 void Coord::listProsCoordSystem(ostream& str, CoordSystem sys, SkyFrame sky)
{
  switch (sys) {
  case IMAGE:
    str << "logical";
    return;
  case PHYSICAL:
    str << "physical";
    return;
  case DETECTOR:
    str << "detector";
    return;
  case AMPLIFIER:
    str << "amplifier";
    return;
  default:
    switch (sky) {
    case FK4:
      str << "b1950";
      return;
    case FK4_NO_E:
      str << "fk4-no-e";
      return;
    case FK5:
      str << "j2000";
      return;
    case ICRS:
      str << "icrs";
      return;
    case GALACTIC:
      str << "galactic";
      return;
    case SUPERGALACTIC:
      str << "supergalactic";
      return;
    case ECLIPTIC:
      str << "ecliptic";
      return;
    case HELIOECLIPTIC:
      str << "helioecliptic";
      return;
    }
  }
}

 void Coord::strToCoordSystem(const char* str, CoordSystem wcssys, 
			      CoordSystem* sys, SkyFrame* sky)
{
  if (!str) {
    *sys = PHYSICAL;
    *sky = FK5;
  }
  else if (STRCMP(str,"image",5)) {
    *sys = IMAGE;
    *sky = FK5;
    }
  else if (STRCMP(str,"physical",8)) {
    *sys = PHYSICAL;
    *sky = FK5;
  }
  else if (STRCMP(str,"amplifier",9)) {
    *sys = AMPLIFIER;
    *sky = FK5;
  }
  else if (STRCMP(str,"detector",9)) {
    *sys = DETECTOR;
    *sky = FK5;
  }
  else if (STRCMP(str,"fk4-no-e",8)) {
    *sys = wcssys;
    *sky = FK4_NO_E;
  }
  else if (STRCMP(str,"fk4",3)) {
    *sys = wcssys;
    *sky = FK4;
  }
  else if (STRCMP(str,"fk5",3)) {
    *sys = wcssys;
    *sky = FK5;
  }
  else if (STRCMP(str,"icrs",4)) {
    *sys = wcssys;
    *sky = ICRS;
  }
  else if (STRCMP(str,"galactic",8)) {
    *sys = wcssys;
    *sky = GALACTIC;
  }
  else if (STRCMP(str,"supergalactic",12)) {
    *sys = wcssys;
    *sky = SUPERGALACTIC;
  }
  else if (STRCMP(str,"ecliptic",8)) {
    *sys = wcssys;
    *sky = ECLIPTIC;
  }
  else if (STRCMP(str,"helioecliptic",12)) {
    *sys = wcssys;
    *sky = HELIOECLIPTIC;
  }
  else if (STRCMP(str,"wcs",3)) {
    *sys = wcssys;
    *sky = FK5;
  }
  else if (STRCMP(str,"linear",6)) {
    *sys = wcssys;
    *sky = FK5;
  }
  else {
    *sys = PHYSICAL;
    *sky = FK5;
  }
}

void Coord::strToSkyFormat(const char* str, SkyFormat* format)
{
  if (!str)
    *format = DEGREES;
  else if (STRCMP(str,"degrees",7))
    *format = DEGREES;
  else if (STRCMP(str,"degree",6))
    *format = DEGREES;
  else if (STRCMP(str,"deg",3))
    *format = DEGREES;
  else if (STRCMP(str,"hms",3))
    *format = SEXAGESIMAL;
  else if (STRCMP(str,"h:m:s",5))
    *format = SEXAGESIMAL;
  else if (STRCMP(str,"\"h:m:s\"",7))
    *format = SEXAGESIMAL;
  else if (STRCMP(str,"dms",3))
    *format = SEXAGESIMAL;
  else if (STRCMP(str,"d:m:s",5))
    *format = SEXAGESIMAL;
  else if (STRCMP(str,"\"d:m:s\"",7))
    *format = SEXAGESIMAL;
  else
    *format = DEGREES;
}

void Coord::strToSkyDist(const char* str, SkyDist* dist)
{
  if (!str)
    *dist = DEGREE;
  else if (STRCMP(str,"degrees",7))
    *dist = DEGREE;
  else if (STRCMP(str,"degree",6))
    *dist = DEGREE;
  else if (STRCMP(str,"deg",3))
    *dist = DEGREE;
  else if (STRCMP(str,"arcminute",9))
    *dist = ARCMIN;
  else if (STRCMP(str,"arcmin",6))
    *dist = ARCMIN;
  else if (STRCMP(str,"arcsecond",9))
    *dist = ARCSEC;
  else if (STRCMP(str,"arcsec",6))
    *dist = ARCSEC;
  else
    *dist = DEGREE;
}

 void Coord::strToAngleFormat(const char* str, AngleFormat* format)
{
  if (!str)
    *format = DEG;
  else if (STRCMP(str,"degrees",7))
    *format = DEG;
  else if (STRCMP(str,"degree",6))
    *format = DEG;
  else if (STRCMP(str,"deg",3))
    *format = DEG;
  else if (STRCMP(str,"radian",6))
    *format = RAD;
  else if (STRCMP(str,"rad",3))
    *format = RAD;
  else
    *format = DEG;
}

void Coord::strToDistSystem(const char* str, CoordSystem wcssys, 
			    CoordSystem* sys, SkyDist* dist)
{
  if (!str) {
    *sys = PHYSICAL;
    *dist = DEGREE;
  }
  else if (STRCMP(str,"image",5)) {
    *sys = IMAGE;
    *dist = DEGREE;
    }
  else if (STRCMP(str,"physical",8)) {
    *sys = PHYSICAL;
    *dist = DEGREE;
  }
  else if (STRCMP(str,"amplifier",9)) {
    *sys = AMPLIFIER;
    *dist = DEGREE;
  }
  else if (STRCMP(str,"detector",8)) {
    *sys = DETECTOR;
    *dist = DEGREE;
  }
  else if (STRCMP(str,"degrees",7)) {
    *sys = wcssys;
    *dist = DEGREE;
  }
  else if (STRCMP(str,"arcmin",6)) {
    *sys = wcssys;
    *dist = ARCMIN;
  }
  else if (STRCMP(str,"arcsec",6)) {
    *sys = wcssys;
    *dist = ARCSEC;
  }
  else if (STRCMP(str,"pixels",6)) {
    *sys = PHYSICAL;
    *dist = DEGREE;
  }
  else {
    *sys = PHYSICAL;
    *dist = DEGREE;
  }
}
