/* 
   ORSA - Orbit Reconstruction, Simulation and Analysis
   Copyright (C) 2002-2004 Pasquale Tricarico
   
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.
   
   As a special exception, Pasquale Tricarico gives permission to
   link this program with Qt commercial edition, and distribute the
   resulting executable, without including the source code for the Qt
   commercial edition in the source distribution.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#ifndef _ORSA_FILE_JPL_H_
#define _ORSA_FILE_JPL_H_

namespace orsa {
  
  enum JPL_planets {
    NONE=0,
    MERCURY=1,
    VENUS=2,
    EARTH=3,
    MARS=4,
    JUPITER=5,
    SATURN=6,
    URANUS=7,
    NEPTUNE=8,
    PLUTO=9,
    MOON=10,
    SUN=11,
    SOLAR_SYSTEM_BARYCENTER=12,
    EARTH_MOON_BARYCENTER=13,
    NUTATIONS=14,
    LIBRATIONS=15,
    EARTH_AND_MOON=1000
  };
  // note: EARTH_AND_MOON is only an useful definition, not used in orsa files or by JPL...
  // same thing for NONE...
  
} // namespace orsa 

#include <string>
#include <map>
#include <list>

#include "orsa_units.h"
#include "orsa_coord.h"
// #include "orsa_body.h"

namespace orsa {
  
  class Body;
  class BodyWithEpoch;
  class JPLBody;
  class Frame;
  class Date;
  class UniverseTypeAwareTime;
  
  inline void convert(JPL_planets & jp, const unsigned int i)  {
    switch(i) {
    case 0:  jp = NONE;                    break;
      //
    case 1:  jp = MERCURY;                 break;
    case 2:  jp = VENUS;                   break;
    case 3:  jp = EARTH;                   break;
    case 4:  jp = MARS;                    break;
    case 5:  jp = JUPITER;                 break;
    case 6:  jp = SATURN;                  break;
    case 7:  jp = URANUS;                  break;
    case 8:  jp = NEPTUNE;                 break;
    case 9:  jp = PLUTO;                   break;
    case 10: jp = MOON;                    break;
    case 11: jp = SUN;                     break;
    case 12: jp = SOLAR_SYSTEM_BARYCENTER; break;
    case 13: jp = EARTH_MOON_BARYCENTER;   break;
    case 14: jp = NUTATIONS;               break;
    case 15: jp = LIBRATIONS;              break;
      //
    case 1000: jp = EARTH_AND_MOON;        break;
      //
    default:
      ORSA_ERROR("conversion problem: i = %i",i);    
      break;
    }
  }
  
  //! JPL ephem file  
  class JPLFile {
  public:
    JPLFile(std::string);
    ~JPLFile();
    
  public:
    // basic one, just to check if the db is a working JPL ephem file
    bool GoodFile() const {
      return (jpl_database != 0);
    }
    
  public:
    void GetEph(const UniverseTypeAwareTime & date, JPL_planets target, JPL_planets center, Vector & position, Vector & velocity);       
    inline void GetEph(const UniverseTypeAwareTime & date, JPL_planets target, Vector & position, Vector & velocity) {
      GetEph(date, target, default_ephem_center, position, velocity);       
    }
    
    const UniverseTypeAwareTime & EphemStart();
    const UniverseTypeAwareTime & EphemEnd();
    
    double GetMass(JPL_planets planet);
    
    double GetAU_MKS();
    double GetMSun_MKS();
    double GetMJupiter_MKS();
    double GetMEarth_MKS();
    double GetMMoon_MKS();
    double GetC_MKS(); // speed of light
    double GetREarth_MKS();
    double GetRMoon_MKS();
    
  public:
    double GetTag(std::string);
    
  private:
    std::map <std::string,double> * map_tag;
    
  private:
    bool bool_ephem_start_computed;
    bool bool_ephem_end_computed;
    void ComputeEphemStart();
    void ComputeEphemEnd();
    
  private:
    static const JPL_planets default_ephem_center;
    
  private:
    void * jpl_database;
    bool calc_velocity;
    // 
    UniverseTypeAwareTime ephem_start;
    UniverseTypeAwareTime ephem_end;
   };  
  
  // defined in orsa_universe.cc
  extern JPLFile * jpl_file;
  
  class JPLCache {
  public:
    JPLCache();
    ~JPLCache();
  public:
    const JPLBody & GetJPLBody(const JPL_planets, const UniverseTypeAwareTime &);
  public:
    void Clear();
  private:
    typedef std::map <UniverseTypeAwareTime,JPLBody> data_map_type; 
    typedef std::map <JPL_planets,data_map_type> big_map_type;
    big_map_type big_map;
  };
  
  // defined in orsa_universe.cc
  extern JPLCache * jpl_cache;
  
  // bool is_genuine_planet(const JPL_planets p);
  
  std::string JPL_planet_name(const JPL_planets p);
  
  double radius(const JPL_planets p);
  
  void SetupSolarSystem(Frame &, const std::list<JPL_planets> &, const UniverseTypeAwareTime &);
  
} // namespace orsa

#endif // _ORSA_FILE_JPL_H_
