//
// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
//
// The contents of this file are covered under the licence agreement in the
// file "LICENCE" distributed with Cforall.
//
// TupleAssignment.h -- 
//
// Author           : Rodolfo G. Esteves
// Created On       : Mon May 18 07:44:20 2015
// Last Modified By : Peter A. Buhr
// Last Modified On : Mon May 18 15:04:02 2015
// Update Count     : 2
//

#ifndef _TUPLE_ASSIGNMENT_H_
#define _TUPLE_ASSIGNMENT_H_

#include <string>
#include <vector>
#include "ResolvExpr/AlternativeFinder.h"

#include "SynTree/Expression.h"
#include "SynTree/Declaration.h"
#include "SynTree/Type.h"

namespace Tuples {
	class TupleAssignSpotter {
	  public:
		// dispatcher for Tuple (multiple and mass) assignment operations
		TupleAssignSpotter( ResolvExpr::AlternativeFinder * );
		~TupleAssignSpotter() { delete matcher; matcher = 0; }

		bool pointsToTuple( Expression * );
		static bool isTupleVar( DeclarationWithType * );
		bool isTuple( Expression *, bool isRight = false );
		bool isMVR( Expression * );
		bool isTupleAssignment( UntypedExpr *, std::list<ResolvExpr::AltList> & );
		bool match();
	  private:
		// records for assignment generation
		class Options {
		  public:
			void add_option( ResolvExpr::AltList &opt );
			std::list< ResolvExpr::AltList > get_best();
			void print( std::ostream & );
			int size() const { return options.size(); }
			ResolvExpr::AltList get_option( std::list< ResolvExpr::AltList >::size_type index );

			// should really use the one in ResolvExpr/AlternativeFinder, but it's too coupled with the object
			template< typename InputIterator, typename OutputIterator >
			void findMinCost( InputIterator begin, InputIterator end, OutputIterator out );

			template< typename InputIterator, typename OutputIterator >
			void lift_intersection( InputIterator begin, InputIterator end, OutputIterator out );
		  private:
			std::list< ResolvExpr::AltList > options;
			std::vector< std::vector< ResolvExpr::Cost > > costMatrix;
		};

		class Matcher {
		  public:
			Matcher( /*TupleAssignSpotter &spot, */Expression *_lhs, Expression *_rhs );
			virtual ~Matcher() {}
			virtual bool match( std::list< Expression * > &out ) = 0;
			virtual bool solve( std::list< Expression * > &assigns ) = 0;
			static UntypedExpr *createAssgn( Expression *left, Expression *right );
		  protected:
			Matcher() /*: own_spotter( TupleAssignSpotter(0) ) */{}
			void init(/* TupleAssignSpotter &, */Expression *_lhs, Expression *_rhs );
			std::list< Expression * > lhs, rhs;
			//TupleAssignSpotter &own_spotter;
		};

		class MassAssignMatcher : public Matcher {
		  public:
			MassAssignMatcher( Expression *_lhs, Expression *_rhs ) : Matcher( _lhs, _rhs ) {
				rhs.push_back( _rhs );
			}
			virtual bool match( std::list< Expression * > &out );
			virtual bool solve( std::list< Expression * > &assigns );
		  private:
			//std::vector< ResolvExpr::AltList > optMass;
		};

		class MultipleAssignMatcher : public Matcher {
		  public:
			MultipleAssignMatcher( Expression *_lhs, Expression *_rhs );
			virtual bool match( std::list< Expression * > &out );
			virtual bool solve( std::list< Expression * > &assigns );
		  private:
			//Options options;
		};

		friend class Matcher;

		ResolvExpr::AlternativeFinder *currentFinder;
		//std::list<Expression *> rhs, lhs;
		Expression *rhs, *lhs;
		Matcher *matcher;
		bool hasMatched;
		Options options;
		std::vector< ResolvExpr::AltList > optMass;
	};

	ResolvExpr::Cost extract_cost( ResolvExpr::Alternative & );

	template< typename InputIterator, typename OutputIterator >
	void findMinCostAlt( InputIterator begin, InputIterator end, OutputIterator out ) {
		using namespace ResolvExpr;
		AltList alternatives;

		// select the alternatives that have the minimum parameter cost
		Cost minCost = Cost::infinity;
		for ( AltList::iterator i = begin; i != end; ++i ) {
			if ( i->cost < minCost ) {
				minCost = i->cost;
				i->cost = i->cvtCost;
				alternatives.clear();
				alternatives.push_back( *i );
			} else if ( i->cost == minCost ) {
				i->cost = i->cvtCost;
				alternatives.push_back( *i );
			}
		}
		std::copy( alternatives.begin(), alternatives.end(), out );
	}
} // namespace Tuples

#endif // _TUPLE_ASSIGNMENT_H_

// Local Variables: //
// tab-width: 4 //
// mode: c++ //
// compile-command: "make install" //
// End: //
