import java.awt.Color;
import java.util.Enumeration;



public class UvaStudent extends RandomWalker {
    // OVERVIEW: UvaStudent is a supertype class for other Simulated Objects involved in SatNightSimulation.
    // UvaStudent provides many definitions and functions that are inherited by the other SatNightSimulation objects.

    protected boolean inTurn;
    protected boolean response;
    protected UvaStudent friend;
    protected Color natural = Color.yellow;
    protected boolean isTalking;
    protected boolean isResponding;
    protected boolean isHappy;
    protected String quote;
    protected String name;
    protected int firstIndex = 0;
    protected String gender;
    protected int drinkCount = 0;
    protected boolean isOut;
    static private int counterG = 0;
    static synchronized private String getNextName ()
    //@ensures \result != null
    {
	counterG++;
	return "Keg" + counterG;
    }
    static private int qCounter = 0;
    static synchronized protected String getNextQuote() {
        ++qCounter;
        if (qCounter > 5){
          qCounter = qCounter - 5;
        }
        if (qCounter == 1){
          return "Hey";
        }
        if (qCounter == 2){
          return "Sup";
        }
        if (qCounter == 3){
          return "WASSUP?!?";
        }
        if (qCounter == 4){
          return "Yo";
        }
        if (qCounter == 5){
          return "Hi";
        }
        if (qCounter == 6){
          return "Hello";
        }
        return "Error No Quote";
    }
    public UvaStudent () {
	inTurn = false;
	friend = null;
	isTalking = false;
	isResponding = false;
        isHappy = false;
        isOut = false;
	quote = getNextQuote();
        name = getNextName ();

    }

    public Color getColor()
    //Effects: Gets the color for the simulation of the object depending on the
    //natural color of the object and its current action.
    {
	if (inTurn) {
	    return Color.white;
	} else {
	    if (isTalking) {
		return Color.green;
	    } else if (isResponding) {
		return Color.cyan;
	    } else if (isHappy) {
		return Color.orange;
	    }else {
		return natural;
	    }
        }
    }//@nowarn NonNullResult // ESC/Java doesn't know Color constants are not null
    public void talk ()
    //Effects: Locks both this and friend, prints out a dialoge to initiate conversation, and calls response. If friend is of type UvaKeg, gives
    //specific message for keg interaction.
    {
       Object lock1, lock2;
       if (friend instanceof UvaKeg){
          //System.err.println("1");
          synchronized (this){
            synchronized (friend){
              isTalking = true;
	      isResponding = false;
              System.err.println (name + " says " + quote + " I'm thirsty, pour me a brewski ");
              ++drinkCount;
              delay (1000);
              //System.err.println("2");
              friend.respond(this.gender);
              System.err.println (name + " says:  Chug, Chug, Ah");
              System.err.println (name + " has had " + drinkCount
                + " drinks!");
              isTalking = false;
              friend = null;

                if (drinkCount == 4){
                  System.err.println (name + " is now a player!");
                  if (gender == "male"){
                    newPlayerBoy(this);
                  }
                  if (gender == "female"){
                    newPlayerGirl(this);
                  }
                }
                if (drinkCount == 7){
                  System.err.println (name + " is passed out!");
                  outStu(this);
                }
              }
           }

        } else if ((friend != null) && (name !=null) && (friend.name != null)) {
	    // Always grab the lock for whichever name is alphabetically first
	    if (name.compareTo (friend.name) < 0) {
		lock1 = this;
		lock2 = friend;
	    } else {
		lock1 = friend;
		lock2 = this;
	    }
            synchronized (lock1) {
		synchronized (lock2) {
                  //System.err.println("before talk");
                  isTalking = true;
	          isResponding = false;

	          System.err.println (name + " says " + quote + " I'm " + name);
                  //System.err.println("aftertalk before response");
	          delay (1000);
                  friend.respond(this.gender);
                  //System.err.println("afterresponse");
                  isTalking = false;
                  friend = null;
	        }
            }
        }else{System.err.println("P (opposite = null) || (opposite.name =null) || (name = null)");}

    }
    public boolean respond (String sex)
    //Requires:  String != null
    //requires sex != null
    //Effects:  Prints generic response
    {
        //System.err.println("in response");
	isTalking = false;
	isResponding = true;
	System.err.println (name + " responds: " + quote + " I'm " + name);
	delay (1000);
	isResponding = false;
        return false;
    }

    public boolean respondPlayer ()
    {
    //Effects:  Prints response of normal student to Player
    	//System.err.println("in responseplayer");
        isTalking = false;
	isResponding = true;
	System.err.println (name + " responds: " + quote + " Slap!");
	delay (1000);
	isResponding = false;
        return false;
    }

    public String getGender()
    //NOT USED
    {
      return "nuetral";
    }

    protected synchronized void outStu(UvaStudent StuOut)
      //Requires: StuOut != null
      //@requires StuOut != null
      //Effects: replaces StuOut with and OutStudent object
    {
      OutStudent drunk;
      Grid gDrunk = getGrid(); //@nowarn
      //Grid is being used, must be initialized
      gDrunk.setObjectAt(StuOut.getRow(), StuOut.getColumn(), (new OutStudent())); //@nowarn
      //warning that precondition may not be established, but only used in class and subtypes
      //since protected, and class meets requirements


    }
    protected synchronized void  newPlayerBoy(UvaStudent StuIn)
    //@requires StuIn != null
    //Effects:  replaces StuIn with a new UvaPlayerBoy
    {
      //UvaPlayerBoy pBoy;
      Grid gPB = getGrid(); //@nowarn
      //Grid is being used, must be initialized
      gPB.setObjectAt(StuIn.getRow(), StuIn.getColumn(), (new UvaPlayerBoy()));//@nowarn
      //warning that precondition may not be established, but only used in class and subtypes
      //since protected, and class meets requirements

    }
     protected synchronized void  newPlayerGirl(UvaStudent StuIn)
    //@requires StuIn != null
    //Effects:  replaces StuIn with a new UvaPlayerBoy
    {
      //UvaPlayerGirl pGirl;
      Grid gPG = getGrid(); //@nowarn
      //Grid is being used, must be initialized
      gPG.setObjectAt(StuIn.getRow(), StuIn.getColumn(), (new UvaPlayerGirl()));//@nowarn
      //warning that precondition may not be established, but only used in class and subtypes
      //since protected, and class meets requirements

    }
     protected synchronized void  happy(UvaStudent a, UvaStudent b)
    {
    //Requires:  a and b are not null
    //Effects:  Changes a and b into type HappyStudent

      Grid g = getGrid(); //@nowarn
      //HappyStudent just made, must be initialized.  Grid is being used,
      // must also be initialized.  rows  are being used in program, must
      // not be null.
      g.setObjectAt(a.getRow(), a.getColumn(), (new HappyStudent())); //@nowarn
      g.setObjectAt(b.getRow(), b.getColumn(), (new HappyStudent())); //@nowarn
    }



    public void executeTurn () throws RuntimeException
       // Note: requires isInitialized is inherited from SimObject
       // EFFECTS: First, checks if 'this' has friend.  If it does, calls talk()
       // on this.  Else picks a random direction and tries to move that way,
       //then checks to see if it
       //has any neighbors, adding them to friend
    {
	inTurn = true;
        //System.err.println("before choices");

	if (friend != null) {
            //System.err.println("friend != null");
	    if (!isTalking && !isResponding) {

                talk ();

                //friend = null;
      		// delay (600);
	    }
        } else {
	    synchronized (getGrid ()) {
                //System.err.println("before super.executeTurn");
                super.executeTurn ();
                //System.err.println("after super.executeTurn");
		Enumeration neighbors = getNeighbors ();

		while (neighbors.hasMoreElements ()) {
		    SimObject neighbor = (SimObject) neighbors.nextElement ();
                    //System.err.println("before synchronized neighbor");
                    //@assume neighbor != null
                    //no null neighbors in graph
                    synchronized (neighbor) {
                    //System.err.println("after synchronized neighbor");
		      if (neighbor instanceof UvaStudent) {

                          UvaStudent newFriend = (UvaStudent) neighbor;
                          if (!((neighbor instanceof HappyStudent)
                           || (neighbor instanceof OutStudent))){
			    System.err.println (name + " found a friend: " + newFriend.name);
                            //System.err.println("4");

			      if ((newFriend.friend == null) || (newFriend.friend == this)) {
				friend = newFriend;
				newFriend.friend = this;
                                //System.err.println("5");
				break;
			    }
                          }
			}
		    }
                  }
	    }
	}

	inTurn = false;
        //System.err.println("6");
    }
}