
/** ISPCharge represents an internet charge
 *
 * @author Nancy Harris
 * @version V1 10/2013
 */
public class ISPCharge
{
	private final double A_CEILING = 10.0;
	private final double A_PRICE_HOUR = 2.0;
	private final double A_PRICE_MONTH = 9.95;
	private final double B_CEILING = 20.0;
	private final double B_PRICE_HOUR = 1.0;
	private final double B_PRICE_MONTH = 13.95;
	private final double C_PRICE_MONTH = 19.95;
	private final double TAX_RATE = .05;

   // variables describing this charge.
   private char packageCode;
   private double hours;
   
   /**************************************************** 
    * The constructor sets the package and hours attributes.
    * This assumes that the pkg code is correct
    *
    * @param pkg The code for the package, A, B, or C
    * @param hours The number of hours this month
    */
    public ISPCharge(char pkg, double hrs)
    {
       this.packageCode = pkg;
       this.hours = hrs;
    }
   
   /************************************************
    * calc charge will decide which package to apply
    * and will return the correct cost.
    *
    * @return The charges for this month.
    */
   public double calcCost()
   {
	   double cost;
	   
	   switch (packageCode)
	   {
		   case 'A':
         case 'a': cost = calcA(); break;
		   case 'B':
         case 'b': cost = calcB(); break;
		   case 'C':
         case 'c': cost = calcC(); break;
		   default: cost = 0;
	   }
	   return cost;
   }

   
   /************************************************
    * calcA calculates the charges for package A
    *
    * @return The cost for package A
    */
    public double calcA()
    {  	
    	double cost;
    	
    	cost = A_PRICE_MONTH;
    	
    	if (hours > A_CEILING)
    	{
    		cost = cost + (hours - A_CEILING) * A_PRICE_HOUR;
    	} 
    	
    	return cost;
    
    }
    
    
    /************************************************
    * calcB calculates the charges for package B
    *
    * @return The cost for package B
    */
    public double calcB()
    {  	
    	double cost;
    	
    	cost = B_PRICE_MONTH;
    	
    	if (hours > B_CEILING)
    	{
    		cost = cost + (hours - B_CEILING) * B_PRICE_HOUR;
    	} 
    	
    	return cost;
    
    }
    
    
    
    /************************************************
    * calcC calculates the charges for package C
    *
    * @return The cost for package C
    */
    public double calcC()
    {
    	return C_PRICE_MONTH;
    }
    
    
    /** calcTax calculates the tax on the passed charge
     *
     * @return The tax for this charge.
     */
     public double calcTax()
     {
    	 return calcCost() * TAX_RATE;
     }
     
     
     /** saveWithB calculates whether or not this 
     * charge would be less if they were on plan B
     *  
     * @return true if you can save with B, false 
     *         otherwise.
     */
     public boolean saveWithB()
     {
    	 ISPCharge b_option;
    	 boolean result;
    	 
    	 result = false;
    	 if (packageCode == 'A')
    	 {
    		 b_option = new ISPCharge('B', hours);
    		 result = this.calcCost() > b_option.calcCost();
    	 }
    	 return result;
     }
     
     /** saveWithC calculates whether or not this 
     * charge would be less if they were on plan C
     *  
     * @return true if there are savings with C
     *         false otherwise
     */
     public boolean saveWithC()
     {
    	 ISPCharge c_option;
    	 boolean result;
    	 
    	 result = false;
    	 if (packageCode == 'A' || packageCode == 'B')
    	 {
    		 c_option = new ISPCharge('C', hours);
    		 result = this.calcCost() > c_option.calcCost();
    	 }
    	 return result;
     }
    
    /** savingsWithB calculates the savings with planB
     *  
     * @return the amount of saving with B, 0 if 
     *         no savings.
     */
     public double savingsWithB()
     {
    	 ISPCharge b_option;
    	 double result;
    	 
    	 result = 0.0;
       
    	 if (saveWithB())
    	 {
    		 b_option = new ISPCharge('B', hours);
    		 result = b_option.calcCost() - this.calcCost();
    	 }
    	 return Math.abs(result);
     }
     
     /** savingsWithC calculates the savings if the 
     * charge would be less if they were on plan C
     *  
     * @return the amount of saving with C.
     */
     public double savingsWithC()
     {
    	 ISPCharge c_option;
    	 double result;
    	 
    	 result = 0.0;
    	 if (saveWithC())
    	 {
    		 c_option = new ISPCharge('C', hours);
    		 result = c_option.calcCost() - this.calcCost();
    	 }
    	 return Math.abs(result);
     }

     /*************************************************
      * toString describes this charge.  It should include the 
      * package for this charge and the hours.
      *
      * @return a String representation of this package
      */   
      public String toString()
      {
    	  return String.format("Package: %s\tHours: %f", this.packageCode, this.hours);
      }
      
      /** needAddtlHours records whether or not 
       *  additional hours are needed for this 
       *  package
       *
       * @return true if we need to include additional
       *         hours, false otherwise
       */
      public boolean needAddtlHours()
      {
         boolean addtl;
         
         if (packageCode == 'A' || packageCode == 'B')
            addtl = true;
         else
            addtl = false;
         return addtl;
      }
      /** getAddtlHours calculates the additional hours
       *  based on this package code
       * 
       * @return the additional hours
       */
      public double getAddtlHours()
      {
    	  double extra;
    	  extra = 0; 
    	  
    	  if (needAddtlHours())
    	  {
    		  if (this.packageCode == 'A' && this.hours > this.A_CEILING)
    		  {
    			  extra = this.hours - this.A_CEILING;
    		  }
    		  else if (this.packageCode == 'B' && this.hours > this.B_CEILING)
    		  {
    			  extra = this.hours - this.B_CEILING;
    		  }
    	  }
    	  
    	  return extra;
      }
      /** getAddtlCharge calculates the 
       * additional charge for this package
       *
       *@return this additional charge.
       */
      public double getAddtlCharge()
      {
    	  double extra;
    	  extra = 0; 
    	  
    	  if (needAddtlHours())
    	  {
    		  if (this.packageCode == 'A' && this.hours > this.A_CEILING)
    		  {
    			  extra = getAddtlHours() * this.A_PRICE_HOUR;
    		  }
    		  else if (this.packageCode == 'B' && this.hours > this.B_CEILING)
    		  {
    			  extra = getAddtlHours() - this.B_PRICE_HOUR;
    		  }
    	  }
    	  
    	  return extra;

      }
      /** getBase returns the base charge
       *
       * @return the base charge for this package
       */
      public double getBase()
      {
    	  double base;
    	  if (packageCode == 'C')
    		  base = this.C_PRICE_MONTH;
    	  else if (packageCode == 'B')
    		  base = this.B_PRICE_MONTH;
    	  else
    		  base = this.A_PRICE_MONTH;
    	  
    	  return base;
    	  
      }
      
      /** getBaseHours returns the base
       *  hours for this package
       *
       * @return base hours. 
       */
      public double getBaseHours()
      {
    	  double base;
    	  if (packageCode == 'A')
    		  base = this.A_CEILING;
    	  else 
    		  base = this.B_CEILING;
    	  return base;  
      }

   /** getPackage returns the standardized 
    *  package code
    *
    * @return this package code
    */
	public char getPackage()
	{
		return packageCode;
	}
}
    			  
    	