diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5ff6309
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,38 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..aa00ffa
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..5274667
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..111501f
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,32 @@
+
+
+ 4.0.0
+
+ org.to
+ HW03
+ 1.0-SNAPSHOT
+
+
+ 23
+ 23
+ UTF-8
+
+
+
+
+ com.google.code.gson
+ gson
+ 2.11.0
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.17.2
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/Rational/Rational.java b/src/main/java/Rational/Rational.java
new file mode 100644
index 0000000..7bd840e
--- /dev/null
+++ b/src/main/java/Rational/Rational.java
@@ -0,0 +1,108 @@
+package Rational;
+
+public class Rational {
+ private int numerator;
+ private int denominator;
+
+ // Constructor
+ public Rational(int numerator, int denominator) {
+ if (denominator == 0) {
+ throw new IllegalArgumentException("Denominator cannot be zero");
+ }
+ this.numerator = numerator;
+ this.denominator = denominator;
+ simplify();
+ }
+
+ // GCD helper for simplification
+ private int gcd(int a, int b) {
+ a = Math.abs(a);
+ b = Math.abs(b);
+ while (b != 0) {
+ int temp = b;
+ b = a % b;
+ a = temp;
+ }
+ return a;
+ }
+
+ // Simplify the fraction
+ private void simplify() {
+ int gcd = gcd(numerator, denominator);
+ numerator /= gcd;
+ denominator /= gcd;
+
+ // Keep denominator positive
+ if (denominator < 0) {
+ numerator = -numerator;
+ denominator = -denominator;
+ }
+ }
+
+ // COMPLETED - Instance method: this + other
+ public Rational add(Rational other) {
+ int newNumerator = this.numerator * other.denominator + other.numerator * this.denominator;
+ int newDenominator = this.denominator * other.denominator;
+ return new Rational(newNumerator, newDenominator);
+ }
+
+ // COMPLETED - Static method: r1 + r2
+ public static Rational add(Rational r1, Rational r2) {
+ return r1.add(r2);
+ }
+
+ // TODO: Instance method - this - other
+ // Formula: a/b - c/d = (a*d - c*b) / (b*d)
+ public Rational subtract(Rational other) {
+ // YOUR CODE HERE
+ return null; // Remove this line when implemented
+ }
+
+ // TODO: Static method - r1 - r2
+ public static Rational subtract(Rational r1, Rational r2) {
+ // YOUR CODE HERE
+ return null; // Remove this line when implemented
+ }
+
+ // TODO: Instance method - this * other
+ // Formula: (a/b) * (c/d) = (a*c) / (b*d)
+ public Rational multiply(Rational other) {
+ // YOUR CODE HERE
+ return null; // Remove this line when implemented
+ }
+
+ // TODO: Static method - r1 * r2
+ public static Rational multiply(Rational r1, Rational r2) {
+ // YOUR CODE HERE
+ return null; // Remove this line when implemented
+ }
+
+ // TODO: Instance method - this / other
+ // Formula: (a/b) ÷ (c/d) = (a*d) / (b*c)
+ public Rational divide(Rational other) {
+ // YOUR CODE HERE
+ // HINT: Division is multiplication by reciprocal
+ // Don't forget to check if other.numerator is zero!
+ return null; // Remove this line when implemented
+ }
+
+ // TODO: Static method - r1 / r2
+ public static Rational divide(Rational r1, Rational r2) {
+ // YOUR CODE HERE
+ return null; // Remove this line when implemented
+ }
+
+ // PROVIDED - String representation
+ @Override
+ public String toString() {
+ if (denominator == 1) {
+ return numerator + "";
+ }
+ return numerator + "/" + denominator;
+ }
+
+ // PROVIDED - Decimal value
+ public double toDouble() {
+ return (double) numerator / denominator;
+ }
+}
diff --git a/src/main/java/Rational/RationalTest.java b/src/main/java/Rational/RationalTest.java
new file mode 100644
index 0000000..32df336
--- /dev/null
+++ b/src/main/java/Rational/RationalTest.java
@@ -0,0 +1,108 @@
+package Rational;
+
+public class RationalTest {
+ public static void main(String[] args) {
+ System.out.println("=== Testing Rational Operations ===\n");
+
+ // Create some rational numbers
+ Rational r1 = new Rational(1, 2); // 1/2
+ Rational r2 = new Rational(1, 3); // 1/3
+ Rational r3 = new Rational(3, 4); // 3/4
+ Rational r4 = new Rational(2, 5); // 2/5
+ Rational r5 = new Rational(5, 1); // 5 (integer)
+
+ System.out.println("Created rational numbers:");
+ System.out.println("r1 = " + r1);
+ System.out.println("r2 = " + r2);
+ System.out.println("r3 = " + r3);
+ System.out.println("r4 = " + r4);
+ System.out.println("r5 = " + r5);
+ System.out.println();
+
+ // Test ADDITION
+ System.out.println("=== ADDITION ===");
+ System.out.println("Instance method - r1 + r2 = " + r1.add(r2));
+ System.out.println("Static method - Rational.add(r1, r2) = " + Rational.add(r1, r2));
+ System.out.println("Expected: 1/2 + 1/3 = 5/6");
+ System.out.println("Decimal: " + r1.add(r2).toDouble());
+ System.out.println();
+
+ // Test SUBTRACTION
+ System.out.println("=== SUBTRACTION ===");
+ System.out.println("Instance method - r1 - r2 = " + r1.subtract(r2));
+ System.out.println("Static method - Rational.subtract(r1, r2) = " + Rational.subtract(r1, r2));
+ System.out.println("Expected: 1/2 - 1/3 = 1/6");
+ System.out.println("Decimal: " + r1.subtract(r2).toDouble());
+ System.out.println();
+
+ // Test MULTIPLICATION
+ System.out.println("=== MULTIPLICATION ===");
+ System.out.println("Instance method - r1 * r3 = " + r1.multiply(r3));
+ System.out.println("Static method - Rational.multiply(r1, r3) = " + Rational.multiply(r1, r3));
+ System.out.println("Expected: 1/2 * 3/4 = 3/8");
+ System.out.println("Decimal: " + r1.multiply(r3).toDouble());
+ System.out.println();
+
+ // Test DIVISION
+ System.out.println("=== DIVISION ===");
+ System.out.println("Instance method - r1 ÷ r2 = " + r1.divide(r2));
+ System.out.println("Static method - Rational.divide(r1, r2) = " + Rational.divide(r1, r2));
+ System.out.println("Expected: 1/2 ÷ 1/3 = 3/2");
+ System.out.println("Decimal: " + r1.divide(r2).toDouble());
+ System.out.println();
+
+ // Test with negative numbers
+ System.out.println("=== NEGATIVE NUMBERS ===");
+ Rational neg1 = new Rational(-2, 3);
+ Rational neg2 = new Rational(4, -5);
+ System.out.println("neg1 = " + neg1); // Should show -2/3
+ System.out.println("neg2 = " + neg2); // Should show -4/5
+ System.out.println("neg1 + neg2 = " + neg1.add(neg2));
+ System.out.println("-2/3 + -4/5 = (-10/15 + -12/15) = -22/15");
+ System.out.println("neg1 * neg2 = " + neg1.multiply(neg2));
+ System.out.println("(-2/3) * (-4/5) = 8/15");
+ System.out.println();
+
+ // Test simplification
+ System.out.println("=== SIMPLIFICATION ===");
+ Rational r6 = new Rational(6, 8);
+ Rational r7 = new Rational(10, 25);
+ Rational r8 = new Rational(18, -24);
+ System.out.println("6/8 simplified = " + r6);
+ System.out.println("10/25 simplified = " + r7);
+ System.out.println("18/-24 simplified = " + r8);
+ System.out.println();
+
+ // Test chaining operations
+ System.out.println("=== CHAINING OPERATIONS ===");
+ Rational result = r1.add(r2).multiply(r3).divide(r4);
+ System.out.println("((r1 + r2) * r3) ÷ r4 = " + result);
+ System.out.println("((1/2 + 1/3) * 3/4) ÷ 2/5 = (5/6 * 3/4) ÷ 2/5 = (15/24) ÷ 2/5 = 15/24 * 5/2 = 75/48 = 25/16");
+ System.out.println("Decimal: " + result.toDouble());
+ System.out.println();
+
+ // Test integer handling
+ System.out.println("=== INTEGER HANDLING ===");
+ System.out.println("r5 = " + r5); // Should show 5, not 5/1
+ System.out.println("r5 + r1 = " + r5.add(r1));
+ System.out.println("5 + 1/2 = 11/2");
+ System.out.println("r1 * r5 = " + r1.multiply(r5));
+ System.out.println("1/2 * 5 = 5/2");
+ System.out.println();
+
+ // Test exception handling
+ System.out.println("=== EXCEPTION TEST ===");
+ try {
+ Rational invalid = new Rational(1, 0);
+ } catch (IllegalArgumentException e) {
+ System.out.println("Caught exception: " + e.getMessage());
+ }
+
+ try {
+ Rational zero = new Rational(0, 1);
+ Rational divisionByZero = r1.divide(zero);
+ } catch (ArithmeticException e) {
+ System.out.println("Caught division by zero: " + e.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/movie/apis/Genre.java b/src/main/java/movie/apis/Genre.java
new file mode 100644
index 0000000..8560f7f
--- /dev/null
+++ b/src/main/java/movie/apis/Genre.java
@@ -0,0 +1,35 @@
+package movie.apis;
+
+public class Genre {
+ private Long id;
+ private String name;
+
+ public Genre(Long id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public Genre() {
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return id + ". " + name;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/movie/apis/Main.java b/src/main/java/movie/apis/Main.java
new file mode 100644
index 0000000..f0e713d
--- /dev/null
+++ b/src/main/java/movie/apis/Main.java
@@ -0,0 +1,87 @@
+package movie.apis;
+
+import java.util.Scanner;
+
+public class Main {
+
+ private static final MovieService movieService = new MovieService();
+ private static final Scanner scanner = new Scanner(System.in);
+
+ public static void main(String[] args) {
+ System.out.println("\n=== MOVIE API CLIENT ===\n");
+
+ boolean running = true;
+ while (running) {
+ displayMenu();
+ int choice = getIntInput("Enter your choice: ");
+
+ switch (choice) {
+ case 1:
+ movieService.displayGenres();
+ break;
+
+ case 2:
+ // TODO: Get genre ID and page from user, then call movieService.displayMoviesByGenre()
+
+ break;
+
+
+ case 3:
+ // TODO (BONUS): Get movie ID from user, then call movieService.displayMovieDetails()
+
+
+ break;
+
+ case 0:
+ running = false;
+ System.out.println("Goodbye!");
+
+ break;
+
+ default:
+ System.out.println("Invalid choice! Please enter 0-4");
+ }
+
+ if (running) {
+ System.out.println("\nPress Enter to continue...");
+ scanner.nextLine();
+ scanner.nextLine();
+ }
+ }
+
+ scanner.close();
+ }
+
+ private static void displayMenu() {
+ System.out.println("\n================================");
+ System.out.println(" MENU");
+ System.out.println("================================");
+ System.out.println("1. Get all genres");
+ System.out.println("2. Get movies by genre ID");
+ System.out.println("3. Get movie details by ID");
+ System.out.println("0. Exit");
+ System.out.println("================================");
+ }
+
+ private static int getIntInput(String prompt) {
+ System.out.print(prompt);
+ while (!scanner.hasNextInt()) {
+ System.out.print("Invalid input. " + prompt);
+ scanner.next();
+ }
+ int input = scanner.nextInt();
+ scanner.nextLine();
+ return input;
+ }
+
+ private static Long getLongInput(String prompt) {
+ System.out.print(prompt);
+ while (!scanner.hasNextLong()) {
+ System.out.print("Invalid input. " + prompt);
+ scanner.next();
+ }
+ Long input = scanner.nextLong();
+ scanner.nextLine();
+ return input;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/movie/apis/Movie.java b/src/main/java/movie/apis/Movie.java
new file mode 100644
index 0000000..c8cc4e2
--- /dev/null
+++ b/src/main/java/movie/apis/Movie.java
@@ -0,0 +1,24 @@
+package movie.apis;
+
+import java.util.List;
+
+/**
+ * Model class representing a movie
+ * Fields: id, title, genres, images
+ */
+public class Movie {
+
+ private Long id;
+ private String title;
+ private List genres;
+ private String images;
+ private String year;
+ private String imdbRating;
+ private String country;
+
+ // TODO: Create a constructor with all fields
+
+ // TODO: Create a simple constructor with id and title only
+
+ // TODO: Create getters and setters for all fields
+}
\ No newline at end of file
diff --git a/src/main/java/movie/apis/MovieService.java b/src/main/java/movie/apis/MovieService.java
new file mode 100644
index 0000000..cbbe70b
--- /dev/null
+++ b/src/main/java/movie/apis/MovieService.java
@@ -0,0 +1,188 @@
+package movie.apis;
+
+import com.google.gson.*;
+import com.google.gson.reflect.TypeToken;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+
+public class MovieService {
+
+ private final static String GENRES_URL = "https://api.meshcomp.ir/api/v1/genres";
+ private final static String MOVIE_BY_ID_URL = "https://api.meshcomp.ir/api/v1/movies/";
+ private final static HttpClient client = HttpClient.newHttpClient();
+
+ private String getGenresList() {
+ try {
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(GENRES_URL))
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() == 200) {
+ System.out.println("Genres List received successfully");
+ return response.body();
+ } else {
+ throw new IOException("HTTP error code: " + response.statusCode());
+ }
+ } catch (Exception e) {
+ System.out.println("!!Exception : " + e.getMessage());
+ }
+ return null;
+ }
+
+ private String getMoviesByGenreList(Long genreId, Long page) {
+ try {
+ String url = "https://api.meshcomp.ir/api/v1/genres/" + genreId + "/movies?page=" + page;
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(url))
+ .build();
+
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() == 200) {
+ return response.body();
+ } else {
+ System.out.println("HTTP error code: " + response.statusCode());
+ return null;
+ }
+ } catch (Exception e) {
+ System.out.println("!!Exception : " + e.getMessage());
+ }
+ return null;
+ }
+
+
+
+ public void displayGenres() {
+ String jsonResponse = getGenresList();
+
+ if (jsonResponse == null) {
+ System.out.println("Failed to get genres");
+ return;
+ }
+
+ try {
+ JsonObject rootObject = JsonParser.parseString(jsonResponse).getAsJsonObject();
+ JsonArray genresArray = rootObject.getAsJsonArray("genres");
+ Type genreListType = new TypeToken>(){}.getType();
+ Gson gson = new Gson();
+ List genres = gson.fromJson(genresArray, genreListType);
+
+ System.out.println("\nALL GENRES:");
+ for (Genre genre : genres) {
+ System.out.println(genre.getId() + ". " + genre.getName());
+ }
+ System.out.println();
+ } catch (Exception e) {
+ System.err.println("ERROR parsing genres: " + e.getMessage());
+ }
+ }
+
+ /**
+ * TODO 1: Display movies for a specific genre and page
+ *
+ * JSON format: { "movies": [ { "id": 1, "title": "Movie", "year": "1994" } ], "total": 177, "total_pages": 18 }
+ *
+ * Steps:
+ * - Call getMoviesByGenreList(genreId, page) to get JSON
+ * - Parse JSON to JsonObject
+ * - Get "movies" array (NOT "data")
+ * - Loop through array and print: "ID: {id} | {title} ({year})"
+ * - Also print total and total_pages
+ *
+ * PUT ALL PARSING CODE INSIDE try-catch
+ */
+ public void displayMoviesByGenre(Long genreId, Long page) {
+ // TODO: Write your code here
+ // All parsing code must be inside try-catch
+ try {
+ // Your code here
+
+ } catch (Exception e) {
+ System.err.println("ERROR: " + e.getMessage());
+ }
+ }
+
+
+ /**
+ * BONUS: Fetch movie details from API using movie ID
+ * URL format: https://api.meshcomp.ir/api/v1/movies/{movieId}
+ */
+ private String getMovieById(Long movieId) {
+ try {
+ // TODO: Complete this method
+ // String url = MOVIE_BY_ID_URL + movieId;
+ // HttpRequest request = HttpRequest.newBuilder().uri(URI.create(url)).build();
+ // HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+ // if (response.statusCode() == 200) return response.body();
+
+ return null;
+ } catch (Exception e) {
+ System.out.println("!!Exception : " + e.getMessage());
+ }
+ return null;
+ }
+
+ /**
+ * BONUS TODO: Display complete movie details for a given movie ID
+ *
+ * Expected JSON format from getMovieById():
+ * {
+ * "id": 1,
+ * "title": "The Shawshank Redemption",
+ * "year": "1994",
+ * "genres": ["Crime", "Drama"],
+ * "poster": "https://moviesapi.ir/images/tt0111161_poster.jpg",
+ * "country": "USA",
+ * "imdb_rating": "9.3"
+ * }
+ *
+ * INSTRUCTIONS:
+ * 1. Call getMovieById(movieId) to get the JSON response
+ * 2. Check if response is null (if yes, print error and return)
+ * 3. Parse the JSON string to JsonObject (inside try-catch)
+ * 4. Extract all fields: id, title, year, genres array, poster, country, imdb_rating
+ * 5. Convert genres array to comma-separated string
+ * 6. Print all movie details in a readable format
+ *
+ * PUT ALL PARSING CODE INSIDE THE EXISTING try-catch
+ *
+ * @param movieId The ID of the movie to display
+ */
+ public void displayMovieDetails(Long movieId) {
+ // Step 1: Get JSON response from API
+ String jsonResponse = getMovieById(movieId);
+
+ // Step 2: Check if we got valid data
+ if (jsonResponse == null) {
+ System.out.println("Failed to get movie details for ID: " + movieId);
+ return;
+ }
+
+ // Step 3-6: Parse JSON and display details (PUT YOUR CODE INSIDE try-catch)
+ try {
+ // TODO: Parse jsonResponse to JsonObject
+ // TODO: Extract id, title, year, genres array, poster, country, imdb_rating
+ // TODO: Convert genres array to a readable string
+ // TODO: Print all movie details
+ // HINT: Use JsonParser.parseString(jsonResponse).getAsJsonObject()
+ // HINT: Use getAsJsonArray("genres") to get genres
+ // HINT: For each genre, use getAsString()
+
+ // Your code here:
+
+
+ } catch (Exception e) {
+ System.err.println("ERROR parsing movie details: " + e.getMessage());
+ }
+ }
+}
\ No newline at end of file