Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 82 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,82 @@
# Library Management System
# <img src="app/src/main/resources/library.png" alt="Library Icon" width="50"/> 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.**

<img src="app/src/main/resources/cmd.png" alt="Console Icon" width="50"/> <img src="app/src/main/resources/kotlin.png" alt="Kotlin Icon" width="50"/>

## ❓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`

15 changes: 0 additions & 15 deletions app/src/main/kotlin/org/example/App.kt

This file was deleted.

14 changes: 14 additions & 0 deletions app/src/main/kotlin/org/example/Book.kt
Original file line number Diff line number Diff line change
@@ -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
}
}
14 changes: 14 additions & 0 deletions app/src/main/kotlin/org/example/DVD.kt
Original file line number Diff line number Diff line change
@@ -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
}
}
148 changes: 148 additions & 0 deletions app/src/main/kotlin/org/example/Library.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package org.example

import kotlin.math.PI
import kotlin.math.pow

class Library {
// Map of item id to LibraryItem
private val itemsById = HashMap<String, LibraryItem>()

// Map of category to list of LibraryItems in category
private val itemsByCategory = HashMap<String, MutableList<LibraryItem>>()

// Map of memberId to Member
private val members = HashMap<String, Member>()

// Map of memberId to Member.borrowedItems
private val borrowedItems = HashMap<String, MutableList<String>>()

//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) {

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(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 findBooksByAuthor(author: String): List<Book> {
//
val booksInLibrary = itemsByCategory["Book"] as MutableList<Book>?

val booksByAuthor: MutableList<Book> = mutableListOf()

booksInLibrary?.forEach { book ->
if(book.author == author) {
booksByAuthor.add(book)
}
}

val result = booksByAuthor.toList()

return result
}


// fun <T: LibraryItem> findItemsBy(
// type: Class<T>,
// predicate: (T) -> Boolean
// ) : List<T> {
// if((itemsByCategory).any(type))
//
// }

fun getLibraryStatistics(): Map<String, Any> {
val numberOfBooks = itemsByCategory["Book"]?.count()
val numberOfDVDs = itemsByCategory["DVD"]?.count()
val numberOfMagazines = itemsByCategory["Magazine"]?.count()

val result: Map<String, Any>

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<String, Any>

return result
}

fun processOverdueItems(action: (LibraryItem, Member, Int) -> Unit) {

}

fun List<LibraryItem>.filterByAvailability(available: Boolean): List<LibraryItem> {
val items = itemsById.values

val resultList: MutableList<LibraryItem> = 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}"
// }



}
16 changes: 16 additions & 0 deletions app/src/main/kotlin/org/example/LibraryItem.kt
Original file line number Diff line number Diff line change
@@ -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"
}


}
13 changes: 13 additions & 0 deletions app/src/main/kotlin/org/example/Magazine.kt
Original file line number Diff line number Diff line change
@@ -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
}
}
54 changes: 54 additions & 0 deletions app/src/main/kotlin/org/example/Main.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* This source file was generated by the Gradle 'init' task
*/
package org.example

fun main() {
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")

}
Loading