//---------------------------------------------------------------------------
//	Greenplum Database
//	Copyright (C) 2011 EMC Corp.
//
//	@filename:
//		CJobGroupExploration.h
//
//	@doc:
//		Group exploration job
//---------------------------------------------------------------------------
#ifndef GPOPT_CJobGroupExploration_H
#define GPOPT_CJobGroupExploration_H

#include "gpos/base.h"

#include "gpopt/search/CJobGroup.h"
#include "gpopt/search/CJobStateMachine.h"

namespace gpopt
{
using namespace gpos;


//---------------------------------------------------------------------------
//	@class:
//		CJobGroupExploration
//
//	@doc:
//		Group exploration job
//
//		Responsible for creating the logical rewrites of all expressions in a
//		given group. This happens by firing exploration transformations that
//		perform logical rewriting (e.g., rewriting InnerJoin(A,B) as
//		InnerJoin(B,A))
//
//---------------------------------------------------------------------------
class CJobGroupExploration : public CJobGroup
{
public:
	// transition events of group exploration
	enum EEvent
	{
		eevStartedExploration,	// started group exploration
		eevNewChildren,			// new children have been added to group
		eevExplored,			// group exploration is complete

		eevSentinel
	};

	// states of group exploration job
	enum EState
	{
		estInitialized = 0,	   // initial state
		estExploringChildren,  // exploring group expressions
		estCompleted,		   // done exploration

		estSentinel
	};

private:
	// shorthand for job state machine
	using JSM = CJobStateMachine<EState, estSentinel, EEvent, eevSentinel>;

	// job state machine
	JSM m_jsm;

	// start exploration action
	static EEvent EevtStartExploration(CSchedulerContext *psc, CJob *pj);

	// explore child group expressions action
	static EEvent EevtExploreChildren(CSchedulerContext *psc, CJob *pj);

public:
	CJobGroupExploration(const CJobGroupExploration &) = delete;

	// ctor
	CJobGroupExploration();

	// dtor
	~CJobGroupExploration() override;

	// initialize job
	void Init(CGroup *pgroup);

	// get first unscheduled expression
	CGroupExpression *
	PgexprFirstUnsched() override
	{
		return CJobGroup::PgexprFirstUnschedLogical();
	}

	// schedule exploration jobs for of all new group expressions
	BOOL FScheduleGroupExpressions(CSchedulerContext *psc) override;

	// schedule a new group exploration job
	static void ScheduleJob(CSchedulerContext *psc, CGroup *pgroup,
							CJob *pjParent);

	// job's function
	BOOL FExecute(CSchedulerContext *psc) override;

#ifdef GPOS_DEBUG

	// print function
	IOstream &OsPrint(IOstream &os) const override;

	// dump state machine diagram in graphviz format
	virtual IOstream &
	OsDiagramToGraphviz(CMemoryPool *mp, IOstream &os,
						const WCHAR *wszTitle) const
	{
		(void) m_jsm.OsDiagramToGraphviz(mp, os, wszTitle);

		return os;
	}

	// compute unreachable states
	void
	Unreachable(CMemoryPool *mp, EState **ppestate, ULONG *pulSize) const
	{
		m_jsm.Unreachable(mp, ppestate, pulSize);
	}


#endif	// GPOS_DEBUG

	// conversion function
	static CJobGroupExploration *
	PjConvert(CJob *pj)
	{
		GPOS_ASSERT(nullptr != pj);
		GPOS_ASSERT(EjtGroupExploration == pj->Ejt());

		return dynamic_cast<CJobGroupExploration *>(pj);
	}


};	// class CJobGroupExploration

}  // namespace gpopt

#endif	// !GPOPT_CJobGroupExploration_H


// EOF
