/**
 * @file Bancroft.hpp 
 * Use Bancroft method to get an initial guess of GPS receiver's position
 */
 
#ifndef BANCROFT_HPP
#define BANCROFT_HPP

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk 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 Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Dagoberto Salazar - gAGE. 2006
//
//============================================================================

#include <vector>
#include "Matrix.hpp"

using namespace std;
using namespace gpstk;

namespace gpstk
{
   /** @defgroup GPSsolutions GPS solution algorithms and Tropospheric models */
   //@{
       	
   /** This class defines an algebraic algorithm to get an initial guess of
    * GPS receiver's position given satellites' positions and pseudoranges.
    * The algorithm is based on Bancroft's Method as presented in: YANG, Ming &
    * Kuo-Hwa CHEN. ``Performance Assessment of a Noniterative Algorithm for 
    * Global Positioning System (GPS) Absolute Positioning''. Proc. Natl. Sci.
    * Counc. ROC(A). Vol. 25, No. 2, 2001. pp. 102-106.
    */
   class Bancroft
   {
   public:
      /// Constructor
      Bancroft() throw(Exception) : SecondSolution(4,0.0) { 
        testInput= true;
        ChooseOne = true;
        CloseTo = 6378137.0;
        minPRange = 15000000.0;
        maxPRange = 30000000.0;
        minRadius = 23000000.0;
        maxRadius = 29000000.0;
      };

      /** Compute an initial guess of GPS receiver's position , given satellites' 
       * positions and pseudoranges.
       * @param Data   Matrix of data containing observation data in rows, one
       *               row per observation and complying with this format:
       *
       *                        x y z P
       *
       *               Where x,y,z are satellite coordinates in an ECEF system
       *               and P is pseudorange (corrected as much as possible,
       *               specially from satellite clock errors), all expresed
       *               in meters.
       * @param X      Vector of position solution, in meters. There may be
       *               another solution that may be accessed with vector
       *               "SecondSolution" if "ChooseOne" is set to "false".
       *
       * @return
       *    0  Ok, 
       *   -1  Not enough good data
       *   -2  Singular problem
       */
      int Compute(Matrix<double>& Data, Vector<double>& X) throw(Exception);

      /// Another version of Compute method allowing calls with Matrix B being const.
      int Compute(const Matrix<double>& Data, Vector<double>& X) throw(Exception);

      // input:

      /** If true, the solution closest to CloseTo criterion will be chosen. If false, 
       * both posible solutions will be provided.
       */
      bool ChooseOne;

      /** Criterion to decide which solution to choose. The algorithm will choose the 
       * solution closer to this value. By default, it is set to earth radius, in meters.
       */
      double CloseTo;

      /** If true (the default), the B input Matrix will be screened to get out suspicious data.
       * It works with minPRange, maxPRange, minRadius and maxRadius to pick up a set of "clean
       * data". However, don't be too picky with these parameters in order to leave room for 
       * different GNSS systems and configurations. Anyway, Bancroft will give you just an
       * approximate position.
       */
      bool testInput;

      /// Minimum pseudorange value allowed for input data (in meters).
      double minPRange;

      /// Maximum pseudorange value allowed for input data (in meters).
      double maxPRange;

      /// Minimum allowed distance between Earth center and satellite position for input data (in meters).
      double minRadius;

      /// Maximum allowed distance between Earth center and satellite position for input data (in meters).
      double maxRadius;

      /** Vector<double> containing the estimated second position solution (ECEF, meter),
       * if ChooseOne is set to "false".
       */
      Vector<double> SecondSolution;

      /// Destructor.
      virtual ~Bancroft() throw() {};


   }; // end class Bancroft

   //@}

} // namespace gpstk

#endif
