// Example code for CS 361.  Copyright 2013 by Tom Hayes.
// Important note: This file contains working code for implementing
// retrograde analysis for general games.  It is provided for informational
// purposes only.  You may play around with it and study it to help 
// yourself learn what needs to be done.  However, you may not copy
// any part of the source code to turn in for assignment 5.

import java.util.*;

public class GameGraphNode<T extends GamePosition<T>> {

    T thePosition;
    HashSet<GameGraphNode<T>> outNbrs, inNbrs;
    boolean isSolved;
    int solvedOutNbrCount;
    
    public GameGraphNode( T position ) {
	thePosition = position;
	outNbrs = new HashSet<GameGraphNode<T>>( );
	inNbrs = new HashSet<GameGraphNode<T>>( );
	isSolved = thePosition.gameOver( );
    }
    
    public void addEdgeTo( GameGraphNode<T> successorNode ) {
	outNbrs.add( successorNode );
	if ( this != successorNode )
	    successorNode.inNbrs.add( this );
    }
    
    public GamePlayer whoseMove( ) {
	return thePosition.whoseMove( );
    }
    
    public boolean isSolved( ) {
	return isSolved;
    }
    
    public GamePlayer winner( ) {
	return thePosition.winner;
    }
    
    public void setAnOutNbrWinner ( GamePlayer winner ) {
	if (isSolved)
	    return;
	if (whoseMove( ) == winner) {  // Choose this winning move then.
	    isSolved = true;
	    thePosition.setWinner( winner );
	    notifyInNbrs( );
	    return;
	}
	solvedOutNbrCount++;
	if ( outNbrs.size( ) == solvedOutNbrCount ) {  // All successors solved.  None were winning moves.
	    // Check to see if any are draws.
	    for ( GameGraphNode<T> v : outNbrs ) {
		if ( v.winner( ) == GamePlayer.NOONE ) {
		    // System.out.println("Got one!" + this + v );
		    isSolved = true;
		    thePosition.setWinner( GamePlayer.NOONE );
		    notifyInNbrs( );
		    return;
		}
	    }
	    // If not, then all moves are losing. Might as well play this one.
	    isSolved = true;
	    thePosition.setWinner( winner );
	    notifyInNbrs( );
	}
    }

    // Notify all inNbrs that this position is solved.
    public void notifyInNbrs ( ) {
	if (! isSolved)
	    return;
	GamePlayer winner = thePosition.winner;
	for ( GameGraphNode<T> v : inNbrs ) 
	    v.setAnOutNbrWinner( winner );
    }
    
}
