import java.math.*;
import java.util.Scanner;

//Savings class 
public class Savings {
 public static double goal;
 public static double timeInWeeks;
 public static double homePay;
 public static double savings;
 public static double weeklySavings;
 public static double recSavings;
 //class constructor
 private Savings(double myGoal, double myWeeks, double myHomePay, double mySavings, double myWeeklySavings, double myRecSavings) 
 {
     goal = myGoal;
     timeInWeeks = myWeeks;
     homePay = myHomePay;
     savings = mySavings;
     weeklySavings = myWeeklySavings;
     recSavings = myRecSavings;
 }
 //setter for goal
 private void setGoal() {
	 //String is instantiated
	 String newValue = null;
	 //prompt user for input
	 System.out.print("What is your savings goal? \n");
	 //call function to get user input
	 newValue = getInput(newValue);
	 //apply double value while calling convert to decimal function
     goal = toDecimal(false,(Double.parseDouble(newValue)));
 }
 //getter for goal
 private double getGoal()
 { 
 return goal;
 }
 //setter for time
 private void setTime ()
 {
	 String newValue = null;
	 System.out.print("How many years do you plan to save to reach your goal? \n");
	 newValue = getInput(newValue);
	 timeInWeeks = Double.parseDouble(newValue);
	 //there are 52 weeks in a year to multiply by number of years
	 timeInWeeks = toDecimal(true,(timeInWeeks * 52));
 }
 //getter for time
 private double getTime()
 {
	return timeInWeeks;
 }
 //setter for home pay
 private void setHomePay() {
	 String newValue = null;
	 System.out.print("How much is your home pay? \n");
	 newValue = getInput(newValue);
     homePay = toDecimal(false,(Double.parseDouble(newValue)));
 }
 //getter for home pay
 private double getHomePay()
 {
 return homePay;
 }
 //setter for savings
 private void setSavings() {
	 String newValue = null;
	 System.out.print("How much do you currently have saved? \n");
	 newValue = getInput(newValue);
     savings = toDecimal(false,(Double.parseDouble(newValue)));
 }
 //getter for savings
 private double getSavings()
 {
 return savings;
 }
 //setter for weekly savings
 private void setWeeklySavings() {
	 String newValue = null;
	 System.out.print("How much can you save this week? \n");
	 newValue = getInput(newValue);
	 //double check this one
     weeklySavings = Double.parseDouble(newValue);
     //weekly savings is also added to overall savings to keep track of what is saved
     savings = toDecimal(false,(savings + weeklySavings));
 }
 //getter for weekly savings
 private double getWeeklySavings()
 {
 return weeklySavings;
 }
 // setter for recommended savings
 private void setRecSavings(double mytimePassed) {
	 //formula takes into consideration that constantly changing input and recalculates with new value apr and time passed
     recSavings = toDecimal(false,((goal - savings)-((goal - savings)*0.015))/(timeInWeeks-mytimePassed));
 }
 //getter for recommended savings
 private double getRecSavings()
 {
 return recSavings;
 }
 //function to check if input is a numeric value
 private static boolean isNumeric(String str)  
	{  
	  try  
	  {  
	    Double.parseDouble(str);  
	  }  
	  catch(NumberFormatException nfe)  
	  {  
	    return false;  
	  }  
	  //if is a numeric value then true, otherwise false
	  return true;  
	}
 //function to get user input
 private static String getInput(String newValue)
 {
	 Scanner input = new Scanner(System.in);
	 newValue = input.nextLine();
	 //call function to check if input is numeric
	 while (isNumeric(newValue) == false)
		{
		 //if input is not, them prompt the user to input a valid number
			System.out.print("Error\n please input valid number \n");
			newValue = input.nextLine();
		}
	return newValue;
 }
 //function to convert user input into decimal money format
 public static double toDecimal(boolean time, double myDecimal)
 	{
	 String s = null;
	 BigDecimal bg;
	 	if (time == false)
	 	{
	 		//if time is false then calculate money value to the second decimal
	 		bg = BigDecimal.valueOf(myDecimal);
	 		bg = bg.setScale(2, RoundingMode.CEILING);
	 		myDecimal = bg.doubleValue();
	 	}
	 	else
	 	{
	 		//if time is true then calculate time value without decimal ( in weeks )
	 		bg = BigDecimal.valueOf(myDecimal);
	 		bg = bg.setScale(0, RoundingMode.CEILING);
	 		myDecimal = bg.doubleValue();
	 	}
	 	return myDecimal;
 	}
//main function
 public static void main(String[] args) {
	 System.out.print("This is a program to track savings while applying a reccomended savings ammount\n");
	 System.out.print("The reccomended savings ammount will apply %1.5 apr and will re-calculate recommendation accordingly with each input\n");
	 //variable to hold previous recommended value for comparison
	 double oldSav = 0;
	 //variable to hold selection for case statement if income is less than recommended savings
	 int userInput = 0;
	 //variable to hold user selection for case statement
	 String newValue = null;
	 //constructor for savings sub class Daniel
	 Savings Daniel = new Savings(goal, timeInWeeks, homePay, savings, weeklySavings, recSavings);
	 //input timeframe in which to save in years to be converted to weeks
	 Daniel.setTime();
	 System.out.print("This is about " + Daniel.getTime() + " weeks \n");
	 //input goal
	 Daniel.setGoal();
	 System.out.print( "$" + Daniel.getGoal() + "\n");
	 //input savings
	 Daniel.setSavings();
	 //calculate initial recommended savings
	 Daniel.setRecSavings(0);
	 //input home income
	 Daniel.setHomePay();
	 System.out.print( "$" + Daniel.getHomePay() + "\n");
	 //if recommended savings is greater than home income then goal is unreachable and has to be modified
	 while (Daniel.getRecSavings() > Daniel.getHomePay())
	 {
		 System.out.print("Recomended saving ammount $" + Daniel.getRecSavings() + "\n");
	 System.out.print("Your recomended saving ammount is more than you earn! \nplease please sellect one to change to make your goal attainable\n");
	 System.out.print("1. change time \n2. change goal \n3. change savings \n4. Change home income\n");
	 	{
	 		//Case statement to adjust the factors that influence the recommended savings rate to make goal attainable
		 userInput = Integer.parseInt(getInput(newValue));
		 switch (userInput) {
	     case 1:  Daniel.setTime();
	              break;
	     case 2:  Daniel.setGoal();
	     		  break;
	     case 3:  Daniel.setSavings();
	     		  break;
	     case 4: Daniel.setHomePay();
	     		  break;}
	 	}
	 }
	 //if/when recommended savings amount is less than home income proceed to loop
		 for(int i = 1; i<=Daniel.getTime(); i++)
		 {
			 System.out.print("Week :" + i + "\n");
			 //get weekly savings input and recalculate recommended savings amount
			 System.out.print("The Reccomended ammout to save to reach your goal is $" + Daniel.getRecSavings() + "\n");
			 //add weekly savings input to overall savings
			 Daniel.setWeeklySavings();
			 // if user reaches goal then break loop
			 if (Daniel.getGoal() <= Daniel.getSavings())
			 {
				 break;
			 }
			 //if not then continue
			 else
			 {
				 //save previous value to compare with new recommended save
				 oldSav = Daniel.getRecSavings();
				 //set the new recommended savings amount
				 Daniel.setRecSavings(i);
				 //inform the user of what is saved so far
				 System.out.print("Saved so Far " + Daniel.getSavings() + "\n");
				 //if the what is saved is not what is recommended
				 if (Daniel.getWeeklySavings() != Daniel.getRecSavings())
				 {
					 //check to see if amount is less than recommended
					 if(Daniel.getWeeklySavings() < Daniel.getRecSavings())
					 {
						 System.out.printf("You’ll never make it at this rate, you need to save $%f more each week\n", (toDecimal(false,Daniel.getRecSavings() - oldSav)));
					 }
					 //if amount is not less, then it can only be more than what is recommended
					 else
					 {
						 System.out.printf("Slow down, you could save $%f less and still meet your goal\n", (toDecimal(false,oldSav - Daniel.getRecSavings()))); 
					 }
				 }
			 }
		 }
		 System.out.print("Congratulations, you've reached your goal");
 }
}
