////////////////////////////////////////////////////////////////////////
///
/// \class SNORope
///
/// \brief  G4VSolid class to describe the vertical parts of the rope structure.
///  This DOES NOT include parts of the rope that directly contact the sphere- the belly plates and the
///  hold down rope net are described by the SNORopeNet class.
///
/// \author Aksel Hallin  aksel.hallin@ualberta.ca
///
/// REVISION HISTORY:\n
///     Jun 13, 2014 :  Aksel Hallin  \n
///
/// \detail
////
////////////////////////////////////////////////////////////////////////

#ifndef RAT__SNORope_HH_
#define RAT__SNORope_HH_

#include <RAT/SphericalSubregionList.hh>
#include <G4VSolid.hh>
#include <list>

namespace RAT{
class SNORope:public SphericalSubregionList{
public:
    /// Constructor.  A SNORope describes the entire SNORope system, including upward ropes, downward ropes, the rope net and the rope loops.
    SNORope(const G4String &aTitle);
    /// Return a list of intersections with cylinders that inscribe and circumscribe the vertical portions of either the upward or the downward ropes
    /// @param[in] aPosition Starting point of trajectory
    /// @param[in] aDirection Unit vector in direction of trajectory
    /// @param[out] distances[4][2] The distance values found.  The first index corresponds to the cylindrical radius of the rope net, the second to first or second solution
    /// @param[out]list  A list of solutions that are greater than zero.
    void CalculateCylindricalPoints(const G4ThreeVector &aPosition, const G4ThreeVector &aDirection, G4double distances[4][2],std::list<G4double> &list)const;
    /// Return the closest intersections with cylinders that inscribe and circumscribe the vertical portions of either the upward or the downward ropes
    /// @param[in] aPosition Starting point of trajectory
    /// @param[in] aDirection Unit vector in direction of trajectory
    /// @param[in] aRadius  The radius of the cylinder
    /// @param[out]Dist  The closest positive solution
    void CalculateCylindricalPoints(const G4ThreeVector &aPosition, const G4ThreeVector &aDirection, G4double aRadius,G4double &dist)const;
    /// Implements the G4VSolid function
    G4bool CalculateExtent(const EAxis, const G4VoxelLimits &, const G4AffineTransform &, G4double &, G4double &) const;
    /// Implements the G4VSolid function
    void DescribeYourselfTo(G4VGraphicsScene &)const;
    /// Implements the G4VSolid function
    G4double DistanceToIn(const G4ThreeVector& p, const G4ThreeVector& v)const;
    /// Implements the G4VSolid function
    G4double DistanceToIn(const G4ThreeVector& p)const;
    /// Implements the G4VSolid function
    G4double DistanceToOut(const G4ThreeVector& p,const G4ThreeVector& v,
             const G4bool calcNorm=false, G4bool *validNorm=0, G4ThreeVector *n=0)const;
    /// Implements the G4VSolid function
    G4double DistanceToOut(const G4ThreeVector& p)const;
    /// Calculates the distance to the next intersection, starting from point p and in direction v.  Used by both DistanceToIn and DistanceToOut
    G4double DistanceToNext(const G4ThreeVector &p, const G4ThreeVector &v,NextMode aNextMode)const;
    /// Implements the G4VSolid function
    G4GeometryType GetEntityType(void)const;
    /// Implements the G4VSolid function
    G4VisExtent GetExtent() const;
    /// Implements the G4VSolid function
    G4ThreeVector GetPointOnSurface() const;
    /// Implements the G4VSolid function
    EInside Inside(const G4ThreeVector &p)const;
    /// Returns the actual position of a point on the center of the rope corresponding to an angle phi (typically a 1 degree wide bin)
    /// @param[in] phi  The angle at which you want to find the rope
    /// @return  a position of a point at the center of the rope.
    const  G4ThreeVector *RopePosition(const G4double phi)const;
    /// Returns the actual position of a point on the center of the rope corresponding to an angle phi (typically a 1 degree wide bin)
    /// This also sets the top and bottom positions of the appropriate rope, and the radius (thickness) of the rope
    /// @param[in] phi  The angle at which you want to find the rope
    /// @param[out] zmin The bottom position of the rope
    /// @param[out] zmax The top of the rope
    /// @param[out] radius The thickness of the rope
    /// @return  a position of a point at the center of the rope.
    const  G4ThreeVector *RopePosition(const G4double phi, G4double &zmin, G4double &zmax, G4double &radius)const;
    /// Implements the G4VSolid function
    std::ostream& StreamInfo(std::ostream &)const;
    /// SurfaceNormal A spherical subregion needs to implement this to provide G4VSolid routines.
    using SphericalSubregionList::SurfaceNormal;  //get rid of warnings about hidden methods...
    G4ThreeVector SurfaceNormal(const G4ThreeVector &p, G4bool &isValid)const;

private:
    G4double fAVRadius;  ///<  Outer radius of the AV
    G4double fRopeCylinderRadius; ///< Distance from the axis of the AV to the "inside" surface of the upward ropes
    G4double fUpRopeRadius ;  ///< Radius of the upward ropes
    G4double fDownRopeRadius; ///< Radius of the downward Ropes
    G4double fRadii[2]; ///< Inside and outside cylindrical radii that inscribe and circumscribe the vertical ropes.
    G4double fThreshold; ///<  Geant4 tolerance to determine if one is on a surface or not
    G4ThreeVector *fRopePosition[360]; ///<  List of ropes that correspond to a given angle
    G4ThreeVector fUpRopePositions[10][2]; ///< Positions (a point on) each of the up ropes- 10 whiffle trees, 2 ropes each
    G4ThreeVector fDownRopePositions[20]; ///< Positions on each of the downward ropes
    G4double fUpZMax;  ///< z position of the top of the upward ropes
    G4double fUpZMin; ///< z position of the bottom of the downward ropes (at the equator)- below that is a rope loop
    G4double fDownZMax; ///<  Top of the downward rope straight sections (at the equator)
    G4double fDownZMin; ///<  Bottom position of the downward rope sections
    G4double fRminNet; ///< Inside spherical radius of the rope net
    G4double fRmaxNet; ///< Outside spherical radius of the rope net
    G4double fRopeZMin[360]; ///< List of rope bottoms as a function of angle bin
    G4double fRopeZMax[360]; ///< List of rope top positions as a function of angle bin
    G4double fRopeRadius[360];///< List of rope radii as a funciton of angle bin
    G4double fPhiMapOffset; ///<  To calculate position indices, offset by fPhiMapOffset so that the entire rope width range is in one bin.,
    G4double fPSUPradius; // Radius of the psup
    class SNORopeNet *fRopeNet[10];  ///< List of downward Ropes.
    class SNORopeLoop *fRopeLoop[10];  ///< List of loops on bottom of downward ropes
    class SNOSpreaderRope *fSpreaderRope[10]; ///< Spreader ropes are the horizontal ropes between adjacent downward ropes.

};
} //::RAT
#endif