/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/
#include "StdAfx.h"
#include "mg/Vector.h"
#include "mg/Matrix.h"
#include "mg/Transf.h"
#include "mg/Geometry.h"
#include "mg/Point.h"
#include "topo/PVertex.h"
#include "topo/BVertex.h"
#include "topo/Edge.h"

#if defined(_DEBUG)
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//
//Implements MGPVertex Class.
//MGPVertex is a parameter cell whose manifold dimension is 0,
//a boundary of an Edge(start or end).

///Assignment.
///Binder and partner relation and edge pointer will be cleared, 
MGPVertex& MGPVertex::operator=(const MGPVertex& pv){
	if(this==&pv)
		return *this;

	m_t=pv.m_t;
	m_edge=0;
	MGPCell::operator=(pv);
	return *this;
}
MGPVertex& MGPVertex::operator=(MGPVertex&& pv){
	if(this==&pv)
		return *this;

	m_t=pv.m_t;
	m_edge=0;
	MGPCell::operator=(std::move(pv));
	return *this;
}

//Comparison operator.
bool MGPVertex::is_less_than(const MGPCell& pcel2)const{
	const MGPVertex* pv2=dynamic_cast<const MGPVertex*>(&pcel2);
	if(pv2)
		return is_less_than(*pv2);
	return false;
}
bool MGPVertex::is_less_than(const MGPVertex& cell2)const{
	const MGEdge* e1= starEdge();
	if(!e1)
		return true;
	const MGEdge* e2=cell2.starEdge();
	if(!e2)
		return false;
	MGBVertex* bv=binder_vertex();
	if(!bv)
		return true;
	const MGPVertex* pv0=bv->partner_member_vertex(0);
	const MGEdge* e0=pv0->starEdge();
	if(!e0)
		return true;

	MGVector v0=e0->eval(pv0->t(),1);
	if(!pv0->is_start_vertex())
		v0*=-1.;

	MGVector v1=e1->eval(t(),1);
	if(!is_start_vertex())
		v1*=-1.;
	MGVector v2=e2->eval(cell2.t(),1);
	if(!cell2.is_start_vertex())
		v2*=-1.;

	MGVector zAxis(0.,0.,-1.);
	return v0.angle2pai(v1,zAxis)<v0.angle2pai(v2,zAxis);
}

///Comparison.
bool MGPVertex::operator==(const MGGel& gel2)const{
	const MGPVertex* cel2 = dynamic_cast<const MGPVertex*>(&gel2);
	return cel2 ? cel2==this:false;
}
bool MGPVertex::operator<(const MGGel& gel2)const{
	if(MGGel::operator<(gel2))
		return true;
	const MGPVertex* pcel2 = dynamic_cast<const MGPVertex*>(&gel2);
	return is_less_than(*pcel2);
}

//Get binder.
MGBVertex* MGPVertex::binder_vertex()const{
	return static_cast<MGBVertex*>(binder().get());
}

//Test if this is the start vertex or end verstex on the edge.
bool MGPVertex::is_start_vertex()const{
	const MGEdge* e= starEdge();
	if(!e)
		return false;
	const MGPVertex* pv=e->vertex_start().get();
	return this==pv;
}

std::ostream & MGPVertex::toString(std::ostream& ostrm) const{
	ostrm<<"<<PV="<<(const MGGel*)this;
	MGPCell::toString(ostrm);
	ostrm<<",m_t="<<m_t<<",m_edge="<<(const MGGel*)m_edge;
	ostrm<<"=PV>>";
	return ostrm;
}

///Obtain star cells.
const MGCell* MGPVertex::star() const{ return m_edge; }
MGCell* MGPVertex::star(){ return m_edge; }

//Make a binder cell of this parameter cell.
//This is a parameter cell and the binder will be newed.
//Returned is the binder pointer generated.
//The binder has no geometry, only has binder and parameter cell relationship.
std::shared_ptr<MGBCell>& MGPVertex::make_binder() const{
	std::shared_ptr<MGBCell>& cell=binder();
	if(cell)
		return cell;
	m_binder =std::make_shared<MGBVertex>(*this);
	return m_binder;
}

//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> MGPVertex::make_binder_extent() const{
	const MGEdge* edge = starEdge();
	if(!edge) return nullptr;
	return std::unique_ptr<MGGeometry>(new MGPoint(edge->eval(t())));
}

// Output virtual function.
std::ostream& operator<<(std::ostream& ostrm, const MGPVertex& pv){
	return pv.toString(ostrm);
}
