diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/OODexplained.txt b/docs/OODexplained.txt new file mode 100644 index 0000000..5357500 --- /dev/null +++ b/docs/OODexplained.txt @@ -0,0 +1 @@ +use case 1: diff --git a/docs/crc.txt b/docs/crc.txt new file mode 100644 index 0000000..0d3089e --- /dev/null +++ b/docs/crc.txt @@ -0,0 +1,28 @@ +class: PackageDeliveriesTracker +responsability: starting point of the program. Handles the displaying and modifying opperations of different kinds of packages. Load and store packages to json. +collaborators: textMenu, PackageFactory + +class: textMenu +responsability: Displays operations to be performed for packages. Take user input for the operations and returns the status. +collaborators: PackageDeliveriesTracker, PackageInfo, + +class: PackageInfo +responsability: define the attributes of packages. Allow for accessing and motifying fields of package info. +collaborators: BookPackage, PerishablePackage, ElectronicPackage, PackageFactory + +class: PackageFactory +responsability: initialize and return an instance of one of the package types. +collaborators: BookPackage, PerishablePackage, ElectronicPackage + +class: BookPackage +responsability: Sub class of PackageInfo. Defines the field author name and allows modification. +collaborators: PackageFactory, PackageDeliveriesTracker + +class: PerishablePackage +responsability: Sub class of PackageInfo. Defines the field expiry date and allows modification. +collaborators: PackageFactory, PackageDeliveriesTracker + +class: ElectronicPackage +responsability: Sub class of PackageInfo. Defines the field enviremental handling fee and allows modification. +collaborators: PackageFactory, PackageDeliveriesTracker + diff --git a/docs/uml.txt b/docs/uml.txt new file mode 100644 index 0000000..f004819 --- /dev/null +++ b/docs/uml.txt @@ -0,0 +1,30 @@ +PackageDeliveriesTracker +fileName: String, packageList: ArrayList, rtaf: RuntimeTypeAdapterFactory, gson: GsonBuilder +save():void, load(): void, main(String[] args): void + +PackageInfo +name: String, notes: String, price: double, weight, double, deliver: boolean, expectedDate: LocalDateTime +compareTo(PackageInfo p): int, toString(): String + BookPackage + authorName: String + + PerishablePackage + expiryDate:LocalDateTime + + ElectronicPackage + handlingFee: double + + +TextMenu +title: String, options: String[] +display(): void, list(ArrayList packageList): void, add(ArrayList packageList): void, remove(ArrayList packageList): void, sortList(ArrayList packageList, boolean due): ArrayList, overDueList(ArrayList packageList): void, getUndelivered(List packageList): ArrayList +upcomingList(ArrayList PackageList): void, markDelivered(ArrayList PackageList): void + +PackageFactory +PackageType: enum +getInstance(packageType type, String name, String Notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, string author, LocalDateTime expiryDate, double handlingFee): PackageInfo + + +1. PackageInfo and subclass are created from PackageFactory +2. PackageDeliveriesTracker creates objects of PackageInfo +3. PackageDeliveriesTracker is dependent on TextMenu diff --git a/docs/use cases.txt b/docs/use cases.txt new file mode 100644 index 0000000..1edc724 --- /dev/null +++ b/docs/use cases.txt @@ -0,0 +1,143 @@ +* list packages +* To list packages, user enters 1 and presses enter. +* A message is shown if no packages are in the package list +* Otherwise the packages are displayed with each field associated on a new line. +* Packages are ordered to display oldest delivery date first. +* a number is assigned to each packages. +################### +# Package Tracker # +################### +Today is: 2022-06-27 +1: List of all packages +2: Add a package +3: remove a package +4: list overdue packages +5: List upcoming packages +6: mark package as delivered +7: exit +choose an option between 1 and 7: + +$1 + +No packages to show + +* Back to the main menu + +################### +# Package Tracker # +################### +Today is: 2022-06-27 +1: List of all packages +2: Add a package +3: remove a package +4: list overdue packages +5: List upcoming packages +6: mark package as delivered +7: exit + +* If all inputs are validated, the package is added to the list. + +choose an option between 1 and 7: +$1 +enter a valid package name: +$b1 +notes: +$$ my note +enter date as yyyy-mm-dd hh:mm: +$2022-09-01 11:11 +enter price: +$15 +enter weight: +$15 +enter author +$me +b1 has been added to the list! + +################### +# Package Tracker # +################### +Today is: 2022-06-27 +1: List of all packages +2: Add a package +3: remove a package +4: list overdue packages +5: List upcoming packages +6: mark package as delivered +7: exit + +* When user lists packages again, the newly added package is shown in detail. + +choose an option between 1 and 7: +$1 +Package #1 +Name: b1 +Notes: my note +Price: 15.0 +Weight: 15.0 +Expected Delivery Date: 2022-09-01 11:11 +Delivered? no +65 days remaining +Author: me + +################### +# Package Tracker # +################### +Today is: 2022-06-27 +1: List of all packages +2: Add a package +3: remove a package +4: list overdue packages +5: List upcoming packages +6: mark package as delivered +7: exit +choose an option between 1 and 7: + +* To remove a package, user enters 3 and presses enter. +* The packages are listed with an ID. + +3 +Package #1 +Name: b1 +Notes: my note +Price: 15.0 +Weight: 15.0 +Expected Delivery Date: 2022-09-01 11:11 +Delivered? no +65 days remaining +Author: me + +* user enters 0 to return to the main menu. + +enter item number you want to remove (0 to cancel): +0 +################### +# Package Tracker # +################### +Today is: 2022-06-27 +1: List of all packages +2: Add a package +3: remove a package +4: list overdue packages +5: List upcoming packages +6: mark package as delivered +7: exit +choose an option between 1 and 7: +$3 +Package #1 +Name: b1 +Notes: my note +Price: 15.0 +Weight: 15.0 +Expected Delivery Date: 2022-09-01 11:11 +Delivered? no +65 days remaining +Author: me + +* user enters corresponding ID to remove the package. + +enter item number you want to remove (0 to cancel): +$1 + +* The package is deleted from the list. + +b1 has been removed from the list. diff --git a/list.json b/list.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/list.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/Main.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/Main.class deleted file mode 100644 index bcebd17..0000000 Binary files a/out/production/cmpt213.assignment1.packagedeliveriestracker/Main.class and /dev/null differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/PackageInfo.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/PackageInfo.class deleted file mode 100644 index 840393d..0000000 Binary files a/out/production/cmpt213.assignment1.packagedeliveriestracker/PackageInfo.class and /dev/null differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/TextMenu.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/TextMenu.class deleted file mode 100644 index ca05863..0000000 Binary files a/out/production/cmpt213.assignment1.packagedeliveriestracker/TextMenu.class and /dev/null differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/gson/extras/RuntimeTypeAdapterFactory$1.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/gson/extras/RuntimeTypeAdapterFactory$1.class new file mode 100644 index 0000000..6b1a258 Binary files /dev/null and b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/gson/extras/RuntimeTypeAdapterFactory$1.class differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/gson/extras/RuntimeTypeAdapterFactory.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/gson/extras/RuntimeTypeAdapterFactory.class new file mode 100644 index 0000000..79a3c19 Binary files /dev/null and b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/gson/extras/RuntimeTypeAdapterFactory.class differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/BookPackage.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/BookPackage.class new file mode 100644 index 0000000..81ec4f7 Binary files /dev/null and b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/BookPackage.class differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/ElectronicPackage.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/ElectronicPackage.class new file mode 100644 index 0000000..b53e6c0 Binary files /dev/null and b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/ElectronicPackage.class differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory$PackageType$1.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory$PackageType$1.class new file mode 100644 index 0000000..d429fd4 Binary files /dev/null and b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory$PackageType$1.class differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory$PackageType$2.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory$PackageType$2.class new file mode 100644 index 0000000..69259d1 Binary files /dev/null and b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory$PackageType$2.class differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory$PackageType$3.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory$PackageType$3.class new file mode 100644 index 0000000..6f270ba Binary files /dev/null and b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory$PackageType$3.class differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory$PackageType.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory$PackageType.class new file mode 100644 index 0000000..3205581 Binary files /dev/null and b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory$PackageType.class differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory.class new file mode 100644 index 0000000..c54cfb7 Binary files /dev/null and b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory.class differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageInfo.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageInfo.class new file mode 100644 index 0000000..a20bdd8 Binary files /dev/null and b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PackageInfo.class differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PerishablePackage.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PerishablePackage.class new file mode 100644 index 0000000..b0e8aa5 Binary files /dev/null and b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/model/PerishablePackage.class differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/Main$1.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/textui/PackageDeliveriesTracker$1.class similarity index 55% rename from out/production/cmpt213.assignment1.packagedeliveriestracker/Main$1.class rename to out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/textui/PackageDeliveriesTracker$1.class index 0ffb20c..034a9ba 100644 Binary files a/out/production/cmpt213.assignment1.packagedeliveriestracker/Main$1.class and b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/textui/PackageDeliveriesTracker$1.class differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/textui/PackageDeliveriesTracker$2.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/textui/PackageDeliveriesTracker$2.class new file mode 100644 index 0000000..a18a50f Binary files /dev/null and b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/textui/PackageDeliveriesTracker$2.class differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/textui/PackageDeliveriesTracker.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/textui/PackageDeliveriesTracker.class new file mode 100644 index 0000000..a167860 Binary files /dev/null and b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/textui/PackageDeliveriesTracker.class differ diff --git a/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/textui/TextMenu.class b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/textui/TextMenu.class new file mode 100644 index 0000000..5cd41d7 Binary files /dev/null and b/out/production/cmpt213.assignment1.packagedeliveriestracker/cmpt213/assignment2/packagedeliveriestracker/textui/TextMenu.class differ diff --git a/src/Main.java b/src/Main.java deleted file mode 100644 index 8bed7a7..0000000 --- a/src/Main.java +++ /dev/null @@ -1,97 +0,0 @@ -import com.google.gson.*; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import java.io.*; -import java.time.LocalDateTime; -import java.time.chrono.ChronoLocalDate; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; -import java.util.Scanner; - -public class Main { -private static final String fileName = "list.json"; - private static ArrayList packageList=new ArrayList<>(); -private static void save(){ - Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, - new TypeAdapter() { - @Override - public void write(JsonWriter jsonWriter, - LocalDateTime localDateTime) throws IOException { - jsonWriter.value(localDateTime.toString()); - } - @Override - public LocalDateTime read(JsonReader jsonReader) throws IOException { - return LocalDateTime.parse(jsonReader.nextString()); - } - }).create(); - try{ - Writer w = new FileWriter(fileName); - gson.toJson(packageList, w); - w.flush(); - w.close(); - } - catch (IOException e){ - e.printStackTrace(); - } -} - -private static void load(){ - File file = new File(fileName); -try{ - JsonElement element = JsonParser.parseReader(new FileReader(fileName)); - JsonArray array = element.getAsJsonArray(); - for (int i = 0; i < array.size(); i++){ - JsonObject pObj = array.get(i).getAsJsonObject(); - DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm"); - packageList.add(new PackageInfo(pObj.get("name").getAsString(), - pObj.get("note").getAsString(), - pObj.get("price").getAsDouble(), - pObj.get("weight").getAsDouble(), - pObj.get("delivered").getAsBoolean(), - LocalDateTime.parse(pObj.get("expectedDate").getAsString())) - ); - } - System.out.println("packages loaded"); -} -catch (FileNotFoundException e){ -System.out.println("no packages to load"); - } -} - - public static void main(String[] args) { -TextMenu menu=new TextMenu(); -load(); -do{ - menu.display(); - System.out.println("choose an option between 1 and 7:"); - Scanner scan = new Scanner(System.in); - int option=Integer.parseInt(scan.nextLine()); - if (option > 7 || option < 1){ - System.out.println("invalid input"); - } - else if(option == 7){ - save(); - System.out.print("packages saved"); - break; - } - else{ - switch(option){ - case 1: menu.list(packageList); - break; - case 2: menu.add(packageList); - break; - case 3: menu.remove(packageList); - break; - case 4: menu.overDueList(packageList); - break; - case 5: menu.upcomingList(packageList); - break; - case 6: menu.markDelivered(packageList); - } - } -} -while (true); - } -} - diff --git a/src/PackageFactory.java b/src/PackageFactory.java deleted file mode 100644 index 595bcb5..0000000 --- a/src/PackageFactory.java +++ /dev/null @@ -1,24 +0,0 @@ -import java.time.LocalDateTime; - -public enum PackageFactory { - Book { - public PackageInfo getInstance(String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author) { - return new BookPackage(name, notes, price, weight, delivered, expectedDate, author); - } - } - - Perishable { - public PackageInfo getInstance (String name, String notes,double price, double weight, - boolean delivered, LocalDateTime expectedDate, LocalDateTime expiryDate){ - return new PerishablePackage(name, notes, price, weight, delivered, expectedDate, expiryDate); - } - } - - Electronic{ - public PackageInfo getInstance(String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, double handlingFee){ - return new ElectronicPackage(name, notes, price, weight, delivered, expectedDate, handlingFee); - } - } -} - //public static PackageInfo getInstance(PackageType type, String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, @Nullable String author, @Nullable LocalDateTime expiryDate, @Nullable double handlingFee){ - //} diff --git a/src/PackageInfo.java b/src/PackageInfo.java deleted file mode 100644 index 6b46b5e..0000000 --- a/src/PackageInfo.java +++ /dev/null @@ -1,57 +0,0 @@ -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.time.Duration; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.time.temporal.ChronoUnit; -import static java.lang.Math.abs; - -public class PackageInfo implements Comparable{ -private String name; - private String note; - private double price; - private double weight; - private boolean delivered; - private LocalDateTime expectedDate; - - public PackageInfo(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate) { - this.name =name; - this.note = note; - this.price = price; - this.weight =weight; - this.delivered =delivered; - this.expectedDate = expectedDate; - } - - public String getName() { - return name; - } - - public boolean getDelivered() { - return delivered; - } - - public LocalDateTime getExpectedDate() { - return expectedDate; - } - - public void setDelivered(boolean delivered) { - this.delivered = delivered; - } - - @Override - public int compareTo(PackageInfo p){ - return this.expectedDate.compareTo(p.getExpectedDate()); - } - - @Override - public String toString() { - DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm"); - LocalDateTime today = LocalDateTime.now(); - today.format(format); - long diff = ChronoUnit.DAYS.between(today, expectedDate); - String isDelivered = delivered ? "yes" : "no"; - return "Name: " + name + "\n" + "Notes: " + note + "\n" + "Price: " + price + "\n" + "Weight: " + weight + "\n" + "Expected Delivery Date: " + expectedDate.toString() + "\n" + "Delivered? " + isDelivered + "\n" + ((diff > 0 && !delivered) ? diff + " days remaining" : abs(diff) + " days overdue"); - } -} diff --git a/src/PerishablePackage.java b/src/PerishablePackage.java deleted file mode 100644 index a589e49..0000000 --- a/src/PerishablePackage.java +++ /dev/null @@ -1,15 +0,0 @@ -import java.time.LocalDateTime; - -public class PerishablePackage extends PackageInfo{ - LocalDateTime expiryDate; - - public PerishablePackage(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate, LocalDateTime expiryDate) { - super(name, note, price, weight, delivered, expectedDate); - this.expiryDate = expiryDate; - } - - @Override - public String toString() { - return super.toString()+"expiryDate=" + expiryDate; - } -} diff --git a/src/TextMenu.java b/src/TextMenu.java deleted file mode 100644 index 6b74bb3..0000000 --- a/src/TextMenu.java +++ /dev/null @@ -1,181 +0,0 @@ -import javax.swing.text.html.HTMLDocument; -import java.net.SocketOption; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.time.DateTimeException; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; -import java.time.format.SignStyle; -import java.util.*; - -public class TextMenu { -private final String title = "title"; -private final String[] options = new String []{ - "List of all packages", - "Add a package", -"remove a package", -"list overdue packages", -"List upcoming packages", -"mark package as delivered", -"exit"}; - -public void display(){ - int tag = title.length(); - for (int i=0; i<= tag+3; i++){ - System.out.print("#"); - } - System.out.println("\n# " + title + " #"); - for (int i=0; i<= tag+3; i++){ - System.out.print("#"); - } - DateFormat today = new SimpleDateFormat("yyy-MM-dd"); - Calendar cal=Calendar.getInstance(); - System.out.println("\nToday is: " + today.format(cal.getTime())); -for (int i = 0; i < options.length; i++){ - System.out.println((i+1) + ": " + options[i]); -} -} - -public void list(ArrayList packageList){ -if (packageList.size() == 0){ - System.out.println("No packages to show"); -} -else{ - for (int i=0; i < packageList.size(); i++){ - System.out.println("Package #" + (i+1)); - System.out.println(packageList.get(i).toString()); - } -} -} - - public void add(ArrayList packageList){ - Scanner scan = new Scanner(System.in); - String pName; - do { - System.out.println("enter a valid package name:"); - pName = scan.nextLine(); - } - while (pName.length()==0); - System.out.println("notes:"); - String pNotes = scan.nextLine(); - boolean checkDate = false; - DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm"); - LocalDateTime pDate=LocalDateTime.now(); - while (checkDate == false){ - try { - System.out.println("enter date as yyyy-mm-dd hh:mm:"); - pDate = LocalDateTime.parse(scan.nextLine(), format); - checkDate = true; - } - catch (DateTimeParseException e) { - System.out.println("invalid date format"); - } - } - double pPrice; - do { - System.out.println("enter price:"); - pPrice = scan.nextDouble(); - } - while (pPrice < 0); - double pWeight; - do { - System.out.println("enter weight:"); - pWeight = scan.nextDouble(); - } - while (pWeight <= 0); - - packageList.add(new PackageInfo(pName, pNotes, pPrice, pWeight, false, pDate)); - System.out.println(pName + " has been added to the list!"); - } - - public void remove(ArrayList packageList) { - this.list(packageList); - if (packageList.size() == 0){ - return; - } - Scanner scan = new Scanner(System.in); - int n; - do { - System.out.println("enter item number you want to remove (0 to cancel):"); - n = scan.nextInt(); - } - while (n < 0 || n > packageList.size()); - if (n > 0){ - System.out.println(packageList.get(n-1).getName() + " has been removed from the list."); - packageList.remove(n-1); - } - } - - //due=true returns overdue packages, else upcoming packages - public ArrayList sortList(ArrayList pList, boolean due){ - ArrayList sortedList = new ArrayList<>(); - LocalDateTime today = LocalDateTime.now(); - DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm"); - today.format(format); - for (int i = 0; i < pList.size(); i++) { - PackageInfo p = pList.get(i); - if (!p.getDelivered()) { - if (due && today.isAfter(p.getExpectedDate())) { - sortedList.add(p); - } - else if (!due && today.isBefore(p.getExpectedDate())){ - sortedList.add(p); - } - } - } -Collections.sort(sortedList); - return sortedList; - } - - public void overDueList(ArrayList packageList){ -ArrayList overdue = sortList(packageList, true); -if (overdue.size() == 0){ - System.out.println("no overdue packages to show"); - return; -} -this.list(overdue); - } - - public void upcomingList(ArrayList packageList){ - ArrayList upcoming = sortList(packageList, false); - if (upcoming.size() == 0){ - System.out.println("no upcoming packages to show"); - return; - } - this.list(upcoming); - } - - public ArrayList getUndelivered(List packageList){ - ArrayList undelivered = new ArrayList<>(); - for (int i = 0; i < packageList.size(); i++){ - if (packageList.get(i).getDelivered() == false){ - undelivered.add(packageList.get(i)); - } - } -return undelivered; - } - - public void markDelivered(ArrayList packageList){ - ArrayList undelivered=getUndelivered(packageList); - if (undelivered.size() == 0){ - System.out.println("No undelivered packages to show"); - return; - } - this.list(undelivered); - Scanner scan = new Scanner(System.in); - int n; - do { - System.out.println("enter item number you want to mark delivered (0 to cancel):"); - n = scan.nextInt(); - } - while (n < 0 || n > undelivered.size()); - if (n > 0){ - PackageInfo p = undelivered.get(n-1); - packageList.get(packageList.indexOf(p)).setDelivered(true); - System.out.println(p.getName() + " has been delivered."); - } - } - - -} diff --git a/src/cmpt213/assignment2/packagedeliveriestracker/gson/extras/RuntimeTypeAdapterFactory.java b/src/cmpt213/assignment2/packagedeliveriestracker/gson/extras/RuntimeTypeAdapterFactory.java new file mode 100644 index 0000000..8a4807b --- /dev/null +++ b/src/cmpt213/assignment2/packagedeliveriestracker/gson/extras/RuntimeTypeAdapterFactory.java @@ -0,0 +1,256 @@ +package cmpt213.assignment2.packagedeliveriestracker.gson.extras; + +import com.google.gson.*; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Adapts values whose runtime type may differ from their declaration type. This + * is necessary when a field's type is not the same type that GSON should create + * when deserializing that field. For example, consider these types: + *
   {@code
+ *   abstract class Shape {
+ *     int x;
+ *     int y;
+ *   }
+ *   class Circle extends Shape {
+ *     int radius;
+ *   }
+ *   class Rectangle extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Diamond extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Drawing {
+ *     Shape bottomShape;
+ *     Shape topShape;
+ *   }
+ * }
+ *

Without additional type information, the serialized JSON is ambiguous. Is + * the bottom shape in this drawing a rectangle or a diamond?

   {@code
+ *   {
+ *     "bottomShape": {
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * This class addresses this problem by adding type information to the + * serialized JSON and honoring that type information when the JSON is + * deserialized:
   {@code
+ *   {
+ *     "bottomShape": {
+ *       "type": "Diamond",
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "type": "Circle",
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * Both the type field name ({@code "type"}) and the type labels ({@code + * "Rectangle"}) are configurable. + * + *

Registering Types

+ * Create a {@code cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory} by passing the base type and type field + * name to the {@link #of} factory method. If you don't supply an explicit type + * field name, {@code "type"} will be used.
   {@code
+ *   cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory shapeAdapterFactory
+ *       = cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory.of(Shape.class, "type");
+ * }
+ * Next register all of your subtypes. Every subtype must be explicitly + * registered. This protects your application from injection attacks. If you + * don't supply an explicit type label, the type's simple name will be used. + *
   {@code
+ *   shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle");
+ *   shapeAdapterFactory.registerSubtype(Circle.class, "Circle");
+ *   shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond");
+ * }
+ * Finally, register the type adapter factory in your application's GSON builder: + *
   {@code
+ *   Gson gson = new GsonBuilder()
+ *       .registerTypeAdapterFactory(shapeAdapterFactory)
+ *       .create();
+ * }
+ * Like {@code GsonBuilder}, this API supports chaining:
   {@code
+ *   cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory shapeAdapterFactory = cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory.of(Shape.class)
+ *       .registerSubtype(Rectangle.class)
+ *       .registerSubtype(Circle.class)
+ *       .registerSubtype(Diamond.class);
+ * }
+ * + *

Serialization and deserialization

+ * In order to serialize and deserialize a polymorphic object, + * you must specify the base type explicitly. + *
   {@code
+ *   Diamond diamond = new Diamond();
+ *   String json = gson.toJson(diamond, Shape.class);
+ * }
+ * And then: + *
   {@code
+ *   Shape shape = gson.fromJson(json, Shape.class);
+ * }
+ */ +public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { + private final Class baseType; + private final String typeFieldName; + private final Map> labelToSubtype = new LinkedHashMap<>(); + private final Map, String> subtypeToLabel = new LinkedHashMap<>(); + private final boolean maintainType; + + private RuntimeTypeAdapterFactory(Class baseType, String typeFieldName, boolean maintainType) { + if (typeFieldName == null || baseType == null) { + throw new NullPointerException(); + } + this.baseType = baseType; + this.typeFieldName = typeFieldName; + this.maintainType = maintainType; + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + * {@code maintainType} flag decide if the type will be stored in pojo or not. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName, boolean maintainType) { + return new RuntimeTypeAdapterFactory<>(baseType, typeFieldName, maintainType); + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName) { + return new RuntimeTypeAdapterFactory<>(baseType, typeFieldName, false); + } + + /** + * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as + * the type field name. + */ + public static RuntimeTypeAdapterFactory of(Class baseType) { + return new RuntimeTypeAdapterFactory<>(baseType, "type", false); + } + + /** + * Registers {@code type} identified by {@code label}. Labels are case + * sensitive. + * + * @throws IllegalArgumentException if either {@code type} or {@code label} + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type, String label) { + if (type == null || label == null) { + throw new NullPointerException(); + } + if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { + throw new IllegalArgumentException("types and labels must be unique"); + } + labelToSubtype.put(label, type); + subtypeToLabel.put(type, label); + return this; + } + + /** + * Registers {@code type} identified by its {@link Class#getSimpleName simple + * name}. Labels are case sensitive. + * + * @throws IllegalArgumentException if either {@code type} or its simple name + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type) { + return registerSubtype(type, type.getSimpleName()); + } + + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (type.getRawType() != baseType) { + return null; + } + + final TypeAdapter jsonElementAdapter = gson.getAdapter(JsonElement.class); + final Map> labelToDelegate = new LinkedHashMap<>(); + final Map, TypeAdapter> subtypeToDelegate = new LinkedHashMap<>(); + for (Map.Entry> entry : labelToSubtype.entrySet()) { + TypeAdapter delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); + labelToDelegate.put(entry.getKey(), delegate); + subtypeToDelegate.put(entry.getValue(), delegate); + } + + return new TypeAdapter() { + @Override + public R read(JsonReader in) throws IOException { + JsonElement jsonElement = jsonElementAdapter.read(in); + JsonElement labelJsonElement; + if (maintainType) { + labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName); + } else { + labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); + } + + if (labelJsonElement == null) { + throw new JsonParseException("cannot deserialize " + baseType + + " because it does not define a field named " + typeFieldName); + } + String label = labelJsonElement.getAsString(); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) labelToDelegate.get(label); + if (delegate == null) { + throw new JsonParseException("cannot deserialize " + baseType + " subtype named " + + label + "; did you forget to register a subtype?"); + } + return delegate.fromJsonTree(jsonElement); + } + + @Override + public void write(JsonWriter out, R value) throws IOException { + Class srcType = value.getClass(); + String label = subtypeToLabel.get(srcType); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) subtypeToDelegate.get(srcType); + if (delegate == null) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + "; did you forget to register a subtype?"); + } + JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); + + if (maintainType) { + jsonElementAdapter.write(out, jsonObject); + return; + } + + JsonObject clone = new JsonObject(); + + if (jsonObject.has(typeFieldName)) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + " because it already defines a field named " + typeFieldName); + } + clone.add(typeFieldName, new JsonPrimitive(label)); + + for (Map.Entry e : jsonObject.entrySet()) { + clone.add(e.getKey(), e.getValue()); + } + jsonElementAdapter.write(out, clone); + } + }.nullSafe(); + } +} \ No newline at end of file diff --git a/src/BookPackage.java b/src/cmpt213/assignment2/packagedeliveriestracker/model/BookPackage.java similarity index 57% rename from src/BookPackage.java rename to src/cmpt213/assignment2/packagedeliveriestracker/model/BookPackage.java index 16abec8..9d1447a 100644 --- a/src/BookPackage.java +++ b/src/cmpt213/assignment2/packagedeliveriestracker/model/BookPackage.java @@ -1,17 +1,23 @@ +package cmpt213.assignment2.packagedeliveriestracker.model; + import java.time.LocalDateTime; -public class BookPackage extends PackageInfo{ +/** + * It's a subclass of PackageInfo that adds an author field + */ +public class BookPackage extends PackageInfo { String author; public BookPackage(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author) { super(name, note, price, weight, delivered, expectedDate); this.author = author; + this.setType("book"); } @Override public String toString() { - return super.toString()+"author='" + author + '\''; + return super.toString() + "\nAuthor: " + author; } } diff --git a/src/ElectronicPackage.java b/src/cmpt213/assignment2/packagedeliveriestracker/model/ElectronicPackage.java similarity index 54% rename from src/ElectronicPackage.java rename to src/cmpt213/assignment2/packagedeliveriestracker/model/ElectronicPackage.java index 13847b2..715e209 100644 --- a/src/ElectronicPackage.java +++ b/src/cmpt213/assignment2/packagedeliveriestracker/model/ElectronicPackage.java @@ -1,15 +1,21 @@ +package cmpt213.assignment2.packagedeliveriestracker.model; + import java.time.LocalDateTime; -public class ElectronicPackage extends PackageInfo{ +/** + * ElectronicPackage is a subclass of PackageInfo that adds a handlingFee attribute + */ +public class ElectronicPackage extends PackageInfo { double handlingFee; public ElectronicPackage(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate, double handlingFee) { super(name, note, price, weight, delivered, expectedDate); this.handlingFee = handlingFee; + this.setType("electronic"); } @Override public String toString() { - return super.toString()+"handlingFee=" + handlingFee; + return super.toString() + "\nHandling fee: " + handlingFee; } } diff --git a/src/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory.java b/src/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory.java new file mode 100644 index 0000000..4ffe028 --- /dev/null +++ b/src/cmpt213/assignment2/packagedeliveriestracker/model/PackageFactory.java @@ -0,0 +1,68 @@ +package cmpt213.assignment2.packagedeliveriestracker.model; + +import java.time.LocalDateTime; + +/** + * The PackageFactory class is a factory class that creates a package object based on the type of + * package that is passed in + */ +public class PackageFactory { + /** + * > This function creates a new package object based on the package type + * + * @param type The type of package. + * @param name The name of the package. + * @param notes A string of notes about the package. + * @param price The price of the package + * @param weight The weight of the package in kilograms + * @param delivered Whether or not the package has been delivered + * @param expectDate The date the package is expected to be delivered. + * @param author The author of the book. + * @param expiryDate The date the package expires. + * @param handlingFee The handling fee for the package. + * @return A new instance of the package type. + */ + + public static PackageInfo create(PackageType type, String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectDate, String author, LocalDateTime expiryDate, double handlingFee) { + return type.getInstance(name, notes, price, weight, delivered, expectDate, author, expiryDate, handlingFee); + } + + // Creating an enum called PackageType. + public enum PackageType { + Book { + public PackageInfo getInstance(String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author, LocalDateTime expiryDate, double handlingFee) { + return new BookPackage(name, notes, price, weight, delivered, expectedDate, author); + } + }, + + Perishable { + public PackageInfo getInstance(String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author, LocalDateTime expiryDate, double handlingFee) { + return new PerishablePackage(name, notes, price, weight, delivered, expectedDate, expiryDate); + } + }, + + Electronic { + public PackageInfo getInstance(String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author, LocalDateTime expiryDate, double handlingFee) { + return new ElectronicPackage(name, notes, price, weight, delivered, expectedDate, handlingFee); + } + }; + + /** + * It returns a PackageInfo object. + * + * @param name The name of the package. + * @param notes a string that describes the package + * @param price The price of the package + * @param weight the weight of the package in kg + * @param delivered true if the package has been delivered, false otherwise + * @param expectedDate The date the package is expected to be delivered. + * @param author The name of the author of the book. + * @param expiryDate The date when the package expires. + * @param handlingFee The handling fee for the package. + * @return A package object + */ + + public abstract PackageInfo getInstance(String name, String notes, double price, double weight, boolean delivered, LocalDateTime expectedDate, String author, LocalDateTime expiryDate, double handlingFee); + } + +} \ No newline at end of file diff --git a/src/cmpt213/assignment2/packagedeliveriestracker/model/PackageInfo.java b/src/cmpt213/assignment2/packagedeliveriestracker/model/PackageInfo.java new file mode 100644 index 0000000..e4ef20b --- /dev/null +++ b/src/cmpt213/assignment2/packagedeliveriestracker/model/PackageInfo.java @@ -0,0 +1,85 @@ +package cmpt213.assignment2.packagedeliveriestracker.model; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; + +import static java.lang.Math.abs; + +/** + * PackageInfo is a class that contains information about a package + */ + +public class PackageInfo implements Comparable { + private final String name; + private final String note; + private final double price; + private final double weight; + private final LocalDateTime expectedDate; + private boolean delivered; + private String type; + + public PackageInfo(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate) { + this.name = name; + this.note = note; + this.price = price; + this.weight = weight; + this.delivered = delivered; + this.expectedDate = expectedDate; + } + + /** + * This function returns the name of the person. + * + * @return The name of the person. + */ + public String getName() { + return name; + } + + + public boolean getDelivered() { + return delivered; + } + + /** + * This function sets the value of the delivered variable to the value of the delivered parameter. + * + * @param delivered This is a boolean value that indicates whether the message has been delivered + * to the recipient. + */ + public void setDelivered(boolean delivered) { + this.delivered = delivered; + } + + public LocalDateTime getExpectedDate() { + return expectedDate; + } + + /** + * This function sets the type of the object to the type passed in as a parameter + * + * @param type The type of the event. + */ + public void setType(String type) { + this.type = type; + } + + // Comparing the expected date of the package to the expected date of the package passed in as a + // parameter. + @Override + public int compareTo(PackageInfo p) { + return this.expectedDate.compareTo(p.getExpectedDate()); + } + + // Overriding the toString method. + @Override + public String toString() { + DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm"); + LocalDateTime today = LocalDateTime.now(); + today.format(format); + long diff = ChronoUnit.DAYS.between(today, expectedDate); + String isDelivered = delivered ? "yes" : "no"; + return "Name: " + name + "\n" + "Notes: " + note + "\n" + "Price: " + price + "\n" + "Weight: " + weight + "\n" + "Expected Delivery Date: " + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(expectedDate) + "\n" + "Delivered? " + isDelivered + "\n" + ((diff > 0 && !delivered) ? diff + " days remaining" : abs(diff) + " days overdue"); + } +} diff --git a/src/cmpt213/assignment2/packagedeliveriestracker/model/PerishablePackage.java b/src/cmpt213/assignment2/packagedeliveriestracker/model/PerishablePackage.java new file mode 100644 index 0000000..522ec5e --- /dev/null +++ b/src/cmpt213/assignment2/packagedeliveriestracker/model/PerishablePackage.java @@ -0,0 +1,24 @@ +package cmpt213.assignment2.packagedeliveriestracker.model; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * It's a subclass of PackageInfo that adds an expiry date + */ +public class PerishablePackage extends PackageInfo { + LocalDateTime expiryDate; + + // It's a constructor that initializes the object with the given parameters. + public PerishablePackage(String name, String note, double price, double weight, boolean delivered, LocalDateTime expectedDate, LocalDateTime expiryDate) { + super(name, note, price, weight, delivered, expectedDate); + this.expiryDate = expiryDate; + this.setType("perishable"); + } + + // It's a method that returns a string representation of the object. + @Override + public String toString() { + return super.toString() + "\nExpiry date: " + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(expiryDate); + } +} diff --git a/src/cmpt213/assignment2/packagedeliveriestracker/textui/PackageDeliveriesTracker.java b/src/cmpt213/assignment2/packagedeliveriestracker/textui/PackageDeliveriesTracker.java new file mode 100644 index 0000000..405470c --- /dev/null +++ b/src/cmpt213/assignment2/packagedeliveriestracker/textui/PackageDeliveriesTracker.java @@ -0,0 +1,137 @@ +package cmpt213.assignment2.packagedeliveriestracker.textui; + +import cmpt213.assignment2.packagedeliveriestracker.gson.extras.RuntimeTypeAdapterFactory; +import cmpt213.assignment2.packagedeliveriestracker.model.BookPackage; +import cmpt213.assignment2.packagedeliveriestracker.model.ElectronicPackage; +import cmpt213.assignment2.packagedeliveriestracker.model.PackageInfo; +import cmpt213.assignment2.packagedeliveriestracker.model.PerishablePackage; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.*; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Scanner; + +/** + * It's a class that contains a main method that creates a TextMenu object, loads a list of packages + * from a file, and then loops through a menu of options until the user chooses to quit + */ +public class PackageDeliveriesTracker { + private static final String fileName = "list.json"; + private static final RuntimeTypeAdapterFactory r = RuntimeTypeAdapterFactory.of(PackageInfo.class, "type") + .registerSubtype(BookPackage.class, "book") + .registerSubtype(PerishablePackage.class, "perishable") + .registerSubtype(ElectronicPackage.class, "electronic"); + private static final Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, + new TypeAdapter() { + @Override + public void write(JsonWriter jsonWriter, + LocalDateTime localDateTime) throws IOException { + jsonWriter.value(localDateTime.toString()); + } + + @Override + public LocalDateTime read(JsonReader jsonReader) throws IOException { + return LocalDateTime.parse(jsonReader.nextString()); + } + }).registerTypeAdapterFactory(r).create(); + private static ArrayList packageList = new ArrayList<>(); + + /** + * It saves the packageList to a file. + */ + private static void save() { + try { + Writer w = new FileWriter(fileName); + gson.toJson(packageList, w); + w.flush(); + w.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * It reads the json file, converts it to a list of PackageInfo objects, and then sets the type of + * each object to the appropriate type + */ + private static void load() { + File file = new File(fileName); + try { + String json = Files.readString(Paths.get(fileName)); + Type lType = new TypeToken>() { + }.getType(); + packageList = gson.fromJson(json, lType); + for (PackageInfo p : packageList) { + if (p instanceof BookPackage) { + p.setType("book"); + } else if (p instanceof PerishablePackage) { + p.setType("perishable"); + } else if (p instanceof ElectronicPackage) { + p.setType("electronic"); + } + } + System.out.println("packages loaded"); + } catch (FileNotFoundException e) { + System.out.println("no packages to load"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * This function is the main function of the program. It creates a TextMenu object, loads the + * packages from the file, displays the menu, and then waits for the user to input a number between + * 1 and 7. If the user inputs a number outside of that range, the program will display an error + * message. If the user inputs 7, the program will save the packages to the file and exit. If the + * user inputs a number between 1 and 6, the program will call the corresponding function in the + * TextMenu class + */ + public static void main(String[] args) { + TextMenu menu = new TextMenu(); + load(); + do { + menu.display(); + System.out.println("choose an option between 1 and 7:"); + Scanner scan = new Scanner(System.in); + int option = Integer.parseInt(scan.nextLine()); + if (option > 7 || option < 1) { + System.out.println("invalid input"); + } else if (option == 7) { + save(); + System.out.print("packages saved"); + break; + } else { + switch (option) { + case 1: + menu.list(packageList); + break; + case 2: + menu.add(packageList); + break; + case 3: + menu.remove(packageList); + break; + case 4: + menu.overDueList(packageList); + break; + case 5: + menu.upcomingList(packageList); + break; + case 6: + menu.markDelivered(packageList); + } + } + } + while (true); + } +} + diff --git a/src/cmpt213/assignment2/packagedeliveriestracker/textui/TextMenu.java b/src/cmpt213/assignment2/packagedeliveriestracker/textui/TextMenu.java new file mode 100644 index 0000000..7613412 --- /dev/null +++ b/src/cmpt213/assignment2/packagedeliveriestracker/textui/TextMenu.java @@ -0,0 +1,280 @@ +package cmpt213.assignment2.packagedeliveriestracker.textui; + +import cmpt213.assignment2.packagedeliveriestracker.model.PackageFactory; +import cmpt213.assignment2.packagedeliveriestracker.model.PackageInfo; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.*; + +/** + * It's a class that displays a menu and allows the user to interact with the program + */ +public class TextMenu { + private final String title = "Package Tracker"; + private final String[] options = new String[]{ + "List of all packages", + "Add a package", + "remove a package", + "list overdue packages", + "List upcoming packages", + "mark package as delivered", + "exit"}; + + /** + * This function displays the title of the menu, the current date, and the options available to the + * user + */ + public void display() { + int tag = title.length(); + for (int i = 0; i <= tag + 3; i++) { + System.out.print("#"); + } + System.out.println("\n# " + title + " #"); + for (int i = 0; i <= tag + 3; i++) { + System.out.print("#"); + } + DateFormat today = new SimpleDateFormat("yyy-MM-dd"); + Calendar cal = Calendar.getInstance(); + System.out.println("\nToday is: " + today.format(cal.getTime())); + for (int i = 0; i < options.length; i++) { + System.out.println((i + 1) + ": " + options[i]); + } + } + + /** + * This function takes an ArrayList of PackageInfo objects and prints them out in reverse order + * + * @param packageList The list of packages to be displayed + */ + public void list(ArrayList packageList) { + if (packageList.size() == 0) { + System.out.println("No packages to show"); + } else { + Collections.sort(packageList); + for (int i = 0; i < packageList.size(); i++) { + System.out.println("Package #" + (i + 1)); + System.out.println(packageList.get(i) + "\n"); + } + } + } + + /** + * This function allows the user to add a package to the list of packages + * + * @param packageList the list of packages + */ + public void add(ArrayList packageList) { + Scanner scan = new Scanner(System.in); + int itemType; + do { + System.out.println("please select (1) book, (2) perishable, or (3) electronic package"); + itemType = Integer.parseInt(scan.nextLine()); + } + while (itemType < 1 || itemType > 3); + PackageFactory.PackageType pType = PackageFactory.PackageType.Book; + String author = ""; + LocalDateTime expiryDate = LocalDateTime.now(); + double handlingFee = 0.0; + String pName; + do { + System.out.println("enter a valid package name:"); + pName = scan.nextLine(); + } + while (pName.length() == 0); + System.out.println("notes:"); + String pNotes = scan.nextLine(); + boolean checkDate = false; + DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm"); + LocalDateTime pDate = LocalDateTime.now(); + while (checkDate == false) { + try { + System.out.println("enter date as yyyy-mm-dd hh:mm:"); + pDate = LocalDateTime.parse(scan.nextLine(), format); + checkDate = true; + } catch (DateTimeParseException e) { + System.out.println("invalid date format"); + } + } + double pPrice; + do { + System.out.println("enter price:"); + pPrice = Double.parseDouble(scan.nextLine()); + } + while (pPrice < 0); + double pWeight; + do { + System.out.println("enter weight:"); + pWeight = Double.parseDouble(scan.nextLine()); + } + while (pWeight <= 0); + switch (itemType) { + case 1: + do { + System.out.println("enter author"); + author = scan.nextLine(); + } + while (author.length() == 0); + break; + case 2: + boolean checkExpDate = false; + while (checkExpDate == false) { + try { + System.out.println("enter expiry date as yyyy-mm-dd hh:mm"); + expiryDate = LocalDateTime.parse(scan.nextLine(), format); + checkExpDate = true; + } catch (DateTimeParseException e) { + System.out.println("invalid date format"); + } + } + pType = PackageFactory.PackageType.Perishable; + break; + case 3: + do { + System.out.println("enter handling fee"); + handlingFee = Double.parseDouble(scan.nextLine()); + } + while (handlingFee <= 0); + pType = PackageFactory.PackageType.Electronic; + break; + } + PackageInfo p = PackageFactory.create(pType, pName, pNotes, pPrice, pWeight, false, pDate, author, expiryDate, handlingFee); + packageList.add(p); + System.out.println(pName + " has been added to the list!"); + } + + /** + * This function takes in an ArrayList of PackageInfo objects and prints out the list of packages + * in the ArrayList. The user is then prompted to enter the number of the package they want to + * remove. If the user enters a number that is not in the list, the user is prompted to enter a + * number again. If the user enters 0, the function returns without removing anything. If the user + * enters a number that is in the list, the package is removed from the list and the user is + * notified + * + * @param packageList the list of packages to be displayed + */ + public void remove(ArrayList packageList) { + this.list(packageList); + if (packageList.size() == 0) { + return; + } + Scanner scan = new Scanner(System.in); + int n; + do { + System.out.println("enter item number you want to remove (0 to cancel):"); + n = scan.nextInt(); + } + while (n < 0 || n > packageList.size()); + if (n > 0) { + System.out.println(packageList.get(n - 1).getName() + " has been removed from the list."); + packageList.remove(n - 1); + } + } + + /** + * This function takes in a list of packages, a boolean for whether or not the user wants to see + * packages that are due, and a boolean for whether or not the user wants to see all packages. It + * then returns a list of packages that are sorted by their expected delivery date + * + * @param pList the list of packages to be sorted + * @param due true if you want to sort the list by due date, false if you want to sort the list by + * expected date + * @return An ArrayList of PackageInfo objects. + */ + //due=true returns overdue packages, else upcoming packages + public ArrayList sortList(ArrayList pList, boolean due) { + ArrayList sortedList = new ArrayList<>(); + LocalDateTime today = LocalDateTime.now(); + DateTimeFormatter format = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm"); + today.format(format); + for (int i = 0; i < pList.size(); i++) { + PackageInfo p = pList.get(i); + if (!p.getDelivered()) { + if (due && today.isAfter(p.getExpectedDate())) { + sortedList.add(p); + } else if (!due && today.isBefore(p.getExpectedDate())) { + sortedList.add(p); + } + } + } + Collections.sort(sortedList); + return sortedList; + } + + /** + * This function takes in a list of packages and returns a list of packages that are overdue + * + * @param packageList the list of packages to be sorted + */ + public void overDueList(ArrayList packageList) { + ArrayList overdue = sortList(packageList, true); + if (overdue.size() == 0) { + System.out.println("no overdue packages to show"); + return; + } + this.list(overdue); + } + + /** + * This function takes in a list of packages and prints out the packages that are upcoming + * + * @param packageList the list of packages to be sorted + */ + public void upcomingList(ArrayList packageList) { + ArrayList upcoming = sortList(packageList, false); + if (upcoming.size() == 0) { + System.out.println("no upcoming packages to show"); + return; + } + this.list(upcoming); + } + + /** + * This function takes a list of packages and returns a list of packages that have not been + * delivered + * + * @param packageList The list of packages to be filtered + * @return An ArrayList of PackageInfo objects that have not been delivered. + */ + public ArrayList getUndelivered(List packageList) { + ArrayList undelivered = new ArrayList<>(); + for (int i = 0; i < packageList.size(); i++) { + if (packageList.get(i).getDelivered() == false) { + undelivered.add(packageList.get(i)); + } + } + return undelivered; + } + + /** + * This function takes a list of packages and prints out the undelivered packages, then asks the + * user to select a package to mark as delivered + * + * @param packageList the list of packages to be marked as delivered + */ + public void markDelivered(ArrayList packageList) { + ArrayList undelivered = getUndelivered(packageList); + if (undelivered.size() == 0) { + System.out.println("No undelivered packages to show"); + return; + } + this.list(undelivered); + Scanner scan = new Scanner(System.in); + int n; + do { + System.out.println("enter item number you want to mark delivered (0 to cancel):"); + n = scan.nextInt(); + } + while (n < 0 || n > undelivered.size()); + if (n > 0) { + PackageInfo p = undelivered.get(n - 1); + packageList.get(packageList.indexOf(p)).setDelivered(true); + System.out.println(p.getName() + " has been delivered."); + } + } + + +}