#pragma ident "$Id: Namelist.hpp 286 2006-11-08 02:21:51Z ocibu $"

//============================================================================
//
//  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
//  
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

//============================================================================
//
//This software developed by Applied Research Laboratories at the University of
//Texas at Austin, under contract to an agency or agencies within the U.S. 
//Department of Defense. The U.S. Government retains all rights to use,
//duplicate, distribute, disclose, or release this software. 
//
//Pursuant to DoD Directive 523024 
//
// DISTRIBUTION STATEMENT A: This software has been approved for public 
//                           release, distribution is unlimited.
//
//=============================================================================

/**
 * @file Namelist.hpp
 * Include file defining class Namelist.
 * class gpstk::Namelist encapsulates a list of labels for use with classes Matrix,
 * Vector and SRI.
 */

#ifndef CLASS_NAMELIST_INCLUDE
#define CLASS_NAMELIST_INCLUDE

//------------------------------------------------------------------------------------
// system includes
#include <string>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <ostream>
#include <sstream>
// GPSTk
#include "Matrix.hpp"

namespace gpstk
{

//------------------------------------------------------------------------------------
class Namelist;
/// class LabelledVector. Pretty print a Vector using the labels in a Namelist.
class LabelledVector {
public:
   int wid,prec,form;
   std::string msg;
   const Namelist& NL;
   Vector<double>& V;
   LabelledVector(const Namelist& nl, Vector<double>& v)
      : wid(12), prec(5), form(1), NL(nl), V(v) { }
   LabelledVector& setw(int w) { wid = w; return *this; }
   LabelledVector& setprecision(int p) { prec = p; return *this; }
   LabelledVector& fixed(void) { form = 1; return *this; }
   LabelledVector& scientific(void) { form = 2; return *this; }
   LabelledVector& message(const std::string& m) { msg=m; return *this; }
};

/// class LabelledMatrix. Pretty print a Matrix using the labels in a Namelist.
class LabelledMatrix {
public:
   int wid,prec;
   int form;         // format: 1=fixed, 2=scientific
   int rc;           // rows only (1) columns only (2) or both (0)
   std::string msg;
   const Namelist& NLrows;
   const Namelist& NLcols;
   const Matrix<double>& M;
   LabelledMatrix(const Namelist& nl, const Matrix<double>& m)
      : wid(12), prec(5), form(1), rc(0), NLrows(nl), NLcols(nl), M(m) { }
   LabelledMatrix(const Namelist& nlr, const Namelist& nlc, const Matrix<double>& m)
      : wid(12), prec(5), form(1), rc(0), NLrows(nlr), NLcols(nlc), M(m) { }
   LabelledMatrix& setw(int w) { wid = w; return *this; }
   LabelledMatrix& setprecision(int p) { prec = p; return *this; }
   LabelledMatrix& fixed(void) { form = 1; return *this; }
   LabelledMatrix& scientific(void) { form = 2; return *this; }
   LabelledMatrix& rows(void) { rc=1; return *this; }
   LabelledMatrix& cols(void) { rc=2; return *this; }
   LabelledMatrix& message(const std::string& m) { msg=m; return *this; }
};

std::ostream& operator<<(std::ostream&, const LabelledMatrix&);
std::ostream& operator<<(std::ostream&, const LabelledVector&);


//------------------------------------------------------------------------------------
/** class Namelist. A Namelist is simply an ordered set of unique strings ('names' or
 * 'labels') of any length. Namelists are used to label or identify elements of
 * Vectors or Matrix rows and columns. Namelist is particularly useful in class SRI,
 * which includes a Matrix and Vector that hold state and covariance information in
 * an estimation problem; SRI include a Namelist which associates readable labels with
 * the elements of the state and covariance.
 */

class Namelist {
   friend class SRI;
   friend std::ostream& operator<<(std::ostream&, const LabelledMatrix&);
   friend std::ostream& operator<<(std::ostream&, const LabelledVector&);
public:
      /// empty constructor
   Namelist(void) {}
      /// constructor given dimension - creates default labels
   Namelist(const unsigned int&);
      /// explicit constructor - only a unique subset of the input will be included.
   Namelist(const std::vector<std::string>&);
      /// copy constructor
   Namelist(const Namelist& names) { labels = names.labels; }
      /// destructor
   ~Namelist(void) { labels.clear(); }

      /// operator=
   Namelist& operator=(const Namelist& right)
      { labels = right.labels; return *this; }
      /// add a single name to the Namelist; do nothing if the name is not unique.
   Namelist& operator+=(const std::string&);
      /// remove a name from the Namelist; does nothing if the name is not found.
   Namelist& operator-=(const std::string&);

      /// swap two elements, as given by their indexes; no effect if either index
      /// is out of range.
   void swap(const unsigned int&, const unsigned int&);
      /// reorder the list by sorting
   void sort(void);
      /// resize the list by either truncation or adding default names.
   void resize(unsigned int);
      /// randomize the list
   void randomize(long seed=0);
      /// empty the list
   void clear(void) { labels.clear(); }

      /// is the Namelist valid? checks for repeated names
      /// (? not possible to create an invalid Namelist?)
   bool valid(void) const;
      /// does the Namelist contain the input name?
   bool contains(const std::string&) const;
      /// are two Namelists identical, ignoring permutations?
   friend bool operator==(const Namelist&, const Namelist&);
      /// are two Namelists different, ignoring permutations?
   friend bool operator!=(const Namelist&, const Namelist&);
      /// are two Namelists exactly identical, even considering permutations?
   friend bool identical(const Namelist&, const Namelist&);

      /// construct the subset Namelist which is common to the two inputs (AND)
   friend Namelist operator&(const Namelist&, const Namelist&);
      /// merge two Namelists, i.e. construct a non-redundant combination (OR)
   friend Namelist operator|(const Namelist&, const Namelist&);
      /// construct the subset Namelist which is NOT common to two others (XOR)
   friend Namelist operator^(const Namelist&, const Namelist&);
      /// replace this with (this & input)
   Namelist& operator&=(const Namelist&);
      /// replace this with (this | input)
   Namelist& operator|=(const Namelist&);
      /// replace this with (this ^ input)
   Namelist& operator^=(const Namelist&);

      /// bind a Namelist to a Matrix<double> before sending it to an output
      /// stream, to get a 'labelled display' of the matrix.
   LabelledMatrix operator()(Matrix<double>& m)
      { return LabelledMatrix(*this,m); }

      /// bind a Namelist to a Vector<double> before sending it to an output
      /// stream, to get a 'labelled display' of the vector.
   LabelledVector operator()(Vector<double>& v)
      { return LabelledVector(*this,v); }

      // member access

      /// return the size of the list.
   inline unsigned int size(void) const { return labels.size(); }

   //std::string& operator[](const unsigned int);
   //Don't do this, b/c it means user could create invalid Namelists,
   //and b/c passing an invalid int would require a throw

      /// access to a specific name, given its index.
      /// returns 'out-of-range' if the index is out of range.
   std::string getName(const unsigned int) const;

      /// assign a specific name, given its index;
      /// no effect if the name is not unique;
      /// return true if successful.
   bool setName(const unsigned int, const std::string&);

      /// return the index of the name in the list that matches the input,
      /// -1 if not found.
   int index(const std::string&) const;

      /// output operator
   friend std::ostream& operator<<(std::ostream& s, const Namelist&);

   // member data

      /// vector of names (strings)
   std::vector<std::string> labels;

//private:
}; // end class Namelist

} // end of namespace gpstk

#endif
