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

#include <vector>
#include "topo/Topology.h"

//
//Define MGCellBase Class.

class MGBox;
class MGVector;
class MGMatrix;
class MGTransf;
class MGGeometry;
class MGCellNB;
class MGCellMap;
class MGComplex;
class MGPVertex;

/** @addtogroup TOPO
 *  @{
 */

///Is an abstract class and the super class of MGPVertex and MGCellNB.

///A CellBase includes only a binder cell pointer if exists.
///There are two types of cells. One is parameter cell(pcell) and
///the other is binder cell(bcell). They are exclusive, that is, if
///a cell is a parameter cell, the cell cannot be binder cell and
///vice versa.
///Parameter cell is a constituent of a complex.
///Binder cell is a binder of parameter cells. Plural cells are connected
///through a binder.
class MG_DLL_DECLR MGCellBase: public MGTopology{

public:

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

///Void constructor. Constructor of pcell.
MGCellBase():m_binder(0){;};

///Copy constructor.
///The binder will not be copied even if cell had one.
MGCellBase(const MGCellBase& cell):MGTopology(cell),m_binder(0){;};

////////////Virtual Destructor////////////
virtual ~MGCellBase();

///////operator overload//////

///Assignment.
///When the leaf object of this and topo2 are not equal, this assignment
///does nothing.
virtual MGCellBase& operator=(const MGCellBase& gel2);

///Object transformation.
virtual MGCellBase& operator+=(const MGVector& v)=0;
virtual MGCellBase& operator-=(const MGVector& v)=0;
virtual MGCellBase& operator*=(double scale)=0;
virtual MGCellBase& operator*=(const MGMatrix& mat)=0;
virtual MGCellBase& operator*=(const MGTransf& tr)=0;

/////////////Member Function///////////////

///Obtain binder.
MGCellNB* binder()const{return m_binder;};

///Obtain the box of the cell.
const MGBox& box()const=0;

///Make a clone of the cell.
///clone(), clone_without_boundaries() does not copy the binder cell relation.
virtual MGCellBase* clone()const=0;
virtual MGCellBase* clone_without_boundaries()const=0;

///Connect this cell to cell2.
///This cell is a pcell of a boundary of a higher manifold dimension's cell A,
///and cell2 is also is a pcell of a boundary of another cell B.
///That is, this cell is a part of a boundary of cell A,
///and cell2 is a part of a boundary of cell B.
///If cell A's manifold dimension is n, then this cell's manifold dimension is n-1.
///B's manifold dimension is same as A's. and cell2's manifold dimension is n-1.
virtual void connect(MGCellBase& cell2);

///Draw 3D curve in the topology's star cell world coordinates.
///The object is converted to curve(s) and is drawn.
virtual void drawWire_in_star(
	mgVBO& vbo,///<Target graphic object.
	int line_density=1	///<line density to draw a surface in wire mode.
)const;

///Draw 3D point(vertex) in world coordinates.
///The object is converted to point(s) and is drawn.
///This is valid only for topology objects or MGPoint.
virtual void draw3DVertex(mgVBO& vbo)const=0;

///Draw 3D point(vertex) in star cell's world coordinates.
///The object is converted to point(s) and is drawn.
virtual void draw3DVertex_in_star(mgVBO& vbo)const;

///Free partnership relation of this cell.
///If the binder is prprietry use of this cell, it will be deleted.
void free_partnership();

///Ask if this is binder cell.
virtual bool is_bcell() const=0;

///Ask if this is parameter cell.
bool is_pcell()const{return !is_bcell();};

///Make a binder cell of this parameter cell.
///Returned is the binder pointer generated by new.
///The binder has no geometry, only has binder and parameter cell relationship.
virtual MGCellNB* make_binder() const=0;

///Make a binder associated with the extent geometry rep.
///Returned is the binder MGCellNB pointer.
///If this already had the binder with the extent,
///make_binder_with_curve() only returns the pointer.
///If this had the binder without extent, make_binder_with_extent() will
///generate the extent expression.
const MGCellNB* make_binder_with_extent()const;

///Obtain manifold dimension.
virtual int manifold_dimension() const=0;

///Negate the direction of the cell.
virtual void negate()=0;

///Return number of partners.
///Partners do not inclue own cell.
int number_of_partners() const;

///Obtain partner cells.
///Partners represent same world's(same cell's parameter) coordinates.
///Parameter cell's partners are parameter cells.
///Binder cell's partners are binder cells.
///The partners do not include this pcell except when star cell is
///connected to the star cell itself(closed only by the star cell).
///Let prtnrs[.] is the function's output, then prtners[0] is
///the netxt partner of this, and prtnrs[last] is the previous one of this
///in the partners array of the binder.
std::vector<const MGCellBase*> partners() const;

///Set binder cell relation to this parameter cell.
///***The binder must be newed object and the owenership is transfered
///to this parameter cell.
void set_binder(MGCellNB& binder)const;

///Obtain star cells.
virtual const MGCellNB* star() const=0;
virtual MGCellNB* star()=0;

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

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

protected:
	mutable MGCellNB* m_binder;	///<Binder cell of this cell.
								///<Binder cell is always MGCellNB.

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

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

///Assignment.
///When the leaf object of this and topo2 are not equal, this assignment
///does nothing.
MGCellBase& set_cellbase(const MGCellBase& cb2);

private:

///Copy boundary data of cell2 into this.
virtual void copy_all_boundaries(const MGCellBase& cell2)=0;

///Copy all boundaries of cell into this, and binders association
///of the boundaries in the cmap.
///Binder cells of cell will be registered in cmap.
virtual void copy_all_boundaries(const MGCellBase& cell2, MGCellMap& cmap)=0;

virtual void copy_box(const MGCellBase& cb)const=0;
virtual void copy_perror(const MGCellBase& cb)const=0;

///Generate new MGCellBase by newing the original MGCellBase.
///Binder cells of pcells will be registered in cmap.
virtual MGCellBase* clone_pcell_with_bcell(
	MGCellMap& cmap,
	MGCellMap* cellmap_parent=0
)const;

///Generate a new MGCellBase pointer by newing the original MGCellBase.
///This is a proprietry routine of MGComplex copy.
///Copy all boundary data, (but does not copy own binder cell relation)
///and register boundary binder association data into cmap.
virtual MGCellBase* clone(MGCellMap& cmap) const=0;

///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.
virtual MGGeometry* make_binder_extent() const=0;

friend class MGComplex;
friend class MGCellNB;
friend class MGEdge;

};

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