diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 0f182a0..0000000 --- a/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -*.class - -# Package Files # -*.jar -*.war -*.ear diff --git a/README.md b/README.md deleted file mode 100644 index 87b7f79..0000000 --- a/README.md +++ /dev/null @@ -1,4 +0,0 @@ -budgetboss -========== - -The organizational repository for BudgetBoss \ No newline at end of file diff --git a/features/BudgetBossFeatureList.md b/features/BudgetBossFeatureList.md new file mode 100644 index 0000000..0605577 --- /dev/null +++ b/features/BudgetBossFeatureList.md @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureStoryStatus
BudgetBoss has a main menu +
    +
  • Given: Personal finances need to be managed in a boss-like fashion
  • +
  • When: BudgetBoss is launched
  • +
  • And: After an initial welcome message
  • +
  • Then: A main menu will appear with access to various functions
  • +
  • For more on available main menu features see: Main Menu Feature List +
Implemented
BudgetBoss can create new budgets +
    +
  • Given: BudgetBoss is running
  • +
  • When: A user needs to create a new budget
  • +
  • Then: The user will be prompted to name the budget, and it will be created and set as the budget in use
  • +
  • For more on the features of the budgets themselves, see: Budget Feature List
  • +
Implemented
BudgetBoss can save budgets to disk +
    +
  • Given: BudgetBoss is running and a budget is in use
  • +
  • When: A user needs to store a budget outside of the program
  • +
  • Then: The user can write the budget to disk as a .bgt file
  • +
Implemented
BudgetBoss can load saved budgets +
    +
  • Given: BudgetBoss is running
  • +
  • When: A user needs to access a previously saved budget
  • +
  • Then: The user can open the desired budget and it will load into BudgetBoss
  • +
Implemented
BudgetBoss can seach for budgets to load +
    +
  • Given: BudgetBoss is running
  • +
  • When: A user needs to access a previously saved budget
  • +
  • Then: The user can point BudgetBoss to a valid path and it will collect any saved budgets there for potential loading
  • +
  • For more on how the validity of the path is determined, see: Input Validator Feature List
  • +
Implemented
BudgetBoss can load budgets from a selectable list +
    +
  • Given: BudgetBoss has collected saved budgets from a directory searched
  • +
  • When: A user wants to open a collected budgets
  • +
  • Then: The budgets names will be printed and paired with indicator numbers, allowing the user to input the number of the budget they want to open
  • +
Implemented
BudgetBoss can generate budget reports +
    +
  • Given: BudgetBoss is running
  • +
  • When: A user needs to see a summary of all the information in a budget
  • +
  • Then: The user can print out the contents of the budget via the budget's toString() method, to the console
  • +
Implemented
BudgetBoss can save budget reports to disk +
    +
  • Given: BudgetBoss is running
  • +
  • When: A user needs to see a summary of all the information in a budget
  • +
  • And: Have access to that information outside of BudgetBoss +
  • Then: The user can print out the contents of the budget via the budget's toString() method, to a text document
  • +
Implemented
BudgetBoss indicates budget in use +
    +
  • Given: BudgetBoss is launched
  • +
  • When: A saved budget is opened or a budget is created
  • +
  • Then: An indicator above the menus will show the name of the current budget in use
  • +
Implemented
BudgetBoss knows when there is no budget in use +
    +
  • Given: BudgetBoss is launched
  • +
  • When: The main menu comes up initially, before a user has a chance to open/create a budget
  • +
  • Then: The indicator for the budget in use will show "No budget loaded"
  • +
  • And: Menu features will be restricted until a budget is opened/created.
  • +
  • For more on restricting menu functions see: Main Menu Feature List
  • + +
Implemented
BudgetBoss has a default load directory - Linux +
    +
  • Given: BudgetBoss is running
  • +
  • When: A user is loading a budget after initial program launch
  • +
  • Then: The user will be given the option, via inputting "y", to search their Documents directory for budgets, which is the program default(i.e. /home/nathan/Documents/)
  • +
Implemented
BudgetBoss has a default save directory - Linux +
    +
  • Given: BudgetBoss is running
  • +
  • When: A user is saving a budget/budget report after loading/creating one
  • +
  • Then: The user will be given the option, via inputting "y", to save to the budget to their Documents directory, which is the program default(i.e. /home/nathan/Documents/)
  • +
Implemented
BudgetBoss modifies default load directory +
    +
  • Given: BudgetBoss is running
  • +
  • When: A user is loading a budget after initial program launch
  • +
  • And: The user declines to use the default directory, and instead opts to input a custom load directory path
  • +
  • If: The user enters a valid path and successfully loads a budget from it
  • +
  • Then: BudgetBoss will make the directory from which the budget was loaded the new default load directory
  • +
  • For more on how the validity of the inputted path is determined, see: Input Validator Feature List
  • +
Implemented
BudgetBoss modifies default save directory +
    +
  • Given: BudgetBoss is running
  • +
  • When: A user is saving a budget/budget report
  • +
  • And: The user declines to use the default directory, and instead opts to input a custom save directory path
  • +
  • If: The user enters a valid path and successfully saves a budget
  • +
  • Then: BudgetBoss will make the directory to which the budget was saved the new default save directory
  • +
  • For more on how the validity of the inputted path is determined, see: Input Validator Feature List
  • +
Implemented
BudgetBoss shares same default directory for saving/loading +
    +
  • Given: BudgetBoss is running
  • +
  • When: A user is loading/saving a budget/budget report
  • +
  • Then: The default directory they are prompted with will be the last place a budget was saved/loaded from as both saving and loading share the same changeable default directory and either process can modify it
  • +
Implemented
BudgetBoss clears console output on launch and when displaying menus +
    +
  • Given: Personal finances need to be managed in a boss-like fashion
  • +
  • When: BudgetBoss is launched
  • +
  • And: When any menu is displayed +
  • Then: The console output is cleared allowing the menus to remain more or less fixed, for a more pleasant user experience
  • +
Implemented
BudgetBoss can edit budget name +
    +
  • Given: A budget is in use with BudgetBoss
  • +
  • When: A user wants to change the name of the budget in use
  • +
  • Then: A new name can be set for the budget, provided it is not "exit" (regardless of case, as that command works anywhere BudgetBoss takes input)
  • +
Implemented
BudgetBoss can edit budget dates +
    +
  • Given: A budget is in use with BudgetBoss
  • +
  • When: A user wants to change the start/end date of the budget in use
  • +
  • Then: New dates can be set for the budget, provided they are valid
  • +
  • For more on how the validity of the date is determined, see: InputValidator Feature List
  • +
Implemented
BudgetBoss has a global exit command +
    +
  • Given: BudgetBoss is running
  • +
  • When: A user wants to exit the program
  • +
  • And: Is able to provide input to BudgetBoss
  • +
  • Then: Providing "exit" as an input regardless of case will indeed exit the program
  • +
Implemented
\ No newline at end of file diff --git a/features/BudgetFeatureList.md b/features/BudgetFeatureList.md new file mode 100644 index 0000000..d079e47 --- /dev/null +++ b/features/BudgetFeatureList.md @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureStoryStatus
Budgets have names +
    +
  • Given: A budget is to be created
  • +
  • When: The budget is constructed with a String input
  • +
  • Then: That String becomes the budget name
  • +
Implemented
Budgets names serve as filenames +
    +
  • Given: A budget is to be saved
  • +
  • When: A filename is required
  • +
  • Then: The budget filename is derived from the the budget's name
  • +
Implemented
Budgets have start/end dates +
    +
  • Given: A budget is to be created
  • +
  • When: It is instantiated
  • +
  • Then: The budget will have fields for start and end date
  • +
Implemented
Budgets dates are null until set +
    +
  • Given: A budget is created
  • +
  • When: The user has not yet edited the start/end dates
  • +
  • Then: Those fields will be null, and if asked to display will instead show a message indicating they need to be set
  • +
Implemented
\ No newline at end of file diff --git a/features/EditorMenuFeatureList.md b/features/EditorMenuFeatureList.md new file mode 100644 index 0000000..eec0c9c --- /dev/null +++ b/features/EditorMenuFeatureList.md @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureStoryStatus
Editor menu presents options in a numbered list +
    +
  • Given: The editor is started in BudgetBoss
  • +
  • When: The options available on the editor menu need to presented to a user
  • +
  • Then: The options are printed out with numerical identifiers and a brief description
  • +
Implemented
Editor menu takes integer input to select from options +
    +
  • Given: The editor menu is displayed and a user wants to select a option
  • +
  • When: The user inputs a valid number corresponding with a visible option
  • +
  • Then: The associated action of the selected option is carried out
  • +
  • For more on how the validity of the input is determined, see: Input Validator Feature List
  • +
Implemented
Editor menu displays error messages below numbered option list +
    +
  • Given: An attempt was made to select an editor menu option
  • +
  • When: The input received to indicate selection is invalid
  • +
  • Then: An appropriate error message indicating the problem with the input will be printed at the bottom of the numbered list of options
  • +
  • And: The user will be able to offer input again
  • +
  • For more on how the validity of the input is determined, see: Input Validator Feature List
  • +
Implemented
Editor menu has the option to print a budget report to the console +
    +
  • Given: The editor menu of BudgetBoss is displayed
  • +
  • When: A user wants to generate a budget report to the console
  • +
  • Then: "Print budget report to console" will be an option on the menu
  • +
  • And: Upon selecting this option, the budget report prints to the console
  • +
  • For more on budget reports, see: BudgetBoss Feature List
  • +
Implemented
Editor menu has the option to save a budget report to disk +
    +
  • Given: The editor menu of BudgetBoss is displayed
  • +
  • When: A user wants to generate a budget report and save it for future access
  • +
  • Then: "Save a budget report" will be an option on the menu
  • +
  • And: Upon selecting this option, a budget report will be generated and saved to a directory of the user's choosing, as a text file
  • +
  • For more on how saving works in BudgetBoss or budget reports, see: BudgetBoss Feature List
  • +
Implemented
Editor menu has the option edit budget name +
    +
  • Given: The editor menu of BudgetBoss is displayed
  • +
  • When: A user wants to change the name of the budget in use
  • +
  • Then: "Edit budget name" will be an option on the menu
  • +
  • And: Upon selecting this option, a new name for the budget can be inputted
  • +
  • For more on editing the budget name, see: BudgetBoss Feature List
  • +
Implemented
Editor menu has the option edit budget dates +
    +
  • Given: The editor menu of BudgetBoss is displayed
  • +
  • When: A user wants to change the start/end date of the budget in use
  • +
  • Then: "Edit budget start date" and "Edit budget end date" will be options on the menu, respectively
  • +
  • And: Upon selecting either option, a new date can be inputted
  • +
  • For more on editing the budget dates, see: BudgetBoss Feature List
  • +
Implemented
Editor menu has the option to return to main menu +
    +
  • Given: The editor menu of BudgetBoss is displayed
  • +
  • When: A user wants to stop editing the budget in use and have access to the main menu options
  • +
  • Then: "Return to main menu" will be an option on the menu
  • +
  • And: Upon selecting this option, BudgetBoss will display the main menu
  • +
Implemented
\ No newline at end of file diff --git a/features/FeatureRequests b/features/FeatureRequests new file mode 100644 index 0000000..9adf8cc --- /dev/null +++ b/features/FeatureRequests @@ -0,0 +1 @@ +1) The customer is thrilled that their BudgetBoss program is coming along swimmingly! But they want to be able to integrate their budgets with Budginator, another program that looks at your budget history and proactively schedules online payments to pay down debt. Budginator accepts budgets in a JSON format, and expects them to adhere to the MasterBudget interface. diff --git a/features/InputValidatorFeatureList.md b/features/InputValidatorFeatureList.md new file mode 100644 index 0000000..461acdd --- /dev/null +++ b/features/InputValidatorFeatureList.md @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureStoryStatus
InputValidator can validate for integers +
    +
  • Given: BudgetBoss is running and requires an integer input
  • +
  • When: The user inputs anything other than an integer
  • +
  • Then: An error message is generated and the user is prompted again for input
  • +
Implemented
InputValidator can validate paths - Linux +
    +
  • Given: BudgetBoss is running and requires a path input
  • +
  • When: The user inputs anything other than a valid, existing Linux path
  • +
  • Then: An appropriate error message is generated based on the likely problem with the path and the user is prompted again for input
  • +
Implemented
InputValidator can validate budget selection when loading from a directory +
    +
  • Given: BudgetBoss has searched for budgets in a directory and is displaying the list of found budgets
  • +
  • When: The user inputs anything other than an integer corresponding with the printed list of budgets
  • +
  • Then: An error message is generated and the user is prompted again for input
  • +
Implemented
InputValidator can validate menu selections +
    +
  • Given: BudgetBoss is displaying a numbered menu and waiting for input
  • +
  • When: The user inputs anything other than an integer corresponding with the printed list of menu options
  • +
  • Then: An error message is generated and the user is prompted again for input
  • +
Implemented
InputValidator can validate date inputs +
    +
  • Given: Budgetboss is running and requires a date input (format: MM/DD/YYYY)
  • +
  • When: The user inputs anything other than an a valid date (Month 1-12, corresponding correct number of days, and no years from the past) in the above format
  • +
  • Then: An appropriate error message is generated based on the likely problem with the date and the user is prompted again for input
  • +
Implemented
InputValidator can recognize global exit command +
    +
  • Given: BudgetBoss is waiting for input
  • +
  • When: The user inputs "exit" regardless of case
  • +
  • Then: InputValidator reports this as a valid input, allowing the program to continue and subsequently exit
  • +
Implemented
\ No newline at end of file diff --git a/features/MainMenuFeatureList.md b/features/MainMenuFeatureList.md new file mode 100644 index 0000000..2c7099b --- /dev/null +++ b/features/MainMenuFeatureList.md @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureStoryStatus
Main menu presents options in a numbered list +
    +
  • Given: BudgetBoss is launched
  • +
  • When: The options available on the main menu need to presented to a user
  • +
  • Then: The options are printed out with numerical identifiers and a brief description
  • +
Implemented
Main menu takes integer input to select from options +
    +
  • Given: The main menu is displayed and a user wants to select a option
  • +
  • When: The user inputs a valid number corresponding with a visible option
  • +
  • Then: The associated action of the selected option is carried out
  • +
  • For more on how the validity of the input is determined, see: Input Validator Feature List
  • +
Implemented
Main menu displays error messages below numbered option list +
    +
  • Given: An attempt was made to select a main menu option
  • +
  • When: The input received to indicate selection is invalid
  • +
  • Then: An appropriate error message indicating the problem with the input will be printed at the bottom of the numbered list of options
  • +
  • And: The user will be able to offer input again
  • +
  • For more on how the validity of the input is determined, see: Input Validator Feature List
  • +
Implemented
Main menu restricts selectable options until a budget is in use +
    +
  • Given: BudgetBoss is launched
  • +
  • When: A user is prompted with the initial main menu
  • +
  • Then: The only options that are able to be chosen are open/create a budget, or to exit
  • +
Implemented
Main menu has the option to print a budget report to the console +
    +
  • Given: The main menu of BudgetBoss is displayed
  • +
  • When: A user wants to generate a budget report to the console
  • +
  • Then: "Print budget report to console" will be an option on the menu
  • +
  • And: Upon selecting this option, the budget report prints to the console
  • +
  • For more on budget reports, see: BudgetBoss Feature List
  • +
Implemented
Main menu has the option to save a budget report to disk +
    +
  • Given: The main menu of BudgetBoss is displayed
  • +
  • When: A user wants to generate a budget report and save it for future access
  • +
  • Then: "Save a budget report" will be an option on the menu
  • +
  • And: Upon selecting this option, a budget report will be generated and saved to a directory of the user's choosing, as a text file
  • +
  • For more on how saving works in BudgetBoss or budget reports, see: BudgetBoss Feature List
  • +
Implemented
Main menu has the option to start editing the budget in use +
    +
  • Given: The main menu of BudgetBoss is displayed and a budget is in use
  • +
  • When: A user wants to edit any aspect of the budget
  • +
  • Then: "Edit budget" will be an option on the menu
  • +
  • And: Upon selecting this option, the editor menu will appear, as if by magic
  • +
  • For more on the features of the editor menu, see: Editor Menu Feature List
  • +
Implemented
Main menu has the option to save a budget to disk +
    +
  • Given: The main menu of BudgetBoss is displayed
  • +
  • When: A user wants to save a budget for future access
  • +
  • Then: "Save budget" will be an option on the menu
  • +
  • And: Upon selecting this option, the budget will be saved to a directory of the user's choosing as a .bgt file
  • +
  • For more on how saving works in BudgetBoss, see: BudgetBoss Feature List
  • +
Implemented
Main menu has the option to load a budget from disk +
    +
  • Given: The main menu of BudgetBoss is displayed
  • +
  • When: A user wants to load a previously saved budget
  • +
  • Then: "Load budget" will be an option on the menu
  • +
  • And: Upon selecting this option, a budget will be loaded from a directory of the user's choosing
  • +
  • For more on how loading works in BudgetBoss, see: BudgetBoss Feature List
  • +
Implemented
Main menu has the option to create a new budget +
    +
  • Given: The main menu of BudgetBoss is displayed
  • +
  • When: A user wants to create a new budget
  • +
  • Then: "Create a new budget" will be an option on the menu
  • +
  • And: Upon selecting this option, a new budget will be created with a user-supplied name and set as the budget in use
  • +
  • For more on how creating budgets works in BudgetBoss, see: BudgetBoss Feature List
  • +
Implemented
Main menu has the option to exit BudgetBoss +
    +
  • Given: The main menu of BudgetBoss is displayed
  • +
  • When: A user wants to exit the program
  • +
  • Then: Exit BudgetBoss will be an option on the menu
  • + +
  • And: Upon selecting this option, BudgetBoss will exit
  • +
Implemented
\ No newline at end of file diff --git a/features/ToDo.md b/features/ToDo.md new file mode 100644 index 0000000..687fa25 --- /dev/null +++ b/features/ToDo.md @@ -0,0 +1,92 @@ +I have yet to find a budget application that works the way I want it to, so I am going to make one. The goal of this is to be supremely flexible, but I'm definitely going to be focusing on the paycheck-to-paycheck crowd initially with the features. + +To-Do List : BudgetBoss + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureStoryStatus
BudgetBoss has a default initial save/load directory - Windows +
    +
  • Given: An instance of BudgetBoss
  • +
  • When: The user wants to open/save a Budget
  • +
  • Then: BudgetBoss will offer to use C:\Users\(username)\Documents\
  • +
Not yet implemented
BudgetBoss can detect host OS and current username for default path generation +
    +
  • Given: An instance of BudgetBoss
  • +
  • And: The user wants to open/save a Budget
  • +
  • When: The default path is to be offered
  • +
  • Then: BudgetBoss will generate the correct path by detecting username and host OS
  • +
Partially implemented - It can get the username at this point
BudgetBoss has a user-definable save/load directory +
    +
  • Given: An instance of BudgetBoss
  • +
  • When: A budget needs to be saved/loaded
  • +
  • And: The user declines to use the default directory
  • +
  • Then: The user can define a custom directory, provided it is an existing/valid path
  • +
Partially implemented...only will work on Linux boxes at the moment
BudgetBoss validates user inputs +
    +
  • Given: An instance of BudgetBoss
  • +
  • And: Input is required/requested from the user
  • +
  • When: The user provides the input
  • +
  • Then: BudgetBoss will make sure it meets a set of conditions making it a valid input for whatever purpose the input was required/requested for
  • +
Partially implemented - not all checks in place, yet
BudgetBoss has a mode/menu for editing Budgets +
    +
  • Given: An instance of BudgetBoss
  • +
  • When: A Budget is either created or opened
  • +
  • Then: If desired, the user can access an Editor Menu
  • +
  • And: From there, make changes to any/all aspects of the Budget (specific editing features listed seperately)
  • +
Partially implemented - BudgetEditor exists, but is very sparse
Budgets have default spending categories to add +
    +
  • Given: An instance of BudgetBoss
  • +
  • When: A new Budget is created
  • +
  • Then: The Budget will have some built in spending categories to choose from
  • +
  • And: The user can choose from the categories and add them to the Budget as desired
  • +
Not yet implemented
BudgetBoss budgets can be integrated with Budginator +
    +
  • Given: A Budget created by BudgetBoss
  • +
  • When: That Budget is to be used with Budginator
  • +
  • Then: The Budget will conform to the MasterBudget Interface
  • +
  • And: The Budget can be converted into JSON format
  • +
Partially implemented - initial BudgetToJSON class in place
diff --git a/resources/cliOutput.properties b/resources/cliOutput.properties new file mode 100644 index 0000000..97822c9 --- /dev/null +++ b/resources/cliOutput.properties @@ -0,0 +1,44 @@ +welcome = Welcome to BudgetBoss!\nManage your money...like a boss.\nHit enter to continue... +openBudget = \nWhich budget do you want to open? (#) +invalidEntryYN = Invalid entry! Try again.(y/n) +searchingDirectory = Searching for budgets...\n +noBudgetFound = You don't have any saved budgets there! +noBudgetToSave = No budget to save! +dontSearchBudgets = Not gonna open a budget? I can dig it. +getBudgetName = Let's make a budget!\nWhat do you want to name the budget? (This will be the filename) +fuckThisProgram = You're saying you don't want to open a budget...and you don't want to make one...\nIf you don't want to use me baby, you should exit.\n +getSaveDirectoryPath = Where do you want to save the file? Enter the path or enter y for the default: +badPathInput = That's not a valid path, yo. Try again, or enter y for the default: +notEvenANumberGenius = \nThat's...not a number. Try again! +youreAZero = \nDo you see a choice 0? Does that even make sense to you? Try again. +thatsNotAChoice = \nThat's not one you can choose from, yo. WTF? Try again! +wTF = Something has gone wrong. ABORT THE BABIES!" +budgetSaved = Budget saved successfully!\n +savedInDefault = Where is the budget saved? The default directory is: +whereSaved = Enter y for the default, or enter path below: +endsInSlash = Directory path should end with a "/". Try again, or enter y for the default: +mainMenuHeader = ------------------------\n| BUDGETBOSS MAIN MENU |\n------------------------ +editorMenuHeader = --------------------\n| EDITOR MAIN MENU |\n-------------------- +getNewName = Enter the new name for the budget: +getNewStartDate = Enter the new start date below: (format - MM/DD/YYYY) +getNewEndDate = Enter the new end date below: (format - MM/DD/YYYY) +whitespaceGenius = Paths don't have spaces. C'mon now. Try again, or enter y for the default: +noBudgetLoaded = \nNo budget loaded! You need to open one first, homie, or create one to use.\nTry another choice: +wrongDateFormat = Please format the date MM/DD/YYYY. Try again: +notAMonth = Not a valid date, check the month. Try again: +notADay = Not a valid date, check the day number. Try again: +dontBeASmartass = C'mon. Don't even pretend to try and start a budget on Feb 29th, smartass. Try again: +backToTheFuture = A budget from last year? Further? Forget it. Make it for this year. Or the future...try again: +lessLettersPorFavor = Could you put less letters in the date? Cool, thanks. Try again: +reportToConsoleOption = Print a budget report to the console +reportToDiskOption = Save a budget report +startEditorOption = Edit budget +saveBudgetOption = Save budget +openBudgetOption = Open a saved budget +createBudgetOption = Create a new budget +exitOption = Exit BudgetBoss +newNameOption = Edit budget name +newStartOption = Edit budget start date +newEndOption = Edit budget end date +toMainOption = Return to Main Menu +dateNotSet = You haven't set this date yet! Better get on it. \ No newline at end of file diff --git a/src/com/visionarysoftwaresolutions/budgetboss/app/BudgetBoss.java b/src/com/visionarysoftwaresolutions/budgetboss/app/BudgetBoss.java new file mode 100644 index 0000000..059751c --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/app/BudgetBoss.java @@ -0,0 +1,72 @@ +package com.visionarysoftwaresolutions.budgetboss.app; + +import static org.fusesource.jansi.Ansi.ansi; +import org.fusesource.jansi.AnsiConsole; + +import com.visionarysoftwaresolutions.budgetboss.budget.*; +import com.visionarysoftwaresolutions.budgetboss.cli.*; +import com.visionarysoftwaresolutions.budgetboss.fileops.*; +import com.visionarysoftwaresolutions.budgetboss.menu.*; + +public class BudgetBoss { + + static Budget currentBudget = new Budget("No budget loaded"); + static String defaultDirectory; + static MasterMenu mainMenu; + static boolean stillUsingBudgetBoss = true; + static boolean loadASavedBudget = true; + static boolean needANewBudget = true; + + public static void loadSavedBudget(){ + loadASavedBudget = true; + } + + public static void endLoadSavedBudget(){ + loadASavedBudget = false; + } + + public static void needNewBudget(){ + needANewBudget = true; + } + + public static void endNeedNewBudget(){ + needANewBudget = false; + } + + public static void doneUsingBudgetBoss(){ + stillUsingBudgetBoss = false; + } + + public static void setDefaultDirectory(String newDefaultDirectory){ + defaultDirectory = newDefaultDirectory; + } + + public static String getDefaultDirectory(){ + return defaultDirectory; + } + + public static void setCurrentBudget(Budget newBudget){ + currentBudget = newBudget; + mainMenu = new MainMenu(newBudget); + } + + public static String getCurrentBudget(){ + return currentBudget.getName(); + } + + public static void main(String args[]){ + AnsiConsole.out.println(ansi().eraseScreen()); + defaultDirectory = Finder.pathFinder(); + mainMenu = new MainMenu(currentBudget); + Printer.print("welcome"); + Listener.getInput(); + + while (stillUsingBudgetBoss){ + mainMenu.getOption(mainMenu); + while(loadASavedBudget) + Opener.getLoadDirectory(); + while(needANewBudget) + TheCreator.createBudget(); + } + } +} \ No newline at end of file diff --git a/src/com/visionarysoftwaresolutions/budgetboss/budget/Budget.java b/src/com/visionarysoftwaresolutions/budgetboss/budget/Budget.java new file mode 100644 index 0000000..de9632c --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/budget/Budget.java @@ -0,0 +1,88 @@ +package com.visionarysoftwaresolutions.budgetboss.budget; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.*; +import org.joda.time.*; + +import com.visionarysoftwaresolutions.budgetboss.budginator.*; +import com.visionarysoftwaresolutions.budgetboss.cli.DateConverter; +import com.visionarysoftwaresolutions.budgetboss.cli.Printer; + +public class Budget implements MasterBudget, Serializable{ + + private static final long serialVersionUID = -8611741910364436624L; + + private Collection items; + private BigDecimal totalCost; + private ArrayList expenseCategories; + private ArrayList incomeCategories; + private String name; + private LocalDate startDate; + private LocalDate endDate; + + public Budget(String name){ + setName(name); + } + + public String getName(){ + return name; + } + + public void setName(String name){ + this.name = name; + } + + public String getStartDate() { + if(!(startDate == null)){ + String startDateOutput = DateConverter.formateDate(startDate); + return startDateOutput; + }else + return Printer.getPrintout("dateNotSet"); + } + + public void setStartDate(String newDate) { + String convertedDate = DateConverter.convertDate(newDate); + this.startDate = new LocalDate(convertedDate); + } + + public String getEndDate() { + if(!(endDate == null)){ + String endDateOutput = DateConverter.formateDate(endDate); + return endDateOutput; + }else + return Printer.getPrintout("dateNotSet"); + } + + public void setEndDate(String newDate) { + String convertedDate = DateConverter.convertDate(newDate); + this.endDate = new LocalDate(convertedDate); + } + + + public String toString(){ + return ("\nBudget Name: " + getName() + "\nBudget Start: " + getStartDate() + + "\nBudget End: " + getEndDate() + "\n"); + } + + @Override + public Collection items() { + return items; + } + + @Override + public BigDecimal total() { + return totalCost; + } + + @Override + public LocalDate start() { + return startDate; + } + + @Override + public LocalDate end() { + return endDate; + } + +} diff --git a/src/com/visionarysoftwaresolutions/budgetboss/budget/Expense.java b/src/com/visionarysoftwaresolutions/budgetboss/budget/Expense.java new file mode 100644 index 0000000..3538b28 --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/budget/Expense.java @@ -0,0 +1,42 @@ +package com.visionarysoftwaresolutions.budgetboss.budget; + +import java.math.BigDecimal; +import org.joda.time.LocalDate; + +public class Expense { + + private BigDecimal cost; + private LocalDate incurredOn; + private String payee; + + public Expense(BigDecimal cost, LocalDate incurredOn, String payee){ + this.cost = cost; + this.incurredOn = incurredOn; + this.payee = payee; + } + + public void setCost(BigDecimal cost){ + this.cost = cost; + } + + public BigDecimal getCost(){ + return cost; + } + + public void setIncurred(LocalDate incurredOn){ + this.incurredOn = incurredOn; + } + + public LocalDate getIncurred(){ + return incurredOn; + } + + public void setPayee(String payee){ + this.payee = payee; + } + + public String getPayee(){ + return payee; + } + +} diff --git a/src/com/visionarysoftwaresolutions/budgetboss/budget/ExpenseCategory.java b/src/com/visionarysoftwaresolutions/budgetboss/budget/ExpenseCategory.java new file mode 100644 index 0000000..2ab8359 --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/budget/ExpenseCategory.java @@ -0,0 +1,29 @@ +package com.visionarysoftwaresolutions.budgetboss.budget; + +import java.math.BigDecimal; +import java.util.ArrayList; + +public class ExpenseCategory { + + private String categoryName; + private ArrayList expenses = new ArrayList(); + private BigDecimal budgeted; + private BigDecimal totalSpent; + private BigDecimal totalRemaining; + + public ExpenseCategory(String name){ + categoryName = name; + } + + public void addExpense(Expense expense){ + expenses.add(expense); + } + + public BigDecimal getSpent(){ + totalSpent = new BigDecimal("00.00"); + for(int i = 0; i < expenses.size(); i++){ + totalSpent = totalSpent.add(expenses.get(i).getCost()); + } + return totalSpent; + } +} diff --git a/src/com/visionarysoftwaresolutions/budgetboss/budget/Income.java b/src/com/visionarysoftwaresolutions/budgetboss/budget/Income.java new file mode 100644 index 0000000..dbe774d --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/budget/Income.java @@ -0,0 +1,5 @@ +package com.visionarysoftwaresolutions.budgetboss.budget; + +public class Income { + +} diff --git a/src/com/visionarysoftwaresolutions/budgetboss/budget/IncomeCategory.java b/src/com/visionarysoftwaresolutions/budgetboss/budget/IncomeCategory.java new file mode 100644 index 0000000..d58b205 --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/budget/IncomeCategory.java @@ -0,0 +1,5 @@ +package com.visionarysoftwaresolutions.budgetboss.budget; + +public class IncomeCategory { + +} diff --git a/src/com/visionarysoftwaresolutions/budgetboss/budginator/BudgetToJSON.java b/src/com/visionarysoftwaresolutions/budgetboss/budginator/BudgetToJSON.java new file mode 100644 index 0000000..e9fcff1 --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/budginator/BudgetToJSON.java @@ -0,0 +1,17 @@ +package com.visionarysoftwaresolutions.budgetboss.budginator; + +import org.json.simple.*; + +import com.visionarysoftwaresolutions.budgetboss.budget.Budget; + +public class BudgetToJSON { + + @SuppressWarnings("unchecked") + public static JSONObject convertToBudginator(Budget budget){ + JSONObject convertedBudget = new JSONObject(); + convertedBudget.put("name", budget.getName()); + convertedBudget.put("startDate", budget.getStartDate()); + convertedBudget.put("endDate", budget.getEndDate()); + return convertedBudget; + } +} diff --git a/src/com/visionarysoftwaresolutions/budgetboss/budginator/LineItem.java b/src/com/visionarysoftwaresolutions/budgetboss/budginator/LineItem.java new file mode 100644 index 0000000..3f74e4a --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/budginator/LineItem.java @@ -0,0 +1,10 @@ +package com.visionarysoftwaresolutions.budgetboss.budginator; + +import java.math.BigDecimal; +import org.joda.time.*; +public interface LineItem { + + LocalDate purchased(); + String item(); + BigDecimal cost(); +} diff --git a/src/com/visionarysoftwaresolutions/budgetboss/budginator/MasterBudget.java b/src/com/visionarysoftwaresolutions/budgetboss/budginator/MasterBudget.java new file mode 100644 index 0000000..39f4745 --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/budginator/MasterBudget.java @@ -0,0 +1,13 @@ +package com.visionarysoftwaresolutions.budgetboss.budginator; + +import java.math.BigDecimal; +import java.util.*; +import org.joda.time.*; + +public interface MasterBudget { + + Collection items(); + BigDecimal total(); + LocalDate start(); + LocalDate end(); +} diff --git a/src/com/visionarysoftwaresolutions/budgetboss/cli/DateConverter.java b/src/com/visionarysoftwaresolutions/budgetboss/cli/DateConverter.java new file mode 100644 index 0000000..aadcc94 --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/cli/DateConverter.java @@ -0,0 +1,21 @@ +package com.visionarysoftwaresolutions.budgetboss.cli; + +import org.joda.time.LocalDate; +import org.joda.time.format.*; + +public class DateConverter { + + private static DateTimeFormatter formatter = DateTimeFormat.forPattern("MM/dd/yyyy"); + + public static String formateDate(LocalDate toFormat){ + String formatted = toFormat.toString(formatter); + return formatted; + } + + public static String convertDate(String toConvert){ + String delimiter = "[/]"; + String[] dateInput = toConvert.split(delimiter); + String convertedDate = dateInput[2] + "-" + dateInput[0] + "-" + dateInput[1]; + return convertedDate; + } +} diff --git a/src/com/visionarysoftwaresolutions/budgetboss/cli/InputValidator.java b/src/com/visionarysoftwaresolutions/budgetboss/cli/InputValidator.java new file mode 100644 index 0000000..ab72799 --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/cli/InputValidator.java @@ -0,0 +1,168 @@ +package com.visionarysoftwaresolutions.budgetboss.cli; + +import static org.fusesource.jansi.Ansi.ansi; + +import java.io.File; + +import org.fusesource.jansi.AnsiConsole; +import org.joda.time.DateTime; + +import com.visionarysoftwaresolutions.budgetboss.app.BudgetBoss; +import com.visionarysoftwaresolutions.budgetboss.menu.*; + +public class InputValidator { + + private InputValidator(){} + + public static boolean inputNotAnInteger(String toCheck){ + if(itsTimeToExit(toCheck)) + return false; + try{ + Integer.parseInt(toCheck); + }catch(NumberFormatException e){ + return true; + } + if(Integer.parseInt(toCheck) <= 0) + return true; + else + return false; + } + + public static boolean pathIsInvalid(String toCheck){ + File directory = new File(toCheck); + if(itsTimeToExit(toCheck)) + return false; + if(toCheck.equalsIgnoreCase("y")) + return false; + if(toCheck.endsWith("/")){ + if(directory.isDirectory()) + return false; + } + if(toCheck.contains(" ")){ + AnsiConsole.out.println(ansi().eraseScreen()); + Printer.print("whitespaceGenius"); + System.out.println("The default is: " + BudgetBoss.getDefaultDirectory()); + return true; + } + if(!toCheck.endsWith("/")){ + AnsiConsole.out.println(ansi().eraseScreen()); + Printer.print("endsInSlash"); + System.out.println("The default is: " + BudgetBoss.getDefaultDirectory()); + return true; + }else{ + AnsiConsole.out.println(ansi().eraseScreen()); + Printer.print("badPathInput"); + System.out.println("The default is: " + BudgetBoss.getDefaultDirectory()); + return true; + } + } + + public static boolean inputNotABudget(String toCheck, int highestChoice){ + if(itsTimeToExit(toCheck)) + return false; + if(inputNotAnInteger(toCheck)) + return true; + if(Integer.valueOf(toCheck).equals(0)){ + Printer.print("youreAZero"); + return true; + } + int userChoice = Integer.valueOf(toCheck); + if(userChoice > highestChoice){ + Printer.print("thatsNotAChoice"); + return true; + } + else + return false; + } + + public static boolean menuChoiceIsInvalid(String toCheck, MasterMenu menu){ + if(itsTimeToExit(toCheck)) + return false; + if(inputNotAnInteger(toCheck)){ + menu.setErrorMessage(Printer.getPrintout("notEvenANumberGenius")); + return true; + } + int userChoice = Integer.valueOf(toCheck); + if(Integer.valueOf(toCheck).equals(0)){ + menu.setErrorMessage(Printer.getPrintout("youreAZero")); + return true; + } + if(userChoice > menu.getNumberOfOptions()){ + menu.setErrorMessage(Printer.getPrintout("thatsNotAChoice")); + return true; + } + else + return false; + } + + public static boolean dateIsInvalid(String toCheck){ + if(itsTimeToExit(toCheck)) + return false; + if(!toCheck.contains("/")){ + Printer.print("wrongDateFormat"); + return true; + } + if(toCheck.contains(" ")){ + Printer.print("wrongDateFormat"); + return true; + } + String delimiter = "/"; + String[] date = toCheck.split(delimiter); + if(!(date.length == 3)){ + Printer.print("wrongDateFormat"); + return true; + } + for(int i = 0; i < 3; i++){ + try{ + Integer.parseInt(date[i]); + }catch(NumberFormatException e){ + Printer.print("lessLettersPorFavor"); + return true; + } + } + int month = Integer.valueOf(date[0].toString()); + int day = Integer.valueOf(date[1].toString()); + int year = Integer.valueOf(date[2].toString()); + if((month < 1) || (month > 12)){ + Printer.print("notAMonth"); + return true; + } + if((month == 4) || (month == 6) || (month == 9) || (month == 11)){ + if((day < 1) || (day > 30)){ + Printer.print("notADay"); + return true; + } + }else if(month == 2){ + if((day == 29)){ + Printer.print("dontBeASmartass"); + return true; + } + if((day < 1) || (day > 28)){ + Printer.print("notADay"); + return true; + } + }else{ + if((day < 1) || (day > 31)){ + Printer.print("notADay"); + return true; + } + } + DateTime timeNow = new DateTime(); + int currentYear = timeNow.getYear(); + if(year < currentYear){ + Printer.print("backToTheFuture"); + return true; + }else + return false; + } + + public static boolean itsTimeToExit(String toCheck){ + if(toCheck.equalsIgnoreCase("exit")){ + BudgetBoss.endLoadSavedBudget(); + BudgetBoss.endNeedNewBudget(); + BudgetBoss.doneUsingBudgetBoss(); + return true; + }else + return false; + } +} \ No newline at end of file diff --git a/src/com/visionarysoftwaresolutions/budgetboss/cli/Listener.java b/src/com/visionarysoftwaresolutions/budgetboss/cli/Listener.java new file mode 100644 index 0000000..7137607 --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/cli/Listener.java @@ -0,0 +1,21 @@ +package com.visionarysoftwaresolutions.budgetboss.cli; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +public class Listener { + + private Listener(){} + + public static String getInput(){ + String userInput = null; + BufferedReader listener = new BufferedReader(new InputStreamReader(System.in)); + try { + userInput = listener.readLine(); + } catch (IOException e) { + System.out.println("You fucked up. I mean, it wasn't me. Un-Bosslike."); + } + return userInput; + } +} \ No newline at end of file diff --git a/src/com/visionarysoftwaresolutions/budgetboss/cli/Printer.java b/src/com/visionarysoftwaresolutions/budgetboss/cli/Printer.java new file mode 100644 index 0000000..26ef671 --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/cli/Printer.java @@ -0,0 +1,37 @@ +package com.visionarysoftwaresolutions.budgetboss.cli; + +import java.io.File; +import java.util.*; +import com.visionarysoftwaresolutions.budgetboss.menu.MasterOption; + +public class Printer { + + private Printer(){} + + private static ResourceBundle cliOutput = ResourceBundle.getBundle("cliOutput"); + + public static String getPrintout(String toGet){ + return cliOutput.getString(toGet); + } + + public static void print(String toGet){ + System.out.println(cliOutput.getString(toGet)); + } + + public static void printMenuOptions(MasterOption[] menuOptions){ + for(int i = 0; i < menuOptions.length; i++){ + int optionNumber = (i + 1); + System.out.println(optionNumber + ") " + menuOptions[i].printOption()); + } + } + + public static void printFoundBudgets(File[] foundBudgets){ + List budgetNames = new ArrayList(); + for(int i = 0; i < foundBudgets.length; i++) + budgetNames.add(foundBudgets[i].getName()); + for(int i = 0; i < budgetNames.size(); i++){ + String budgetName = budgetNames.get(i); + System.out.println((i+1) + ") " + budgetName); + } + } +} \ No newline at end of file diff --git a/src/com/visionarysoftwaresolutions/budgetboss/fileops/Finder.java b/src/com/visionarysoftwaresolutions/budgetboss/fileops/Finder.java new file mode 100644 index 0000000..11c8a1d --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/fileops/Finder.java @@ -0,0 +1,39 @@ +package com.visionarysoftwaresolutions.budgetboss.fileops; + +import java.io.*; + +public class Finder { + + private Finder() {} + + private static String currentOS; + private static String currentUser; + + public static File[] findBudgets(String directoryToSearch){ + File foundBudget = new File(directoryToSearch); + return foundBudget.listFiles(new FilenameFilter(){ + public boolean accept(File foundBudget, String filename){ + return filename.endsWith(".bgt"); + } + }); + } + + public static String pathFinder(){ + currentOS = System.getProperty("os.name").toLowerCase(); + currentUser = System.getProperty("user.name"); + if(isWindows()){ + return ("C:/Users/" + currentUser + "/Documents/"); + }else if(isLinux()){ + return ("/home/" + currentUser + "/Documents/"); + }else + return "Can't determine default path!"; + } + + private static boolean isWindows(){ + return (currentOS.indexOf("win") >= 0); + } + + private static boolean isLinux(){ + return (currentOS.indexOf("nux") >=0); + } +} \ No newline at end of file diff --git a/src/com/visionarysoftwaresolutions/budgetboss/fileops/Opener.java b/src/com/visionarysoftwaresolutions/budgetboss/fileops/Opener.java new file mode 100644 index 0000000..8561bde --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/fileops/Opener.java @@ -0,0 +1,95 @@ +package com.visionarysoftwaresolutions.budgetboss.fileops; + +import java.io.*; + +import org.fusesource.jansi.AnsiConsole; +import static org.fusesource.jansi.Ansi.ansi; +import com.visionarysoftwaresolutions.budgetboss.app.BudgetBoss; +import com.visionarysoftwaresolutions.budgetboss.budget.Budget; +import com.visionarysoftwaresolutions.budgetboss.cli.*; + +public class Opener { + + private Opener(){} + + public static void getLoadDirectory(){ + AnsiConsole.out.println(ansi().eraseScreen()); + Printer.print("savedInDefault"); + System.out.println(BudgetBoss.getDefaultDirectory()); + Printer.print("whereSaved"); + String toCheck = Listener.getInput(); + while(InputValidator.pathIsInvalid(toCheck)) + toCheck = Listener.getInput(); + if(!(toCheck.equals("exit"))){ + if(toCheck.equalsIgnoreCase("y")){ + searchDirectory(BudgetBoss.getDefaultDirectory()); + }else + searchDirectory(toCheck); + } + } + + private static void searchDirectory(String directoryToSearch){ + AnsiConsole.out.println(ansi().eraseScreen()); + Printer.print("searchingDirectory"); + File [] foundBudgets = Finder.findBudgets(directoryToSearch); + if(foundBudgets.length > 0){ + chooseBudget(foundBudgets); + BudgetBoss.setDefaultDirectory(directoryToSearch); + }else + Printer.print("noBudgetFound"); + } + + private static void chooseBudget(File[] foundBudgets){ + Printer.printFoundBudgets(foundBudgets); + Printer.print("openBudget"); + int index = getChoiceNumber(foundBudgets); + if(!(index == -5)){ + System.out.println("Opening " + foundBudgets[index].getName() + "...\n"); + BudgetBoss.setCurrentBudget(loadBudget(index, foundBudgets)); + BudgetBoss.endNeedNewBudget(); + } + } + + private static int getChoiceNumber(File[] foundBudgets){ + String toCheck = Listener.getInput(); + int highestChoice = foundBudgets.length; + while(InputValidator.inputNotABudget(toCheck, highestChoice)) + toCheck = Listener.getInput(); + if(!(toCheck.equals("exit"))) + return (Integer.valueOf(toCheck) - 1); + else + return -5; + } + + private static Budget loadBudget(int index, File[] foundBudgets){ + FileInputStream newBudget = null; + ObjectInputStream toLoad = null; + Object loadedBudget = null; + try { + newBudget = new FileInputStream(foundBudgets[index].toString()); + } catch (FileNotFoundException e) { + Printer.print("wTF"); + System.out.println("Error making the FileInputStream"); + } + try { + toLoad = new ObjectInputStream(newBudget); + } catch (IOException e) { + Printer.print("wTF"); + System.out.println("Error making the ObjectInputStream"); + } + try { + loadedBudget = toLoad.readObject(); + } catch (ClassNotFoundException | IOException e) { + Printer.print("wTF"); + System.out.println("IO exception, maybe the file is bad?"); + } + try { + toLoad.close(); + } catch (IOException e) { + Printer.print("wTF"); + System.out.println("Couldn't close the Object/File input streams."); + } + BudgetBoss.endLoadSavedBudget(); + return (Budget) loadedBudget; + } +} diff --git a/src/com/visionarysoftwaresolutions/budgetboss/fileops/Savior.java b/src/com/visionarysoftwaresolutions/budgetboss/fileops/Savior.java new file mode 100644 index 0000000..0277ff5 --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/fileops/Savior.java @@ -0,0 +1,60 @@ +package com.visionarysoftwaresolutions.budgetboss.fileops; + +import java.io.*; + +import com.visionarysoftwaresolutions.budgetboss.app.BudgetBoss; +import com.visionarysoftwaresolutions.budgetboss.budget.Budget; +import com.visionarysoftwaresolutions.budgetboss.cli.*; + +public class Savior { + + private Savior(){} + + private static String getSaveDirectory(){ + Printer.print("getSaveDirectoryPath"); + System.out.println("The default is: " + BudgetBoss.getDefaultDirectory()); + String toCheck = Listener.getInput(); + while(InputValidator.pathIsInvalid(toCheck)) + toCheck = Listener.getInput(); + if(!(toCheck.equalsIgnoreCase("exit"))){ + if(toCheck.equalsIgnoreCase("y")) + return BudgetBoss.getDefaultDirectory(); + else + return toCheck; + }else + return toCheck; + } + + public static void writeBudgetToDisk(String fileName, Budget budget){ + String pathToSalvation = getSaveDirectory(); + if(!(pathToSalvation.equalsIgnoreCase("exit"))){ + try{ + FileOutputStream saveFile = new FileOutputStream(pathToSalvation + fileName + ".bgt"); + ObjectOutputStream saveOutput = new ObjectOutputStream(saveFile); + saveOutput.writeObject(budget); + saveOutput.close(); + Printer.print("budgetSaved"); + BudgetBoss.setDefaultDirectory(pathToSalvation); + }catch(Exception ex){ + ex.printStackTrace(); + } + } + } + + public static void generateBudgetReport(String fileName, Budget budget){ + String pathToSalvation = getSaveDirectory(); + if(!(pathToSalvation.equalsIgnoreCase("exit"))){ + try { + PrintStream budgetToText = new PrintStream(new FileOutputStream(pathToSalvation + fileName + ".txt")); + budgetToText.println(budget.toString()); + budgetToText.close(); + Printer.print("budgetSaved"); + BudgetBoss.setDefaultDirectory(pathToSalvation); + } catch (FileNotFoundException e) { + System.out.println("Rethink this, son."); + e.printStackTrace(); + } + } + } +} + diff --git a/src/com/visionarysoftwaresolutions/budgetboss/fileops/TheCreator.java b/src/com/visionarysoftwaresolutions/budgetboss/fileops/TheCreator.java new file mode 100644 index 0000000..e56a0b5 --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/fileops/TheCreator.java @@ -0,0 +1,25 @@ +package com.visionarysoftwaresolutions.budgetboss.fileops; + +import com.visionarysoftwaresolutions.budgetboss.app.BudgetBoss; +import com.visionarysoftwaresolutions.budgetboss.budget.Budget; +import com.visionarysoftwaresolutions.budgetboss.cli.*; + +public class TheCreator { + + private TheCreator(){} + + public static void createBudget(){ + Printer.print("getBudgetName"); + String desiredName = Listener.getInput(); + if(!(desiredName.equals("exit"))){ + System.out.println("Creating budget " + desiredName + "...\n"); + Budget newBudget = new Budget(desiredName); + BudgetBoss.setCurrentBudget(newBudget); + BudgetBoss.endNeedNewBudget(); + }else{ + BudgetBoss.endLoadSavedBudget(); + BudgetBoss.endNeedNewBudget(); + BudgetBoss.doneUsingBudgetBoss(); + } + } +} diff --git a/src/com/visionarysoftwaresolutions/budgetboss/menu/EditorMenu.java b/src/com/visionarysoftwaresolutions/budgetboss/menu/EditorMenu.java new file mode 100644 index 0000000..edce0e2 --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/menu/EditorMenu.java @@ -0,0 +1,115 @@ +package com.visionarysoftwaresolutions.budgetboss.menu; + +import static org.fusesource.jansi.Ansi.ansi; +import org.fusesource.jansi.AnsiConsole; +import com.visionarysoftwaresolutions.budgetboss.app.BudgetBoss; +import com.visionarysoftwaresolutions.budgetboss.budget.Budget; +import com.visionarysoftwaresolutions.budgetboss.cli.*; +import com.visionarysoftwaresolutions.budgetboss.fileops.Savior; + +public class EditorMenu implements MasterMenu{ + + private Budget toEdit; + private boolean stillEditing = true; + private String errorMessage = ""; + + public EditorMenu(Budget toEdit){ + this.toEdit = toEdit; + } + + public void setErrorMessage(String newMessage){ + errorMessage = newMessage; + } + + public boolean stillEditingBudget(){ + return stillEditing; + } + + public int getNumberOfOptions() { + return menuOptions.length; + } + + private MasterOption[] menuOptions = new MasterOption[] { + new MasterOption() {String optionPrintout = Printer.getPrintout("reportToConsoleOption"); + public void optionMethod() {System.out.println(toEdit.toString());} + public String printOption(){return optionPrintout;}}, + new MasterOption() {String optionPrintout = Printer.getPrintout("reportToDiskOption"); + public void optionMethod() {reportToDisk();} + public String printOption(){return optionPrintout;}}, + new MasterOption() {String optionPrintout = Printer.getPrintout("newNameOption"); + public void optionMethod() {getNewName();} + public String printOption(){return optionPrintout;}}, + new MasterOption() {String optionPrintout = Printer.getPrintout("newStartOption"); + public void optionMethod() {getNewStartDate();} + public String printOption(){return optionPrintout;}}, + new MasterOption() {String optionPrintout = Printer.getPrintout("newEndOption"); + public void optionMethod() {getNewEndDate();} + public String printOption(){return optionPrintout;}}, + new MasterOption() {String optionPrintout = Printer.getPrintout("toMainOption"); + public void optionMethod() {stillEditing = false;} + public String printOption(){return optionPrintout;}} + }; + + public void displayMenu(){ + AnsiConsole.out.println(ansi().eraseScreen()); + Printer.print("editorMenuHeader"); + System.out.println("Budget in use: " + toEdit.getName() + "\n"); + Printer.printMenuOptions(menuOptions); + } + + public void getOption(MasterMenu menu){ + displayMenu(); + System.out.println(errorMessage); + String userInput = Listener.getInput(); + while(InputValidator.menuChoiceIsInvalid(userInput, this)){ + displayMenu(); + System.out.println(errorMessage); + userInput = Listener.getInput(); + } + if(!(userInput.equalsIgnoreCase("exit"))){ + int optionChose = Integer.valueOf(userInput); + chooseOption(optionChose); + }else + stillEditing = false; + } + + private void reportToDisk(){ + Savior.generateBudgetReport(toEdit.getName(), toEdit); + } + + private void getNewName(){ + Printer.print("getNewName"); + String userInput = Listener.getInput(); + if(!(userInput.equalsIgnoreCase("exit"))) + toEdit.setName(userInput); + else{ + stillEditing = false; + BudgetBoss.endLoadSavedBudget(); + BudgetBoss.endNeedNewBudget(); + BudgetBoss.doneUsingBudgetBoss(); + } + } + + private void getNewStartDate(){ + Printer.print("getNewStartDate"); + String userInput = Listener.getInput(); + while(InputValidator.dateIsInvalid(userInput)) + userInput = Listener.getInput(); + if(!(userInput.equalsIgnoreCase("exit"))) + toEdit.setStartDate(userInput); + } + + private void getNewEndDate(){ + Printer.print("getNewEndDate"); + String userInput = Listener.getInput(); + while(InputValidator.dateIsInvalid(userInput)) + userInput = Listener.getInput(); + if(!(userInput.equalsIgnoreCase("exit"))) + toEdit.setEndDate(userInput); + } + + public void chooseOption(int optionChose){ + int index = (optionChose - 1); + menuOptions[index].optionMethod(); + } +} \ No newline at end of file diff --git a/src/com/visionarysoftwaresolutions/budgetboss/menu/MainMenu.java b/src/com/visionarysoftwaresolutions/budgetboss/menu/MainMenu.java new file mode 100644 index 0000000..ecd0f2e --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/menu/MainMenu.java @@ -0,0 +1,131 @@ +package com.visionarysoftwaresolutions.budgetboss.menu; + +import static org.fusesource.jansi.Ansi.ansi; +import org.fusesource.jansi.AnsiConsole; +import com.visionarysoftwaresolutions.budgetboss.app.BudgetBoss; +import com.visionarysoftwaresolutions.budgetboss.budget.*; +import com.visionarysoftwaresolutions.budgetboss.cli.*; +import com.visionarysoftwaresolutions.budgetboss.fileops.Savior; + +public class MainMenu implements MasterMenu { + + private Budget currentBudget; + private String errorMessage = ""; + + public MainMenu(Budget currentBudget){ + this.currentBudget = currentBudget; + } + + public void setErrorMessage(String newMessage){ + errorMessage = newMessage; + } + + public int getNumberOfOptions(){ + return menuOptions.length; + } + + private MasterOption[] menuOptions = new MasterOption[]{ + new MasterOption(){String optionPrintout = Printer.getPrintout("reportToConsoleOption"); + public void optionMethod() {reportToConsole();} + public String printOption(){return optionPrintout;}}, + new MasterOption(){String optionPrintout = Printer.getPrintout("reportToDiskOption"); + public void optionMethod() {reportToDisk();} + public String printOption(){return optionPrintout;}}, + new MasterOption(){String optionPrintout = Printer.getPrintout("startEditorOption"); + public void optionMethod() {startEditor();} + public String printOption(){return optionPrintout;}}, + new MasterOption(){String optionPrintout = Printer.getPrintout("saveBudgetOption"); + public void optionMethod() {saveBudget();} + public String printOption(){return optionPrintout;}}, + new MasterOption(){String optionPrintout = Printer.getPrintout("openBudgetOption"); + public void optionMethod() {openBudget();} + public String printOption(){return optionPrintout;}}, + new MasterOption(){String optionPrintout = Printer.getPrintout("createBudgetOption"); + public void optionMethod() {createBudget();} + public String printOption(){return optionPrintout;}}, + new MasterOption(){String optionPrintout = Printer.getPrintout("exitOption"); + public void optionMethod() {exitProgram();} + public String printOption(){return optionPrintout;}} + }; + + public void displayMenu(){ + AnsiConsole.out.println(ansi().eraseScreen()); + Printer.print("mainMenuHeader"); + System.out.println("Budget in use: " + currentBudget.getName() + "\n"); + Printer.printMenuOptions(menuOptions); + } + + public void getOption(MasterMenu menu){ + displayMenu(); + System.out.println(errorMessage); + String userInput = Listener.getInput(); + while (InputValidator.menuChoiceIsInvalid(userInput, menu)){ + displayMenu(); + System.out.println(errorMessage); + userInput = Listener.getInput(); + } + if(!(userInput.equalsIgnoreCase("exit"))){ + int optionChose = Integer.valueOf(userInput); + chooseOption(optionChose); + } + } + + private void reportToConsole(){ + if(!(currentBudget.getName().equals("No budget loaded"))){ + System.out.println(currentBudget.toString()); + }else { + errorMessage = Printer.getPrintout("noBudgetLoaded"); + getOption(this); + } + } + + private void reportToDisk(){ + if(!(currentBudget.getName().equals("No budget loaded"))){ + Savior.generateBudgetReport(currentBudget.getName(), currentBudget); + }else{ + errorMessage = Printer.getPrintout("noBudgetLoaded"); + getOption(this); + } + } + + private void startEditor(){ + if(!(currentBudget.getName().equals("No budget loaded"))){ + EditorMenu editor = new EditorMenu(currentBudget); + while(editor.stillEditingBudget()) + editor.getOption(editor); + }else{ + errorMessage = Printer.getPrintout("noBudgetLoaded"); + getOption(this); + } + } + + private void saveBudget(){ + if(!(currentBudget.getName().equals("No budget loaded"))){ + Savior.writeBudgetToDisk(currentBudget.getName(), currentBudget); + }else{ + errorMessage = Printer.getPrintout("noBudgetLoaded"); + getOption(this); + } + } + + private void openBudget(){ + BudgetBoss.loadSavedBudget(); + BudgetBoss.endNeedNewBudget(); + } + + private void createBudget(){ + BudgetBoss.endLoadSavedBudget(); + BudgetBoss.needNewBudget(); + } + + private void exitProgram(){ + BudgetBoss.doneUsingBudgetBoss(); + BudgetBoss.endLoadSavedBudget(); + BudgetBoss.endNeedNewBudget(); + } + + public void chooseOption(int optionChose){ + int index = (optionChose -1); + menuOptions[index].optionMethod(); + } +} \ No newline at end of file diff --git a/src/com/visionarysoftwaresolutions/budgetboss/menu/MasterMenu.java b/src/com/visionarysoftwaresolutions/budgetboss/menu/MasterMenu.java new file mode 100644 index 0000000..9052258 --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/menu/MasterMenu.java @@ -0,0 +1,15 @@ +package com.visionarysoftwaresolutions.budgetboss.menu; + +public interface MasterMenu { + + public int getNumberOfOptions(); + + public void getOption(MasterMenu menu); + + public void chooseOption(int optionChose); + + public void setErrorMessage(String newMessage); + + public void displayMenu(); + +} diff --git a/src/com/visionarysoftwaresolutions/budgetboss/menu/MasterOption.java b/src/com/visionarysoftwaresolutions/budgetboss/menu/MasterOption.java new file mode 100644 index 0000000..4aca389 --- /dev/null +++ b/src/com/visionarysoftwaresolutions/budgetboss/menu/MasterOption.java @@ -0,0 +1,8 @@ +package com.visionarysoftwaresolutions.budgetboss.menu; + +public interface MasterOption { + + public abstract void optionMethod(); + + public String printOption(); +} \ No newline at end of file diff --git a/tests/com/VSSBudgetBoss/tests/BudgetTests.java b/tests/com/VSSBudgetBoss/tests/BudgetTests.java new file mode 100644 index 0000000..608c77b --- /dev/null +++ b/tests/com/VSSBudgetBoss/tests/BudgetTests.java @@ -0,0 +1,63 @@ +package com.VSSBudgetBoss.tests; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import com.visionarysoftwaresolutions.budgetboss.budget.Budget; + +public class BudgetTests { + + @Test + public void createABudget() { + //Given: A Budget needs to be created + //When: User supplied information is provided + String uIBudgetName = "testBudget"; + Budget testBudget = new Budget(uIBudgetName); + //Then: A Budget is created with the supplied information + assertTrue(testBudget.getName().equals(uIBudgetName)); + } + + @Test + public void budgetHasDates(){ + //Given: A Budget needs to be created + //When: The budget is generated + //Then: It will have start and end dates + Budget testBudget = new Budget("testBudget"); + assertNotNull(testBudget.getStartDate()); + assertNotNull(testBudget.getEndDate()); + } + + @Test + public void setBudgetDates(){ + //Given: A Budget needs to be created + //When: The Budget is generated + Budget testBudget = new Budget("testBudget"); + //And: The user wants to modify the start/end dates + //Then: The dates can be accessed and manipulated + testBudget.setStartDate("11/01/2012"); + testBudget.setEndDate("11/15/2012"); + assertTrue(testBudget.getStartDate().equals("11/01/2012")); + assertTrue(testBudget.getEndDate().equals("11/15/2012")); + } + + @Test public void setBudgetName(){ + //Given: A Budget needs to be created + //When: The budget is generated + Budget testBudget = new Budget("testBudget"); + //And: The user wants to modify the name + //Then: The budget name can be accessed and manipulated + testBudget.setName("dontNeedNoTestBudget"); + assertTrue(testBudget.getName().equals("dontNeedNoTestBudget")); + } + + @Test + public void testConvertDates(){ + String userInput = "12/28/2012"; + String delimiter = "[/]"; + String[] dateInput = userInput.split(delimiter); + String convertedDate = dateInput[2] + "-" + dateInput[0] + "-" + dateInput[1]; + System.out.println(convertedDate); + } + +} diff --git a/tests/com/VSSBudgetBoss/tests/BudgetToJSONTests.java b/tests/com/VSSBudgetBoss/tests/BudgetToJSONTests.java new file mode 100644 index 0000000..2000196 --- /dev/null +++ b/tests/com/VSSBudgetBoss/tests/BudgetToJSONTests.java @@ -0,0 +1,19 @@ +package com.VSSBudgetBoss.tests; + +import org.junit.Test; +import com.visionarysoftwaresolutions.budgetboss.budget.Budget; +import com.visionarysoftwaresolutions.budgetboss.budginator.BudgetToJSON; + +public class BudgetToJSONTests { + + @Test + public void testConversion() { + //Given: A budget created by BudgetBoss + Budget testBudget = new Budget("JSONBudget"); + //When: The budget needs to be converted to JSON format for wider use + //Then: The budget will convert to JSON + //See console for output + System.out.print(BudgetToJSON.convertToBudginator(testBudget)); + } + +} diff --git a/tests/com/VSSBudgetBoss/tests/ExpenseCategoryTests.java b/tests/com/VSSBudgetBoss/tests/ExpenseCategoryTests.java new file mode 100644 index 0000000..d211c17 --- /dev/null +++ b/tests/com/VSSBudgetBoss/tests/ExpenseCategoryTests.java @@ -0,0 +1,33 @@ +package com.VSSBudgetBoss.tests; + +import static org.junit.Assert.*; + +import java.math.BigDecimal; + +import org.joda.time.LocalDate; +import org.junit.Test; + +import com.visionarysoftwaresolutions.budgetboss.budget.Expense; +import com.visionarysoftwaresolutions.budgetboss.budget.ExpenseCategory; + +public class ExpenseCategoryTests { + + @Test + public void testGetSpent() { + //Given an ExpenseCategory + ExpenseCategory fhExpenses = new ExpenseCategory("Food/Household"); + //With some expenses + LocalDate today = new LocalDate(2012, 11, 15); + Expense firstExpense = new Expense(new BigDecimal("13.55"), today, "Fry's Food"); + Expense secondExpense = new Expense(new BigDecimal("25.38"), today, "Wal-Mart"); + Expense thirdExpense = new Expense(new BigDecimal("19.93"), today, "Fresh and Easy"); + fhExpenses.addExpense(firstExpense); + fhExpenses.addExpense(secondExpense); + fhExpenses.addExpense(thirdExpense); + //When a user wants to know the total spent in that category + BigDecimal spent = fhExpenses.getSpent(); + //Then the correct total will be reached + assertTrue(spent.equals(new BigDecimal("58.86"))); + } + +} diff --git a/tests/com/VSSBudgetBoss/tests/ExpenseTests.java b/tests/com/VSSBudgetBoss/tests/ExpenseTests.java new file mode 100644 index 0000000..e7527e4 --- /dev/null +++ b/tests/com/VSSBudgetBoss/tests/ExpenseTests.java @@ -0,0 +1,14 @@ +package com.VSSBudgetBoss.tests; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class ExpenseTests { + + @Test + public void test() { + fail("Not yet implemented"); + } + +} diff --git a/tests/com/VSSBudgetBoss/tests/InputValidatorTests.java b/tests/com/VSSBudgetBoss/tests/InputValidatorTests.java new file mode 100644 index 0000000..20e7442 --- /dev/null +++ b/tests/com/VSSBudgetBoss/tests/InputValidatorTests.java @@ -0,0 +1,40 @@ +package com.VSSBudgetBoss.tests; + +import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; + +import com.visionarysoftwaresolutions.budgetboss.cli.InputValidator; + +public class InputValidatorTests { + + InputValidator validator; + + @Before + public void setup(){ + //Given: An input is required from a user + validator = new InputValidator(); + } + + @Test + public void testNonIntegerRejection(){ + //And: The input must be an integer (for selecting menu options numerically) + //When: The user inputs something + //Then: The input will only validate if it is an integer + assertFalse(validator.inputNotAnInteger("8")); + assertFalse(validator.inputNotAnInteger("1")); + assertTrue(validator.inputNotAnInteger("toCheck")); + } + + @Test + public void testValidatePathLinux(){ + //And: A valid directory path is needed + //When: The user inputs something + //Then: The input will only validate if it is a valid path, ending in "/" + String currentUser = System.getProperty("user.name"); + assertTrue(validator.pathIsInvalid("/home/" + currentUser + "/Documents")); + assertFalse(validator.pathIsInvalid("/home/" + currentUser + "/Documents/")); + assertTrue(validator.pathIsInvalid("/home/" + currentUser + "/notevenarealdirectory/")); + } +} + \ No newline at end of file