/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/
#ifndef _MGPVertex_HH_
#define _MGPVertex_HH_

#include "mg/Default.h"
#include "topo/PCell.h"
#include "topo/Edge.h"

class MGBox;
class MGOfstream;
class MGIfstream;
class MGCell;
class MGBVertex;

/** @addtogroup TOPO
 *  @{
 */

//
//Define MGPVertex Class.

///MGPVertex is a parameter cell of the manifold dimension 0.

///MGPVertex is a boundary of an Edge(start or end) to hold edge's parameter data.
///Logically PVertex is a parameter cell and also is a boundary.
///MGPvertex can be only partners of a binder.
///Since MGPVertex's manifold dimension is 0, MGPVertex does not have boundaries.
class MG_DLL_DECLR MGPVertex: public MGPCell{
private:
	MGEdge* m_edge;	///<The edge whose boundary is this PVertex.
	double m_t;		///<Parameter value of the curve of m_edge.

public:

///////// Constructor /////////

///Void constructor.
MGPVertex():MGPCell(),m_edge(nullptr),m_t(0.){;};
~MGPVertex()=default;

///Copy constructor.
///Parent edge will be cleared.
MGPVertex(const MGPVertex& v):MGPCell(),m_edge(nullptr), m_t(v.m_t){;};
MGPVertex(MGPVertex&& v):MGPCell(),m_edge(nullptr), m_t(v.m_t){;};

///Copy constructor with parent edge e.
///e is set as the parent edge.
MGPVertex(const MGPVertex& v, MGEdge* e):MGPCell(), m_edge(e), m_t(v.m_t){;};

///Fundamental constructor.
///Construct from the parameter value t of edge.
///e is set as the parent edge.
explicit MGPVertex(double t, MGEdge* e= nullptr):MGPCell(), m_edge(e), m_t(t){;};

///Assignment.
///Binder and partner relation and edge pointer will be cleared, 
MGPVertex& operator=(const MGPVertex& gel2);
MGPVertex& operator=(MGPVertex&& gel2);

///Get binder.
MGBVertex* binder_vertex()const;

///Generate copied gel of this gel.
///Returned is a newed object. User must delete the object.
MGPVertex* clone()const override{ return new MGPVertex(*this); };

///Return Object's type ID (TID)
long identify_type()const override;

///Comparison of two MGPCell.
bool operator==(const MGGel& gel2)const;
bool operator<(const MGGel& gel2)const;
bool is_less_than(const MGPCell& pcel2)const override;
bool is_less_than(const MGPVertex& pv2)const;

///Test if this is the start vertex or end verstex on the edge.
bool is_start_vertex()const;

///Make a binder cell of this parameter cell.
///Returned is the binder reference.
///The binder may have no geometry, and only has binder and parameter cell relationship.
std::shared_ptr<MGBCell>& make_binder() const override;

///Get manifold dimension.
int manifold_dimension() const{return 0;};

/// Output function.
std::ostream& toString(std::ostream&) const;

///Set the parameter value.
void set_t(double t){m_t=t;};

///Set the edge pointer.
void set_edge(MGEdge* e){m_edge=e;};

///Obtain star cells.
const MGCell* star() const override;
MGCell* star() override;

///Return the edge pointer.
const MGEdge* starEdge() const{return m_edge;};

///Return the edge pointer.
MGEdge* starEdge(){return m_edge;};

///Return the parameter value.
double t() const{return m_t;};

///Get the name of the class.
std::string whoami()const override{return "PVertex";};

protected:

///Read Object's member data.
void ReadMembers(MGIfstream& buf);

///Write Object's Member Data
void WriteMembers(MGOfstream& buf) const;

private:

///Make the binder cell's extent expression of this parameter cell.
///Returned is a MGGeometry pointer generated by new.
///When this cell does not have star cell, null pointer will be returned.
std::unique_ptr<MGGeometry> make_binder_extent() const;

///String stream Function
MG_DLL_DECLR friend std::ostream& operator<< (std::ostream&, const MGPVertex&);

/// Serialization.
MG_DLL_DECLR friend MGOfstream& operator<< (MGOfstream& buf, const MGPVertex& pv);
MG_DLL_DECLR friend MGIfstream& operator>> (MGIfstream& buf, MGPVertex& pv);

};

/** @} */ // end of TOPO group
#endif
