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