Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Meeting statistics (single and multiple meeting counts) #125

48 changes: 48 additions & 0 deletions src/main/java/seedu/address/commons/MonthAndYear.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package seedu.address.commons;

import static java.util.Objects.requireNonNull;

import java.time.Month;
import java.time.Year;
import java.util.Objects;

/**
* Store a month and year.
*/
public class MonthAndYear {

private Month month;
private Year year;

/**
* Creates a MonthAndYear Object from the given {@code month} and {@code year}
*/
public MonthAndYear(Month month, Year year) {
requireNonNull(month);
requireNonNull(year);

this.month = month;
this.year = year;
}

public Month getMonth() {
return month;
}

public Year getYear() {
return year;
}

@Override
public int hashCode() {
return Objects.hash(this.month, this.year);
}

@Override
public boolean equals(Object other) {
return other == this
|| (other instanceof MonthAndYear // instanceof handles nulls
&& this.month.equals(((MonthAndYear) other).month)
&& this.year.equals(((MonthAndYear) other).year));
}
}
45 changes: 45 additions & 0 deletions src/main/java/seedu/address/commons/MonthlyCountData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package seedu.address.commons;

import static java.util.Objects.requireNonNull;

/**
* Store a data object for monthly count data statistic.
*/
public class MonthlyCountData {

private final MonthAndYear monthAndYear;

private final int count;

/**
* Creates MonthlyCountData Object from the given {@code monthAndYear} and {@code count}.
*/
public MonthlyCountData(MonthAndYear monthAndYear, int count) {
requireNonNull(monthAndYear);

this.monthAndYear = monthAndYear;
this.count = count;
}

/**
* Returns the String representation of MonthAndYear.
*/
public String getMonthAndYearAsStr() {
return String.format("%s %s", monthAndYear.getMonth(), monthAndYear.getYear());
}

/**
* Returns the number of counts related to MonthAndYear object.
*/
public int getCount() {
return count;
}

@Override
public boolean equals(Object other) {
return other == this
|| (other instanceof MonthlyCountData // instanceof handles nulls
&& this.monthAndYear.equals(((MonthlyCountData) other).monthAndYear)
&& this.count == ((MonthlyCountData) other).count);
}
}
126 changes: 126 additions & 0 deletions src/main/java/seedu/address/commons/MonthlyList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package seedu.address.commons;

import java.time.Month;
import java.time.Year;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Stores a list of items of type T based on the key of < month, year >
*/
public class MonthlyList<T> {

private final Map<MonthAndYear, List<T>> monthlyList;

public MonthlyList() {
this.monthlyList = new HashMap<>();
}

/**
* Adds {@code item} of type T to an item list
* based on the key of {@code month} and {@code year}.
*
* @param month a valid month number
* @param year a valid year number
* @param item item of type T
*/
public void addItem(Month month, Year year, T item) {
MonthAndYear key = new MonthAndYear(month, year);
if (this.monthlyList.containsKey(key)) {
this.monthlyList.get(key).add(item);
} else {
this.monthlyList.put(key, new ArrayList<>(Collections.singleton(item)));
}
}

/**
* Removes {@code item} of type T from an item list
* based on the key of {@code month} and {@code year} if exists.
*
* @param month a valid month number
* @param year a valid year number
* @param item item of type T
*/
public void removeItem(Month month, Year year, T item) {
MonthAndYear key = new MonthAndYear(month, year);
if (this.monthlyList.containsKey(key)) {
if (this.monthlyList.get(key).size() == 1) {
this.monthlyList.remove(key);
} else {
this.monthlyList.get(key).remove(item);
}
}
}

/**
* Gets the number of items in an item list
* based on the key of {@code month} and {@code year}.
* If the key of {@code month} and {@code year} does not exist, the number is 0.
*
* @param month a valid month number
* @param year a valid year number
* @return the number of items in that month and year
*/
public int getItemCount(Month month, Year year) {
MonthAndYear key = new MonthAndYear(month, year);
if (this.monthlyList.containsKey(key)) {
return this.monthlyList.get(key).size();
}
return 0;
}

/**
* Removes all entries in the monthlyList.
*/
public void clear() {
this.monthlyList.clear();
}

/**
* Gets the item counts in the item list for {@code month}, {@code year}
* and the previous @{numberOfMonths} - 1 months.
* @param month valid month
* @param year valid year
* @param numberOfMonths non-negative integer
* @return list of MonthlyCountData objects, ordered by non-decreasing year and month
*/
public List<MonthlyCountData> getMultipleMonthCount(Month month, Year year, int numberOfMonths) {
List<MonthlyCountData> result = new ArrayList<>();

MonthAndYear currentMonthAndYear = new MonthAndYear(month, year);
result.add(new MonthlyCountData(currentMonthAndYear,
this.monthlyList.getOrDefault(currentMonthAndYear, Collections.emptyList()).size()));

for (int i = 1; i < numberOfMonths; i++) {
MonthAndYear previousMonthAndYear = getPreviousMonthAndYear(month, year);
result.add(new MonthlyCountData(previousMonthAndYear,
this.monthlyList.getOrDefault(previousMonthAndYear, Collections.emptyList()).size()));
month = previousMonthAndYear.getMonth();
year = previousMonthAndYear.getYear();
}

Collections.reverse(result);
return result;
}

/**
* Gets the month and year for
* one month before {@code month} and {@code year}.
* @param month valid month
* @param year valid year
* @return MonthAndYear object that is one month before the {@code month} and {@code year}
*/
private MonthAndYear getPreviousMonthAndYear(Month month, Year year) {
Year yearResult = year;
int monthResult = month.getValue() - 1;
if (monthResult <= 0) {
monthResult += 12;
yearResult = year.minusYears(1);
}
Month previousMonth = Month.of(monthResult);
return new MonthAndYear(previousMonth, yearResult);
}
}
5 changes: 5 additions & 0 deletions src/main/java/seedu/address/commons/core/Messages.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ public class Messages {
public static final String MESSAGE_INVALID_TAG_DISPLAYED_INDEX = "The tag index provided is invalid";
public static final String MESSAGE_INVALID_MEETING_DISPLAYED_INDEX = "The meeting index provided is invalid";
public static final String MESSAGE_INVALID_SALE_DISPLAYED_INDEX = "The sale index provided is invalid";
public static final String MESSAGE_INVALID_MONTH =
"Month must be an integer value in between 1 and 12 inclusive.";
public static final String MESSAGE_INVALID_YEAR = "Year must be an non negative integer.";
public static final String MESSAGE_INVALID_NUMBER_OF_MONTHS =
"The number of months must be an integer value in between 2 and 6 inclusive.";
public static final String MESSAGE_SALE_TAGS_NOT_FOUND = "The provided sales tag(s) do not exist yet";
public static final String MESSAGE_CONTACT_TAGS_NOT_FOUND = "The provided contact tag(s) do not exist yet";

Expand Down
42 changes: 39 additions & 3 deletions src/main/java/seedu/address/logic/commands/CommandResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

import static java.util.Objects.requireNonNull;

import java.util.List;
import java.util.Objects;

import seedu.address.commons.MonthlyCountData;

/**
* Represents the result of a command execution.
*/
Expand All @@ -20,14 +23,35 @@ public class CommandResult {
/** The chat box should be cleared. */
private final boolean clear;

private final List<MonthlyCountData> statisticResult;

/**
* Constructs a {@code CommandResult} with the specified fields.
* Constructs a {@code CommandResult} with the specified {@code feedbackToUser},
* {@code showHelp}, {@code exit}, {@code clear}
* and other fields set to their default value.
*/
public CommandResult(String feedbackToUser, boolean showHelp, boolean exit, boolean clear) {
this(feedbackToUser, showHelp, exit, clear, null);
}

/**
* Constructs a {@code CommandResult} with the specified fields.
*/
public CommandResult(String feedbackToUser, boolean showHelp,
boolean exit, boolean clear, List<MonthlyCountData> statisticResult) {
this.feedbackToUser = requireNonNull(feedbackToUser);
this.showHelp = showHelp;
this.exit = exit;
this.clear = clear;
this.statisticResult = statisticResult;
}

/**
* Constructs a {@code CommandResult} with the specified {@code statisticResult},
* and other fields set to their default value.
*/
public CommandResult(String feedbackToUser, List<MonthlyCountData> statisticResult) {
this(feedbackToUser, false, false, false, statisticResult);
}

/**
Expand All @@ -54,6 +78,14 @@ public boolean isClear() {
return clear;
}

public boolean hasStatisticsResult() {
return !Objects.isNull(this.statisticResult);
}

public List<MonthlyCountData> getStatisticResult() {
return statisticResult;
}

@Override
public boolean equals(Object other) {
if (other == this) {
Expand All @@ -69,12 +101,16 @@ public boolean equals(Object other) {
return feedbackToUser.equals(otherCommandResult.feedbackToUser)
&& showHelp == otherCommandResult.showHelp
&& clear == otherCommandResult.clear
&& exit == otherCommandResult.exit;
&& exit == otherCommandResult.exit
&& ((Objects.isNull(statisticResult)
&& Objects.isNull(otherCommandResult.statisticResult))
|| (!Objects.isNull(statisticResult)
&& statisticResult.equals(otherCommandResult.statisticResult)));
}

@Override
public int hashCode() {
return Objects.hash(feedbackToUser, showHelp, exit, clear);
return Objects.hash(feedbackToUser, showHelp, exit, clear, statisticResult);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package seedu.address.logic.commands.meeting;

import static java.util.Objects.requireNonNull;

import java.time.LocalDate;
import java.time.Month;
import java.time.Year;
import java.time.ZoneId;
import java.util.List;

import seedu.address.commons.MonthlyCountData;
import seedu.address.logic.commands.CommandResult;
import seedu.address.model.Model;

/**
* Gets multiple monthly meeting counts
*/
public class MultipleMeetingStatsCommand extends StatsCommand {

public static final String MESSAGE_SUCCESS = "Opened a new window!";

private final int numberOfMonths;

/**
* Creates a MultipleMeetingStatsCommand with the given {@code numberOfMonths}.
*/
public MultipleMeetingStatsCommand(int numberOfMonths) {
this.numberOfMonths = numberOfMonths;
}

/**
* Gets multiple monthly meeting counts for months between
* the current month and the previous numberOfMonths - 1 months inclusive.
*
* @param model {@code Model} which the command should operate on
* @return CommandResult object storing the success message
* and the multiple monthly count result
*/
@Override
public CommandResult execute(Model model) {
requireNonNull(model);

Month currentMonth = LocalDate.now(ZoneId.of("Asia/Singapore")).getMonth();
Year currentYear = Year.now();

List<MonthlyCountData> result = model
.getMultipleMonthMeetingsCount(currentMonth, currentYear, numberOfMonths);

return new CommandResult(MESSAGE_SUCCESS, result);
}

@Override
public boolean equals(Object other) {
return other == this
|| (other instanceof MultipleMeetingStatsCommand
&& numberOfMonths == (((MultipleMeetingStatsCommand) other).numberOfMonths));
}
}
Loading