/**
 *Register.java
 *Purpose: The class will contain functionality for the register to
 *	   queue up employees, and ring up customers.
 *         Currently the customers will stand to the right of the register
 *         and the employees will stand on the register.
 *@author Joel Grochowski
 *@version 1.9
 */

import java.util.*;

public class Register extends StoreObject
{
  /**
   *customers
   *Purpose: The queue of customers that are to be rung up by the register
   */
  private Vector customers = new Vector();

  /**
   *lineDirection
   *Purpose: The direction that the line is going, so the customer can
   *         easily find the end of the line and stand there:
   *         1 for North, 2 for East, 3 for South, 4 for West
   */
  private int lineDirection;

  /**
   *employee_
   *Purpose: the Employee that will be attending the register
   */
  private Employee employee_ = null;

  /**
   *runningTotal
   *Purpose: the current amount in this register.  The store will check 
   *         periodically to take the money out of the register
   */
  private double runningTotal = 0;

  /**
   *checkoutCounter
   *Purpose: A counter to simulate the Customer actually wating to be rung up 
   *         instead of always being rung up instanenously
   */
  int checkoutCounter = 0;

  /**
   *Register(String name, int lineDir)
   *Purpose: The constructor for the register
   *@param name the name of the register 
   *@param lineDir the integer value for the direction the register faces
   */
  public Register(String name, int lineDir)
  {
     super(name); 
     lineDirection = lineDir;
  } 

  /**
   *getEmployee()
   *Purpose: Accessor to get the employee of this register
   *@param none
   *@return Employee the employee of this register
   */
  public Employee getEmployee()
  {
    return employee_;
  }

  /**
   *takeMoney()
   *Purpose: For the game to take the money out of the register and reset
   *         runningTotal.
   *@param none
   *@return double the value of the amount of money in the register
   */
  public double takeMoney()
  {
    double temp = runningTotal;
    
    runningTotal = 0.0;

    return temp;
  }

  /**
   *viewMoney()
   *Purpose:Accessor to return the running total of the register
   *@param none
   *@return double
   */
  public double viewMoney()
  {
    return runningTotal;
  }

  /**
   *addMoney(double money)
   *Purpose: Add the proper amount of money to the register when somebody
   *         pays for an item.
   *@param money the amount of money the person paid
   *@return void
   */
  public void addMoney(double money)
  {
    runningTotal += money;
  }

  /**
   *getLineDirection()
   *Purpose: Accessor to find which way the line is set up so the Customer 
   *         can find the rear of the line
   *@param none
   *@return int the lineDirection value
   */
  public int getLineDirection()
  {
    return lineDirection;
  }

  /**
   *helpCustomer()
   *Purpose: To help the next customer in the queue and move up the queue 
   *         accordingly.  A bug may be present in the removing of the first
   *         customer if there is a deadlock, but that needs to be tested.
   *@param none
   *@return void
   */
  public void helpCustomer()
  {
    //get the cart of the customer
    Customer thisCustomer = (Customer) customers.elementAt(0);
    int cartSize = thisCustomer.getTotalNumItems();


    //simulate the customer waiting in line
    if(checkoutCounter <= cartSize/5)
      checkoutCounter++;
    else
    {
      Vector items_ = thisCustomer.getCart();
      itemList tempItemList;
      Item tempItem;

      //used for moving up the line
      StoreMap map = StoreMap.getInstance(); 
      Location tempLocation;

      //the total for this person which will get added to runningTotal
      double thisTotal = 0.0;

      //count up all the items in the cart and get their price
      for(int i = 0; i < items_.size(); i++)
      {
        tempItemList = (itemList) items_.elementAt(i);
        tempItem = tempItemList.getItem();

        //multiply the quantity of items by the retail price to get the 
        //current price
        thisTotal += tempItemList.getQuantity() * tempItem.getRetailPrice();

        //compare the prices so the customer can comment about them
        thisCustomer.comparePrice(tempItem);
      }

      //add that to the running total
      runningTotal += thisTotal;

      //move the customer to the next available space and remove them from the 
      //line and set their inLine variable to false and paid variable to true.
      thisCustomer.togglePaid(); 
      thisCustomer.toggleInLine();
      customers.removeElementAt(0);

      //adjust the person's happiness depending on how long they were in line for
      thisCustomer.checkoutTime(checkoutCounter);

      //move the customer towards the exit
      thisCustomer.setTargetLocation(StoreMap.getInstance().findObject("Exit"));
      thisCustomer.move();

      //set all the rest of the customers position one down/up and reset their 
      //positions on the map
      for(int i= 0; i < customers.size(); i++)
      {
        thisCustomer = (Customer) customers.elementAt(i);

        //set the x and y on the map
        tempLocation = new Location(getX()+1, getY()-i);
        map.setObject(thisCustomer, tempLocation);
        map.setObject(null, thisCustomer.getLocation()); 

        //reset the customer's x and y
        thisCustomer.setLocation(tempLocation);

        //add time to affect the person's happiness
        thisCustomer.addWaitTime(checkoutCounter);

      }

      //reset the checkoutCounter
      checkoutCounter = 0;
    }
  }

  /**
   *checkEmployee()
   *Purpose: checks to see if there is an employee using the register
   *@param none
   *@return boolean True or false whether an employee is using the register
   */
  public boolean checkEmployee()
  {
    if (employee_ == null)
      return false;
    
      return true;
  }

  /**
   *obtainEmployee(Employee newEmp)
   *Purpose: The register will obtain an employee that will ring in customers
   *	     and such
   *@param newEmp Employee that will be manning the register
   *@return void
   */
  public void obtainEmployee(Employee newEmp)
  {
    if(employee_ == null && newEmp != null)
    {
      //set the employee at the register
      employee_ = newEmp;
      employee_.toggleAtRegister();

      //set this employee's location variables to the same as the register's
      employee_.setX(getX());
      employee_.setY(getY());
    }
    else if(newEmp == null)
    {
      employee_ = null;
    }
  }

  /**
   *obtainCustomer(Customer newCust)
   *Purpose: The register will effectively queue the customer in the line
   *@param newCust customer will enter the line and inLine will be toggled
   *@return void
   */
  public void obtainCustomer(Customer newCust)
  {
    customers.addElement(newCust);
  }

  /**
   *employeeLeave()
   *Purpose: To relinquish the employee of his duties
   *@param none
   *@return void
   */
  public void employeeLeave()
  {
    //if there's no customers and the employee isnt null
    //then set the employee free
    if(employee_ != null)
    {
      //tell the employee to leave if possible
      employee_.interruptJob(LeaveRegister.getInstance());

    }
  }

  /**
   *getLineSize()
   *Purpose: To return the length of the current line
   *@param none
   *@return int the size of the line
   */
  public int getLineSize()
  {
    return customers.size();
  }
 
  /**
   *getEndOfLine()
   *Purpose: Returns the last Location value for this line
   *@param none
   *@return Location The next available location for a customer
   */
  public Location getEndOfLine()
  {
    Location tempLocation = new Location();

    //In this implementation, the line will always be to the right of 
    //the Register, and the register will alway face North.
    tempLocation.setX(getX()+1);

    if(customers.size() != 0)
      tempLocation.setY(getY()-getLineSize());
    //otherwise the size of the line is 0.
    else
      tempLocation.setY(getY());
    
    return tempLocation; 
  }

  /**
   *getToken()
   *Purpose: Overwrites the getToken() in storeObject.  If there is somebody
   *         at the register, this function will return a different character
   *         than if there is nobody at the register
   *@param none
   *@return char The character token to be displayed
   */
  public char getToken()
  {
    if(employee_ == null)
      return super.getToken();

    return '\u0026';
  }
}
