// $Header: https://oberon.oapd.inaf.it/shins/branches/unstable/shins/test/iifApp.cpp 314 2017-11-22 16:16:12Z depa $

#include "iifApp.h"

int
iifApp::usage ( int _ret )
{
  std::cerr << "Usage: " << appName() << " --CONNECT:Endpoint=[..]\n";
  std::cerr << "Options:\n"
    "-h, --help                                       Show this message.\n"
    "-v, --version                                    Display version.\n"
    "\n"
    "\n"
    "--CONNECT:Endpoint=[NAME=NODENAME,...]          NAME=NODENAME  - name of the service\n"
    "                                                PORT=intval    - tcp port of the service\n"
    "                                                HOST=string    - tcp host address of the service\n"
    "                                                MULTICAST=true - resolve service by multicast\n"
    "\n"
    "Examples:\n"
    "\n";
  std::cerr  << appName() << " --CONNECT:Endpoint=[NAME=svc,HOST=host,PORT=4711]\n";
  std::cerr  << appName() << " --CONNECT:Endpoint=[NAME=svc,PORT=4711]\n";
  std::cerr  << appName() << " --CONNECT:Endpoint=[NAME=svc,MULTICAST=1]\n"
    "\n"
    "Hints:\n"
    " Don't put spaces in commandline arguments or use quotes\n"
    " NO: --CONNECT:Endpoint=[NAME=svc, PORT=4711]\n"
    " OK: --CONNECT:Endpoint=\"[NAME=svc, PORT=4711]\"\n"
    "\n"
    "\n"
    ;
  return _ret;
}

int
iifApp::run ( int argc, char* argv[] )
{
  std::string ddname = "L_AOmode"; // asked via getDouble
  lbto::DDstruct ddt;
  lbto::SeqDD dd;
  lbto::SeqPos2 stars, refs;
  lbto::position2 target, guideStar, reference;
  lbto::result res;
  // Ltcs::IifServiceWorkerInterfacePtr iif;
  std::string endPointName = "CONNECT";
  std::string serviceName = "IIF.SVC";// "Factory";
  
  
  U1_LOG(config()->leaf("CONNECT"));

  reference = {
    "SIDEREAL",
    0.009,
    0.01,
    "RADEC",
    2000.0,
    "J2000",
    0.0,
    0.0,
    0.0,
    "U",
    0.0,
    "U_B",
    0.8,
    "",
    0,
    0,
    0
  };
  refs.push_back(reference);
  if(config()->getAtNode<Nice::Endpoint>(endPointName) != Nice::Endpoint())
   {
      try
        {
          U2_LOG("Trying")
          // NOTE: IIF
          Nice::Endpoint p = config()->getAtNode<Nice::Endpoint>(endPointName);
          // Nice::Endpoint p = Nice::Endpoint::fromString("[NAME=ltcs.iif-svr,TCP=localhost:10000,TIMEOUT=10]");
          U2_LOG("Trying2");
          Nice::AppConfigClientPtr con = Nice::AppConfigClient::create(p, config()->node("DATA"));
          U2_LOG("Trying3");
          m_iif = Ltcs::IifServiceWorkerInterface::create(config()->node("DATA."+serviceName));
          U3_LOG("> Service Name :" << m_iif->readServiceName());

          U3_LOG(argc);
          for (int ii=0; ii<argc; ii++)
            {
              U3_LOG(argv[ii])
                }

          if (argc > 3)
            {
              std::string str;
              for (int i = 3; i < argc; i++)
                {
                  str = argv[i];
                  U3_LOG(argv[i]);
                  if ( str.substr ( 0, 2 ) == "--" )
                    {
                      if (str.substr(2) == "authorize")
                        {
                          U3_LOG("Going to ask if LBTI is authorized ... ");
                          res = m_iif->iifAuthorize();
                          U3_LOG("Asked");
                          if (!res.rescode)
                            {
                              U8_LOG("Test of new parameter passed")
                                // return EXIT_SUCCESS;
                                }
                          else {return EXIT_FAILURE;}
                        }
                    }
                }
            }



          U3_LOG("> Is reachable :" << m_iif->isReachable());
          U2_LOG("> RA           :" << m_iif->getRA());
          U2_LOG("> DEC          :" << m_iif->getDEC());
          U2_LOG("> " << ddname << "     :" << m_iif->getDouble(ddname, "log"));

          ddt.DDname = "L_Instrument";
          dd.push_back(ddt);
          ddt.DDname = "L_AOmode";
          dd.push_back(ddt);
          ddt.DDname = "L_AOShape";
          dd.push_back(ddt);
          ddt.DDname = "L_AOStatus";
          dd.push_back(ddt);
          ddt.DDname = "L_AOaoReady";
          dd.push_back(ddt);
          res = m_iif->iifGetParameter(dd);


          U2_LOG("> iifGetParameter :" << m_iif->iifGetParameter(dd));
          U2_LOG(res.resmsg);
          U2_LOG("> getLINCstation  :" << m_iif->getLINCstation());
          // U2_LOG(m_iif->readPosition());
          U2_LOG("> PA           :" << m_iif->getParallacticAngle());
          U2_LOG("> UTC          :" << m_iif->getUTC());
          U2_LOG("> LST          :" << m_iif->getLST());
          // U2_LOG("> Hour Angle   :" << m_iif->getHourAngle());
          U2_LOG(m_iif->iifAuthorize()); // instrument authorized on service startup
          // U2_LOG(m_iif->iifAuthorizeGet()); // instrument authorized on service startup

          target = {"SIDEREAL", //object type 
                    3.399,      // RA or AZ (radian)
                    1.0009,     // DEC or ALT (radian)
                    "RADEC",    // "RADEC", "AZALT"
                    2000.0,     // epoch (year)
                    "J2000",    // equinox "J2000"
                    0,          // proper motion dRA/dt cos(DEC) (radian/yr)
                    0,          // proper motion dDEC/dt (radian/yr)
                    0,          // magnitude
                    "U",        // filter name
                    0,          // color index
                    "U_B",      // color type
                    0.8,        // wavelength (microns)
                    "",         // non-sidereal ephemeris file name
                    0,          // DIFFERENTIAL MJD (UT days)
                    0,          // DIFFERENTIAL dRA/dt * cos(DEC) (radian/day)
                    0           // DIFFERENTIAL dDEC/dt (radian/day)
          };

          guideStar = {"SIDEREAL", //object type 
                       1.399,      // RA or AZ (radian)
                       1.0009,     // DEC or ALT (radian)
                       "RADEC",    // "RADEC", "AZALT"
                       2000.0,     // epoch (year)
                       "J2000",    // equinox "J2000"
                       0,          // proper motion dRA/dt cos(DEC) (radian/yr)
                       0,          // proper motion dDEC/dt (radian/yr)
                       0,          // magnitude
                       "U",        // filter name
                       0,          // color index
                       "U_B",      // color type
                       0.4,        // wavelength (microns)
                       "",         // non-sidereal ephemeris file name
                       0,          // DIFFERENTIAL MJD (UT days)
                       0,          // DIFFERENTIAL dRA/dt * cos(DEC) (radian/day)
                       0           // DIFFERENTIAL dDEC/dt (radian/day)
          };

          stars.push_back(target);
          stars.push_back(guideStar); // guide star MUST be specified before preset

          U2_LOG(m_iif->iifSetStars2(stars));
          if (res.rescode == EXIT_SUCCESS)
            U2_LOG(res.rescode);
          U2_LOG(m_iif->iifSetReference2(refs)); // AO reference star
          //stars = m_iif->getPresetStars();
          //U2_LOG("> getPresetStars :" << pos.size());
          U2_LOG("> iifPresetTelescopeStart :" << m_iif->iifPresetTelescopeStart(0.0,                 // rotator angle
                                                                               "POSITION",            // rotator mode
                                                                               "ADAPTIVEACE_TRACK",   // telescope mode
                                                                               "left"                 // side
                                                                               ));
          U2_LOG("> iifPresetTelescopeWait: " << m_iif->iifPresetTelescopeWait());
          // U2_LOG(m_iif->setPresetTelescopeGet());
          U2_LOG("> Alt          :" << m_iif->getAlt());
          U2_LOG("> AZ           :" << m_iif->getAz());
          U2_LOG("> Epoch        :" << m_iif->getEpoch());
          U2_LOG("> RA  Radians  :" << m_iif->getRAradians());
          U2_LOG("> DEC Radians  :" << m_iif->getDECradians());
          // U2_LOG(m_iif->setOffsetPointing(double _offx, double _offy, std::string __coordsys, std::string __move_type, std::string __side));
          // U2_LOG(m_iif->getRotatorPolynomials(double __starttime, int __count, double __interval, int __order, std::string __side));
          // U2_LOG(m_iif->getKFPCoordinates(std::string __side));
          // U2_LOG("> Preset stars :" << m_iif->getPresetStars());
          U2_LOG("> RunAO        :" << m_iif->iifRunAO("NORMAL", // TYPE: Issues an AcquireRefAO without rePoint followed by a StartAO.
                                                     "left" // side
                                                     ))
          U2_LOG("> is slewing   :" << m_iif->isSlewing());
          Nice::SeqSeqDouble traj;
          double trajStartTime = Nice::Date::now().toMJD();
          double trajInterval = 60; // seconds
          int trajPolyCount = 120;  // number of polynomials
          int trajPolyOrder = 2;
          std::string side = "left";

          traj = m_iif->getRotatorPolynomials(trajStartTime, trajPolyCount, trajInterval, trajPolyOrder, side);
          U2_LOG(traj);
          writeTrajOnFile(traj);

          U2_LOG("> MoveXY       :" << m_iif->iifMoveXY(1.000,-0.810,"M1","left"));
        }
      catch (const Nice::Exception & ex)
        {
          U2_LOG("Exception!!");
          E_LOG(ex);
          return 1;
        }
   }
  return 0;
}


void iifApp::interruptCallback( int _sig)
{
  N_LOG("Interrupt #" << _sig);
}

// void iifApp::interruptCallback(int _sig)
// {
//   N_LOG( "Interrupt #" << _sig);
//   //    Basda::ServiceWorkerInterface::terminateAll( );
// }


int iifApp::writeTrajOnFile(const Nice::SeqSeqDouble &_trajSet)
{
  std::ofstream trajLog;
  trajLog.open("traj_log.dat");
  if (!trajLog)
    {
      E_LOG("Cannot open out file for trajcetory log!");
      return 1;
    }
  trajLog.precision(6);
  for (BOOST_AUTO(itTraj,_trajSet.begin()); itTraj < _trajSet.end(); ++itTraj)
    {
      for (BOOST_AUTO(it, itTraj->begin()); it < itTraj->end(); ++it)
        {
          trajLog.precision(6);
          trajLog << std::fixed << *it << '\t';
        }
      trajLog << std::endl;
    }
  trajLog.close();
  return 0;
}





int main(int argc, char* argv[])
{
  std::cout << "> The following command is working." << std::endl;
  std::cout << "./iifApp --CONNECT:Endpoint=[NAME=ltcs.iif-svr,TCP=localhost:10000,TIMEOUT=10] --LOGGER.LEVEL:LogLevel=DEBUG $* " << std::endl;

  iifApp app;
  app.start(argc, argv);
}
