From 11d42778e350371c2af9faee5675ed7c72463a76 Mon Sep 17 00:00:00 2001 From: asadlodhi Date: Wed, 27 Aug 2025 18:26:35 +0500 Subject: [PATCH 1/5] OOP Concepts Abstraction inplemented in Abstract LibraryItem class Inheritance & Polymorphism implemented in Book, DVD, Magazine classes Encapsulation implemented in Member class Other changes include: renamed App.kt -> Main.kt added sample data in fun main() to test Book and Member classes --- app/src/main/kotlin/org/example/App.kt | 15 ----- app/src/main/kotlin/org/example/Book.kt | 14 ++++ app/src/main/kotlin/org/example/DVD.kt | 14 ++++ .../main/kotlin/org/example/LibraryItem.kt | 16 +++++ app/src/main/kotlin/org/example/Magazine.kt | 13 ++++ app/src/main/kotlin/org/example/Main.kt | 24 +++++++ app/src/main/kotlin/org/example/Member.kt | 64 +++++++++++++++++++ 7 files changed, 145 insertions(+), 15 deletions(-) delete mode 100644 app/src/main/kotlin/org/example/App.kt create mode 100644 app/src/main/kotlin/org/example/Book.kt create mode 100644 app/src/main/kotlin/org/example/DVD.kt create mode 100644 app/src/main/kotlin/org/example/LibraryItem.kt create mode 100644 app/src/main/kotlin/org/example/Magazine.kt create mode 100644 app/src/main/kotlin/org/example/Main.kt create mode 100644 app/src/main/kotlin/org/example/Member.kt diff --git a/app/src/main/kotlin/org/example/App.kt b/app/src/main/kotlin/org/example/App.kt deleted file mode 100644 index a1d413b..0000000 --- a/app/src/main/kotlin/org/example/App.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * This source file was generated by the Gradle 'init' task - */ -package org.example - -class App { - val greeting: String - get() { - return "Hello World!" - } -} - -fun main() { - println(App().greeting) -} diff --git a/app/src/main/kotlin/org/example/Book.kt b/app/src/main/kotlin/org/example/Book.kt new file mode 100644 index 0000000..ad9dda4 --- /dev/null +++ b/app/src/main/kotlin/org/example/Book.kt @@ -0,0 +1,14 @@ +package org.example + +class Book( + id: String, + title: String, + val author: String, + val isbn: String, + val pages: Int +) : LibraryItem(id, title) { + override fun getItemType(): String = "Book" + override fun calculateLateFee(daysLate: Int): Double { + return daysLate * 0.5 + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/example/DVD.kt b/app/src/main/kotlin/org/example/DVD.kt new file mode 100644 index 0000000..b9a04df --- /dev/null +++ b/app/src/main/kotlin/org/example/DVD.kt @@ -0,0 +1,14 @@ +package org.example + +class DVD( + id: String, + title: String, + val director: String, + val duration: Int, + val genre: String +) : LibraryItem(id, title) { + override fun getItemType(): String = "DVD" + override fun calculateLateFee(daysLate: Int): Double { + return daysLate * 1.0 + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/example/LibraryItem.kt b/app/src/main/kotlin/org/example/LibraryItem.kt new file mode 100644 index 0000000..a0f790e --- /dev/null +++ b/app/src/main/kotlin/org/example/LibraryItem.kt @@ -0,0 +1,16 @@ +package org.example + +abstract class LibraryItem( + val id: String, + val title: String, + var isAvailable: Boolean = true +) { + abstract fun getItemType(): String + abstract fun calculateLateFee(daysLate: Int): Double + + open fun displayInfo(): String { + return "ID: $id, Title: $title, Available: $isAvailable" + } + + +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/example/Magazine.kt b/app/src/main/kotlin/org/example/Magazine.kt new file mode 100644 index 0000000..a273bbb --- /dev/null +++ b/app/src/main/kotlin/org/example/Magazine.kt @@ -0,0 +1,13 @@ +package org.example + +class Magazine( + id: String, + title: String, + val issueNumber: Int, + val publisher: String +) : LibraryItem(id, title) { + override fun getItemType(): String = "Magazine" + override fun calculateLateFee(daysLate: Int): Double { + return daysLate * 0.25 + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/org/example/Main.kt b/app/src/main/kotlin/org/example/Main.kt new file mode 100644 index 0000000..74009e6 --- /dev/null +++ b/app/src/main/kotlin/org/example/Main.kt @@ -0,0 +1,24 @@ +/* + * This source file was generated by the Gradle 'init' task + */ +package org.example + +fun main() { + val member1= Member("M1", "S", "s") + member1.setName("Smith") + member1.setEmail("smith.com") + member1.setEmail("smith@gmail.com") + + val book1 = Book("B1", "Harry Potter", "JK", "1111-222", 122) + member1.borrowItem(book1) + + val member2 = Member("M2", "John", "john@gmail.com") + member2.borrowItem(book1) + + member2.returnItem(book1) + member1.returnItem(book1) + member2.borrowItem(book1) + member1.totalLateFees(15) + member2.totalLateFees(15) + +} diff --git a/app/src/main/kotlin/org/example/Member.kt b/app/src/main/kotlin/org/example/Member.kt new file mode 100644 index 0000000..646982a --- /dev/null +++ b/app/src/main/kotlin/org/example/Member.kt @@ -0,0 +1,64 @@ +package org.example + +class Member( + private val memberId: String, + private var name: String, + private var email: String +) { + private val borrowedItems = mutableListOf() + + fun getMemberId(): String = memberId + fun getName(): String = name + fun getEmail(): String = email + + fun setName(memberName: String) { + name = memberName + println("Member Name set to $name") + } + fun setEmail(memberEmail: String) { + if( + memberEmail.contains('@') + && + memberEmail.contains('.') + ) { + email = memberEmail + println("Member Email set to $email") + } else { + println("invalid email") + } + } + + fun borrowItem(item: LibraryItem) { + if(item.isAvailable) { + borrowedItems.add(item) + item.isAvailable = false + println("Member $memberId $name borrowed item ${item.id} ${item.title}") + } + else { + println("item unavailable") + } + } + + fun returnItem(item: LibraryItem) { + if(borrowedItems.contains(item)) { + borrowedItems.remove(item) + item.isAvailable = true + println("Member $memberId $name returned item ${item.id} ${item.title}") + } else { + println("Member $memberId $name did not borrow this item") + } + } + + fun totalLateFees(daysLate: Int) { + if(borrowedItems.isEmpty()) { + println("no items borrowed") + } + else { + var total = 0.0 + borrowedItems.forEach { item -> + total += item.calculateLateFee(daysLate) + } + println("Total Late Fees = $$total") + } + } +} \ No newline at end of file From b693c3d345fb070e7218a654d22a540aced3ae78 Mon Sep 17 00:00:00 2001 From: asadlodhi Date: Wed, 27 Aug 2025 20:25:29 +0500 Subject: [PATCH 2/5] Collections & HashMaps Created Library Class which holds collections of Items by Id, Items by Category, Members and performs Borrowed Items tracking with HashMaps --- app/src/main/kotlin/org/example/Library.kt | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 app/src/main/kotlin/org/example/Library.kt diff --git a/app/src/main/kotlin/org/example/Library.kt b/app/src/main/kotlin/org/example/Library.kt new file mode 100644 index 0000000..15e8de5 --- /dev/null +++ b/app/src/main/kotlin/org/example/Library.kt @@ -0,0 +1,45 @@ +package org.example + +class Library { + // Map of item id to LibraryItem + private val itemsById = HashMap() + + // Map of category to list of LibraryItems in category + private val itemsByCategory = HashMap>() + + // Map of memberId to Member + private val members = HashMap() + + // Map of memberId to Member.borrowedItems + private val borrowedItems = HashMap>() + + //library.addItem(Book("B001", "The Kotlin Guide", "John Doe", "978-1234567890", 300)) + fun addItem(item: LibraryItem) { + itemsById[item.id] = item + itemsByCategory[item.getItemType()]?.add(item) + } + //library.registerMember(Member("M001", "Alice Johnson", "alice@email.com")) + fun registerMember(member: Member) { + members[member.getMemberId()] = member + } + //borrowItem("M001", "B001") + fun borrowItem(memberId: String, itemId: String) { +// val member = members.get(memberId) +// val item = itemsById.get(itemId) +// +// member?.borrowItem(item) + + borrowedItems[memberId]?.add(itemId) + + } + + fun returningItem(itemId: String) { + + } + + //library.findBooksByAuthor("John Doe") + fun searchItemByCriteria() { + + } + +} \ No newline at end of file From 242c36f65a0a256a93d84a076059cd74f074e9f0 Mon Sep 17 00:00:00 2001 From: asadlodhi Date: Thu, 28 Aug 2025 17:01:47 +0500 Subject: [PATCH 3/5] Recursive Functions Added Recursive Function Class with function to calculate CompoundLateFee In Library class, added borrowItem, returnItem, findBooksbyAuthor, getLibraryStatistics and other functons. In main function, added working examples of Member and Library Class functions. --- app/src/main/kotlin/org/example/Library.kt | 117 ++++++++++++++++-- app/src/main/kotlin/org/example/Main.kt | 62 +++++++--- app/src/main/kotlin/org/example/Member.kt | 4 +- .../kotlin/org/example/RecursiveFunctions.kt | 15 +++ 4 files changed, 173 insertions(+), 25 deletions(-) create mode 100644 app/src/main/kotlin/org/example/RecursiveFunctions.kt diff --git a/app/src/main/kotlin/org/example/Library.kt b/app/src/main/kotlin/org/example/Library.kt index 15e8de5..7f8628f 100644 --- a/app/src/main/kotlin/org/example/Library.kt +++ b/app/src/main/kotlin/org/example/Library.kt @@ -1,5 +1,8 @@ package org.example +import kotlin.math.PI +import kotlin.math.pow + class Library { // Map of item id to LibraryItem private val itemsById = HashMap() @@ -24,22 +27,122 @@ class Library { } //borrowItem("M001", "B001") fun borrowItem(memberId: String, itemId: String) { -// val member = members.get(memberId) -// val item = itemsById.get(itemId) -// -// member?.borrowItem(item) - borrowedItems[memberId]?.add(itemId) + var member: Member? = null + if(members.contains(memberId)){ + member = members[memberId] + } + var item: LibraryItem? = null + if(itemsById.contains(itemId)) { + item = itemsById[itemId] + } + + if(member != null && item != null) { + member.borrowItem(item) + borrowedItems[memberId]?.add(itemId) + } } - fun returningItem(itemId: String) { + fun returningItem(memberId: String, itemId: String) { + + var member: Member? = null + if(members.contains(memberId)){ + member = members[memberId] + } + var item: LibraryItem? = null + if(itemsById.contains(itemId)) { + item = itemsById[itemId] + } + + if(member != null && item != null) { + member.returnItem(item) + borrowedItems[memberId]?.remove(itemId) + } } //library.findBooksByAuthor("John Doe") - fun searchItemByCriteria() { + fun findBooksByAuthor(author: String): List { +// + val booksInLibrary = itemsByCategory["Book"] as MutableList? + + val booksByAuthor: MutableList = mutableListOf() + + booksInLibrary?.forEach { book -> + if(book.author == author) { + booksByAuthor.add(book) + } + } + + val result = booksByAuthor.toList() + + return result + } + + +// fun findItemsBy( +// type: Class, +// predicate: (T) -> Boolean +// ) : List { +// if((itemsByCategory).any(type)) +// +// } + + fun getLibraryStatistics(): Map { + val numberOfBooks = itemsByCategory["Book"]?.count() + val numberOfDVDs = itemsByCategory["DVD"]?.count() + val numberOfMagazines = itemsByCategory["Magazine"]?.count() + + val result: Map + result = mapOf( + Pair("Number of Books in Library:",numberOfBooks), + Pair("Number of DVDs in Library:",numberOfDVDs), + Pair("Number of Magazines in Library:",numberOfMagazines) + + ) as Map + + return result + } + + fun processOverdueItems(action: (LibraryItem, Member, Int) -> Unit) { + + } + + fun List.filterByAvailability(available: Boolean): List { + val items = itemsById.values + + val resultList: MutableList = mutableListOf() + + items.forEach { item -> + if(item.isAvailable == available) { + resultList.add(item) + } + } + + return resultList.toList() + } + + fun String.isValidEmail(): Boolean { + if( + String.toString().contains('@') && + String.toString().contains(".") + ) { + return true + } + else { + return false + } } +// fun LibraryItem.getFormattedInfo(): String { +// val item: LibraryItem +// val info: String +// +// info = "Item ID: ${item.id}" +// } + + + } \ No newline at end of file diff --git a/app/src/main/kotlin/org/example/Main.kt b/app/src/main/kotlin/org/example/Main.kt index 74009e6..94fc8a5 100644 --- a/app/src/main/kotlin/org/example/Main.kt +++ b/app/src/main/kotlin/org/example/Main.kt @@ -4,21 +4,51 @@ package org.example fun main() { - val member1= Member("M1", "S", "s") - member1.setName("Smith") - member1.setEmail("smith.com") - member1.setEmail("smith@gmail.com") - - val book1 = Book("B1", "Harry Potter", "JK", "1111-222", 122) - member1.borrowItem(book1) - - val member2 = Member("M2", "John", "john@gmail.com") - member2.borrowItem(book1) - - member2.returnItem(book1) - member1.returnItem(book1) - member2.borrowItem(book1) - member1.totalLateFees(15) - member2.totalLateFees(15) + val smith= Member("M1", "S", "s") + smith.setName("Smith") + smith.setEmail("smith.com") + smith.setEmail("smith@gmail.com") + + val john = Member("M2", "John", "john@gmail.com") + + val library = Library() +// Add sample data + library.addItem(Book("B1", "The Kotlin Guide", "John Doe", "978-1234567890", 300)) + library.addItem(Book("B2", "Harry Potter", "JK", "1111-222", 122)) + library.addItem(DVD("D1", "Kotlin Tutorial", "Jane Smith", 120, "Educational")) + library.addItem(Magazine("Z1", "Times Magazine", 25, "NY-Times")) + +// Register member + library.registerMember(Member("M3", "Alice Johnson", "alice@email.com")) + library.registerMember(smith) + library.registerMember(john) + + val libraryStats = library.getLibraryStatistics() + println("Library Stats: $libraryStats") + +// Demonstrate borrowing + library.borrowItem("M1", "B1") + library.borrowItem("M2", "B1") + library.borrowItem("M2", "B2") + library.borrowItem("M2", "D1") + library.borrowItem("M3", "Z1") + +//Demostrate returning + library.returningItem("M1", "B2") + library.returningItem("M1", "B1") + + smith.totalLateFees(5) + john.totalLateFees(5) +// Show functional programming + val availableBooks = library.findBooksByAuthor("John Doe") + .filter { it.isAvailable } +// .map { it.getFormattedInfo() } + println("Available books by John Doe:") + availableBooks.forEach { book -> + println(book.title) + } +//// Demonstrate recursion + val compoundFee = calculateCompoundLateFee(5.0, 7) + println("Compound late fee for 7 days: $$compoundFee") } diff --git a/app/src/main/kotlin/org/example/Member.kt b/app/src/main/kotlin/org/example/Member.kt index 646982a..cc3a22a 100644 --- a/app/src/main/kotlin/org/example/Member.kt +++ b/app/src/main/kotlin/org/example/Member.kt @@ -51,14 +51,14 @@ class Member( fun totalLateFees(daysLate: Int) { if(borrowedItems.isEmpty()) { - println("no items borrowed") + println("$name borrowed no items") } else { var total = 0.0 borrowedItems.forEach { item -> total += item.calculateLateFee(daysLate) } - println("Total Late Fees = $$total") + println("$name Total Late Fees = $$total") } } } \ No newline at end of file diff --git a/app/src/main/kotlin/org/example/RecursiveFunctions.kt b/app/src/main/kotlin/org/example/RecursiveFunctions.kt new file mode 100644 index 0000000..36f9f8b --- /dev/null +++ b/app/src/main/kotlin/org/example/RecursiveFunctions.kt @@ -0,0 +1,15 @@ +package org.example + +fun calculateCompoundLateFee(baseFee: Double, days: Int): Double { + // Using Math +// val fee: Double = baseFee * (1.05).pow(days) +// return fee + + // Recursive Function + var fee = baseFee + if(days != 0) { + fee = fee + baseFee * 1.05 + calculateCompoundLateFee(baseFee = fee, days = days - 1 ) + } + return fee +} \ No newline at end of file From ee217a22daf9b2ef44cc4f5e5fd9b3c04da68c9a Mon Sep 17 00:00:00 2001 From: asadlodhi Date: Fri, 29 Aug 2025 15:10:13 +0500 Subject: [PATCH 4/5] Images for README.md --- app/src/main/resources/cmd.png | Bin 0 -> 2400 bytes app/src/main/resources/kotlin.png | Bin 0 -> 2580 bytes app/src/main/resources/library.png | Bin 0 -> 19029 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 app/src/main/resources/cmd.png create mode 100644 app/src/main/resources/kotlin.png create mode 100644 app/src/main/resources/library.png diff --git a/app/src/main/resources/cmd.png b/app/src/main/resources/cmd.png new file mode 100644 index 0000000000000000000000000000000000000000..02d05487af03d92d3ecfcfe8850b47f38f151d2e GIT binary patch literal 2400 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 M07*qoM6N<$g3CK^Q~&?~ literal 0 HcmV?d00001 From 32ecf9e3fd0f3331577afdd0f6507056192214b3 Mon Sep 17 00:00:00 2001 From: Asad Lodhi <154895347+asad-lodhi@users.noreply.github.com> Date: Fri, 29 Aug 2025 17:24:48 +0500 Subject: [PATCH 5/5] Update README.md --- README.md | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9a0c952..0df43f9 100644 --- a/README.md +++ b/README.md @@ -1 +1,82 @@ -# Library Management System +# Library Icon Library Management System +**A console-based Library Management System that demonstrates understanding of Kotlin's core concepts including OOP, functional programming, collections (HashMaps), recursion, and more.** + +Console Icon Kotlin Icon + +## ❓How To Run +Navigate to `app/src/main/kotlin/org/example/Main.kt` + +Run `fun main()` + +## ⭐️ Features +## 🔶 Object-Oriented Programming ## +✅ Abstraction + +An abstract LibraryItem class with core variables and abstract functions + +`app/src/main/kotlin/org/example/LibraryItem.kt` + +✅ Inheritance & Polymorphism + +Book, DVD and Magazine classes which inherit variables from LibraryItem and uniquely implement abstract functions + +`app/src/main/kotlin/org/example/Book.kt` +`app/src/main/kotlin/org/example/DVD.kt` +`app/src/main/kotlin/org/example/Magazine.kt` + +✅ Encapsulation + +A Member class which encapsulates all variables and functions required for Member objects + +`app/src/main/kotlin/org/example/Member.kt` + +## 🔶 Collections & HashMaps ## + +A Library class which uses HashMaps to hold collections of LibraryItems, Members and track Borrowed Items. + +`app/src/main/kotlin/org/example/Library.kt` + +## 🔶 Functional Programming ## + +✅ Higher-Order Functions & Lambdas + +findBookByAuthor(), findItemBy() + +to specify search by criteria + +getLibraryStatistics() + +to get formatted display of entire Library data + +processOverdueItems() + +to process overdue fees on items borrowed by members + +`app/src/main/kotlin/org/example/Library.kt` + +✅ Extension Functions + +Implemented in the Library class fuctions + +List.filterByAvailability() + +to filter a list of LibraryItems and filter by set Availability (true or false) + +String.isValidEmail() + +to varify if a certain string is a valid email + +LibraryItem.getFormattedInfo() + +to obtain a well formatted display of LibraryItem information + +`app/src/main/kotlin/org/example/Library.kt` + +## 🔶 Recursion ## + +calculateCompoundLateFee() + +a recursive function which calculates compounded late fees on item based on a base amount and number of days the item is late for return + +`app/src/main/kotlin/org/example/RecursiveFunctions.kt` +