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

#include <vector>
#include <memory>
#include "mg/MGCL.h"

//
//Define MGPCell Class.

class MGGeometry;
class MGBCell;
class MGCell;
class MGOfstream;
class MGIfstream;

/** @addtogroup TOPO
 *  @{
 */

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

///MGPCell is parameter cell, indicates parameters of MGCell.
///A MGPCell includes only a binder cell shared  pointer if exists.
///A binder cell binds partner parameter cells that share a boudary of a cell.

///Plural cells are bound through a binder.
class MG_DLL_DECLR MGPCell:virtual public MGGel{
protected:
	mutable SharedBCell m_binder;	///<Binder cell of this cell.
	        //m_binder is shared by the bound MGPCell's.

public:

////////Special member functions/////////
MGPCell() = default;
virtual ~MGPCell();

///The binder will not be copied even if cell had one.
MGPCell(const MGPCell& cell){;};

///The binder will not be copied even if cell had one.
MGPCell& operator=(const MGPCell& rhs);//Copy assignment.

MGPCell(MGPCell&& rhs){ ; };//Move constructor.
MGPCell& operator=(MGPCell&& rhs);//Move assignment.

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

///Bind 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 bind(MGPCell& cell2);

///Obtain binder.
SharedBCell& binder()const{return m_binder;};

virtual bool is_less_than(const MGPCell& pcel2)const=0;

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

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

///Make a binder associated with the extent geometry rep.
///If this already had the binder with the extent,
///make_binder_with_curve() only returns the reference.
///If this had the binder without extent, make_binder_with_extent() will
///generate the extent.
SharedBCell& make_binder_with_extent()const;

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

///Obtain partner cells.
///Partners represent same world's(same cell's parameter) coordinates.
///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 MGPCell*> partners() const;

///Reset the binder.
void resetBinder();

///Reset the binder.
void resetBinder(SharedBCell& newBinder)const;

///Rest the binder by newBinder. newBinder's ownership is transfered to this
///as SharedBCell.
void resetBinder(MGBCell* newBinder)const;

//Make this binder the same as pcell2's binder.
//pcell2 must have binder already.
void shareBinder(const MGPCell& pcell2);

//Make this binder the same as bcell's partner membes if bcell already had a partner member.
//If bcell did not have partner members, reset bcell.
void shareBinderIfHadPartner(MGBCell* bcell);

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

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

protected:

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

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

private:

///Make the binder cell's extent expression of this parameter cell.
///When this cell does not have star cell, null pointer will be returned.
virtual UniqueGeometry make_binder_extent() const=0;

friend class MGBCell;
friend class MGEdge;
friend class MGComplex;
friend class MGOfstream;
friend class MGIfstream;

///Merge two binder cells of pcell1 and pcell2.
///Boht had binder, binder cell of pcell2 will be destructed.
friend void merge_2bcells(MGPCell& pcell1, MGPCell& pcell2);

};

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