#ifndef RESOLVEXPR_COST_H
#define RESOLVEXPR_COST_H

#include <iostream>

namespace ResolvExpr {
    class Cost {
      public:
	Cost();
	Cost( int unsafe, int poly, int safe );
  
	void incUnsafe( int inc = 1 );
	void incPoly( int inc = 1 );
	void incSafe( int inc = 1 );
  
	Cost operator+( const Cost &other ) const;
	Cost operator-( const Cost &other ) const;
	Cost &operator+=( const Cost &other );
	bool operator<( const Cost &other ) const;
	bool operator==( const Cost &other ) const;
	bool operator!=( const Cost &other ) const;
	friend std::ostream &operator<<( std::ostream &os, const Cost &cost );
  
	static const Cost zero;
	static const Cost infinity;
      private:
	int compare( const Cost &other ) const;

	int unsafe;
	int poly;
	int safe;
    };

    inline Cost::Cost() : unsafe( 0 ), poly( 0 ), safe( 0 ) {}

    inline Cost::Cost( int unsafe, int poly, int safe ) : unsafe( unsafe ), poly( poly ), safe( safe ) {}

    inline void 
	Cost::incUnsafe( int inc ) {
	unsafe += inc;
    }

    inline void 
	Cost::incPoly( int inc ) {
	unsafe += inc;
    }

    inline void 
	Cost::incSafe( int inc ) {
	unsafe += inc;
    }

    inline Cost Cost::operator+( const Cost &other ) const {
	return Cost( unsafe + other.unsafe, poly + other.poly, safe + other.safe );
    }

    inline Cost Cost::operator-( const Cost &other ) const {
	return Cost( unsafe - other.unsafe, poly - other.poly, safe - other.safe );
    }

    inline Cost &Cost::operator+=( const Cost &other ) {
	unsafe += other.unsafe;
	poly += other.poly;
	safe += other.safe;
	return *this;
    }

    inline bool Cost::operator<( const Cost &other ) const {
	    if ( *this == infinity ) return false;
	    if ( other == infinity ) return true;
	    if ( unsafe > other.unsafe ) {
		return false;
	    } else if ( unsafe < other.unsafe ) {
		return true;
	    } else if ( poly > other.poly ) {
		return false;
	    } else if ( poly < other.poly ) {
		return true;
	    } else if ( safe > other.safe ) {
		return false;
	    } else if ( safe < other.safe ) {
		return true;
	    } else {
		return false;
	    }
	}

    inline bool Cost::operator==( const Cost &other ) const {
	return unsafe == other.unsafe
	&& poly == other.poly
	&& safe == other.safe;
    }

    inline bool Cost::operator!=( const Cost &other ) const {
	return !( *this == other );
    }

    inline std::ostream &operator<<( std::ostream &os, const Cost &cost ) {
	os << "( " << cost.unsafe << ", " << cost.poly << ", " << cost.safe << " )";
	return os;
    }
} // namespace ResolvExpr

#endif // RESOLVEXPR_COST_H
