//===========================================================================
// Copyright (C) 1998, 2000-2007, 2010, 2011, 2012 SINTEF ICT, Applied
// Mathematics, Norway.
//
// This file is part of GoTools
//
// 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 version 2 of the License. 
//
// 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, see <http://www.gnu.org/licenses>
//
// Contact information: E-mail: tor.dokken@sintef.no                      
// SINTEF ICT, Department of Applied Mathematics,                         
// P.O. Box 124 Blindern,                                                 
// 0314 Oslo, Norway.                                                     
//
// Other licenses are also available for this software, notably licenses
// for:
// - Building commercial software.                                        
// - Building software whose source code you wish to keep private.        
//===========================================================================

#ifndef __POINTSEQUENCE_H
#define __POINTSEQUENCE_H


#include <vector>
#include <algorithm>


namespace Go
{


  /// Type of point
  enum PointSequenceType
  {
    /// Each grid position holds a point
    PSTPoint,         
    /// Each grid position holds a point, then a tangent
    PSTPointTangent,  
    /// Regard this an unordered point cloud
    PSTScattered      
  };


  class PointSequence
  {

  public:

    /// Default constructor
    PointSequence()
      : dim_(-1), type_(PSTPoint)
    {
      grid_length_.resize(0);
    }


    /// Constructor given a sequence of points of a specified type
    template <typename RandomIterator> PointSequence(int dim,
						     int nmb_pts,
						     RandomIterator coefs_start,
						     PointSequenceType pst = PSTPoint)
      : dim_(dim), type_(pst)
    {
      grid_length_.resize(1);
      grid_length_[0] = nmb_pts;
      int coefs_size;
      switch (pst)
	{
	case PSTPoint:
	  coefs_size = nmb_pts * dim;
	  break;
	case PSTPointTangent:
	  coefs_size = 2 * nmb_pts * dim;
	  break;
	}
      coefs_.resize(coefs_size);
      copy(coefs_start, coefs_start + coefs_size, coefs_.begin());
    }



    /// Constructor given a number of sequences of points of a specified type,
    /// Each point sequence must contain the same number of points, i.e.
    /// two dimensional grid
    template <typename RandomIterator> PointSequence(int dim,
						     int nmb_pts_1,
						     int nmb_pts_2,
						     RandomIterator coefs_start,
						     PointSequenceType pst = PSTPoint)
      : dim_(dim), type_(pst)
    {
      grid_length_.resize(2);
      grid_length_[0] = nmb_pts_1;
      grid_length_[1] = nmb_pts_2;
      int coefs_size;
      switch (pst)
	{
	case PSTPoint:
	  coefs_size = nmb_pts_1 * nmb_pts_2 * dim;
	  break;
	case PSTPointTangent:
	  coefs_size = 2 * nmb_pts_1 * nmb_pts_2 * dim;
	  break;
	}
      coefs_.resize(coefs_size);
      copy(coefs_start, coefs_start + coefs_size, coefs_.begin());
    }



    /// Constructor given a 3 dimensional grid of points of a specified type
    template <typename RandomIterator> PointSequence(int dim,
						     int nmb_pts_1,
						     int nmb_pts_2,
						     int nmb_pts_3,
						     RandomIterator coefs_start,
						     PointSequenceType pst = PSTPoint)
      : dim_(dim), type_(pst)
    {
      grid_length_.resize(3);
      grid_length_[0] = nmb_pts_1;
      grid_length_[1] = nmb_pts_2;
      grid_length_[2] = nmb_pts_3;
      int coefs_size;
      switch (pst)
	{
	case PSTPoint:
	  coefs_size = nmb_pts_1 * nmb_pts_2 * nmb_pts_3 * dim;
	  break;
	case PSTPointTangent:
	  coefs_size = 2 * nmb_pts_1 * nmb_pts_2 * nmb_pts_3 * dim;
	  break;
	}
      coefs_.resize(coefs_size);
      copy(coefs_start, coefs_start + coefs_size, coefs_.begin());
    }


    // Destructor
    virtual ~PointSequence() { }


    /// Point dimension
    int dimension() const;

    /// Dimension of grid
    int grid_dimension() const;

    /// Length of grid in the given direction
    int grid_length(int i) const;

    /// Point type
    PointSequenceType type() const;

    /// Iterator to grid start
    std::vector<double>::iterator coefs_begin()
    { return coefs_.begin(); }

     /// Iterator to grid end
   std::vector<double>::iterator coefs_end()
    { return coefs_.end(); }

    /// Constant iterator to grid start
    std::vector<double>::const_iterator coefs_begin() const
    { return coefs_.begin(); }

    /// Constant iterator to grid end
    std::vector<double>::const_iterator coefs_end() const
    { return coefs_.end(); }


  private:

    std::vector<double> coefs_;      // The coordinates of the points
    int dim_;                        // The dimension of the space of points
    std::vector<int> grid_length_;   // Number of points in each direction in grid. grid_length_.size()
                                     // gives the grid dimension (flat, 2D, 3D, etc)
    PointSequenceType type_;

  };    // Class PointSequence


} // namespace Go


#endif    // #ifndef __POINTSEQUENCE_H
