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
14 changes: 7 additions & 7 deletions parking_lot/floor.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,20 @@ func createParkingSpots(count int, vehicleType vehicles.VehicleType) map[int]*Pa
return spots
}

func (p *ParkingFloor) FindParkingSpot(vehicleType vehicles.VehicleType) *ParkingSpot {
for _, spot := range p.ParkingSpots[vehicleType] {
func (pf *ParkingFloor) FindParkingSpot(vehicleType vehicles.VehicleType) *ParkingSpot {
for _, spot := range pf.ParkingSpots[vehicleType] {
if spot.IsParkingSpotFree() {
return spot
}
}
return nil
}

func (p *ParkingFloor) DisplayFloorStatus(parkingFloor *ParkingFloor) {
fmt.Printf("Floor ID: %d\n", parkingFloor.FloorID)
func (pf *ParkingFloor) DisplayFloorStatus() {
fmt.Printf("Floor ID: %d\n", pf.FloorID)

for vehicleType, spotMap := range parkingFloor.ParkingSpots {
fmt.Printf("\n%s Spots:\n", vehicleType)
for vehicleType, spotMap := range pf.ParkingSpots {
fmt.Printf("%s Spots:\n", vehicleType)
count := 0

for _, spot := range spotMap {
Expand All @@ -58,6 +58,6 @@ func (p *ParkingFloor) DisplayFloorStatus(parkingFloor *ParkingFloor) {
}
}

fmt.Printf("\n%s Spot: %d Free\n", vehicleType, count)
fmt.Printf("%s Spot: %d Free\n", vehicleType, count)
}
}
2 changes: 2 additions & 0 deletions parking_lot/go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module lld_go_parking_lot

go 1.22.5

require github.com/google/uuid v1.6.0 // indirect
2 changes: 2 additions & 0 deletions parking_lot/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
26 changes: 16 additions & 10 deletions parking_lot/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,36 @@ func main() {

parkingLot.DisplayAvailability()

ticket, _ := parkingLot.ParkVehicle(vehicles.NewTruck("truck-1"))

time.Sleep(10 * time.Second)
err := parkingLot.UnparkVehicle(ticket)
truck := vehicles.NewTruck("truck-1")
ticket, err := parkingLot.ParkVehicle(truck)
if err != nil {
fmt.Printf("Failed to park %s: %v\n", truck.LicenceNumber, err)
return
}

formattedCharge := fmt.Sprintf("%.2f", ticket.CalculateTotalCharge())

fmt.Printf("bill for %s = %s\n", ticket.Vehicle.GetLicenceNumber(), formattedCharge)
time.Sleep(3 * time.Second)
err = parkingLot.UnparkVehicle(ticket.TicketId)
if err != nil {
fmt.Printf("Failed to unpark for ticketId %s: %v\n", ticket.TicketId, err)
return
}

// duplicate ticket unpark attempt
err = parkingLot.UnparkVehicle(ticket.TicketId)
if err != nil {
fmt.Printf("Failed to unpark for ticketId %s: %v\n", ticket.TicketId, err)
return
}
}

func parkCar(ind int, parkingLot *ParkingLot) {
defer wg.Done()

car := vehicles.NewCar(fmt.Sprintf("car-%d", ind))

ticket, err := parkingLot.ParkVehicle(car)
_, err := parkingLot.ParkVehicle(car)
if err != nil {
fmt.Printf("Failed to park %s: %v\n", car.LicenceNumber, err)
return
}

fmt.Printf("%s parked successfully. Ticket: %s\n", car.LicenceNumber, ticket.EntryTime)
}
62 changes: 45 additions & 17 deletions parking_lot/parking_lot.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,34 @@ var (
)

type ParkingLot struct {
Name string
floors []*ParkingFloor
Name string
floors []*ParkingFloor
tickets map[string]*ParkingTicket
}

func GetParkingLotInstance() *ParkingLot {

once.Do(func() {
parkingLotInstance = &ParkingLot{}
parkingLotInstance = &ParkingLot{
tickets: make(map[string]*ParkingTicket),
}
})
return parkingLotInstance
}

func (p *ParkingLot) AddFloor(floorID int) {
p.floors = append(p.floors, NewParkingFloor(floorID))
func (pl *ParkingLot) AddFloor(floorID int) {
pl.floors = append(pl.floors, NewParkingFloor(floorID))
}

func (p *ParkingLot) DisplayAvailability() {
fmt.Printf("Parking Lot: %s\n", p.Name)

for _, floor := range p.floors {
floor.DisplayFloorStatus(floor)
func (pl *ParkingLot) DisplayAvailability() {
fmt.Printf("Parking Lot: %s\n", pl.Name)
for _, floor := range pl.floors {
floor.DisplayFloorStatus()
}
}

func (p *ParkingLot) findParkingSpot(vehicleType vehicles.VehicleType) (*ParkingSpot, error) {
for _, floor := range p.floors {
func (pl *ParkingLot) findParkingSpot(vehicleType vehicles.VehicleType) (*ParkingSpot, error) {
for _, floor := range pl.floors {
if spot := floor.FindParkingSpot(vehicleType); spot != nil {
return spot, nil
}
Expand All @@ -47,8 +49,8 @@ func (p *ParkingLot) findParkingSpot(vehicleType vehicles.VehicleType) (*Parking
return nil, fmt.Errorf("no available parking spot found for %s", vehicleType)
}

func (p *ParkingLot) ParkVehicle(vehicle vehicles.VehicleInterface) (*ParkingTicket, error) {
parkingSpot, err := p.findParkingSpot(vehicle.GetVehicleType())
func (pl *ParkingLot) ParkVehicle(vehicle vehicles.VehicleInterface) (*ParkingTicket, error) {
parkingSpot, err := pl.findParkingSpot(vehicle.GetVehicleType())
if err != nil {
return nil, err
}
Expand All @@ -59,21 +61,47 @@ func (p *ParkingLot) ParkVehicle(vehicle vehicles.VehicleInterface) (*ParkingTic
}

parkingTicket := NewParkingTicket(vehicle, parkingSpot)
pl.tickets[parkingTicket.TicketId] = parkingTicket

fmt.Printf("%s parked successfully. Ticket: %v\n",
vehicle.GetLicenceNumber(),
parkingTicket,
)

return parkingTicket, nil
}

func (p *ParkingLot) UnparkVehicle(parkingTicket *ParkingTicket) error {
func (p *ParkingLot) UnparkVehicle(parkingTicketID string) error {
if len(parkingTicketID) == 0 {
return fmt.Errorf("invalid parking ticket id")
}

parkingTicket := p.tickets[parkingTicketID]
if parkingTicket == nil {
return fmt.Errorf("invalid parking ticket")
}

if parkingTicket.Status == Closed {
return fmt.Errorf("ticket is already used for exit")
}

parkingTicket.SetExitTime(time.Now())
charge := parkingTicket.CalculateTotalCharge()
charge, err := parkingTicket.CalculateTotalCharge()
if err != nil {
return err
}

paymentSystem := NewPaymentSystem(charge, parkingTicket)
formattedCharge := fmt.Sprintf("%.2f", charge)
fmt.Printf("bill for %s = %s\n", parkingTicket.Vehicle.GetLicenceNumber(), formattedCharge)

paymentSystem := NewPaymentSystem(charge, parkingTicket)
if err := paymentSystem.ProcessPayment(); err != nil {
return fmt.Errorf("payment failed: %v. Vehicle is still parked", err)
}

parkingTicket.Spot.RemoveVehicle()
parkingTicket.SetTotalCharge(charge)
parkingTicket.SetTicketStatus(Closed)

return nil
}
22 changes: 11 additions & 11 deletions parking_lot/parking_spot.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,25 @@ func NewParkingSpot(spotID int, vehicleType vehicles.VehicleType) *ParkingSpot {
return &ParkingSpot{SpotID: spotID, VehicleType: vehicleType}
}

func (p *ParkingSpot) IsParkingSpotFree() bool {
return p.CurrentVehicle == nil
func (ps *ParkingSpot) IsParkingSpotFree() bool {
return ps.CurrentVehicle == nil
}

func (p *ParkingSpot) ParkVehicle(vehicle vehicles.VehicleInterface) error {
p.lock.Lock()
defer p.lock.Unlock()
func (ps *ParkingSpot) ParkVehicle(vehicle vehicles.VehicleInterface) error {
ps.lock.Lock()
defer ps.lock.Unlock()

if vehicle.GetVehicleType() != p.VehicleType {
return fmt.Errorf("vehicle type mismatch: expected %s, got %s", p.VehicleType, vehicle.GetVehicleType())
if vehicle.GetVehicleType() != ps.VehicleType {
return fmt.Errorf("vehicle type mismatch: expected %s, got %s", ps.VehicleType, vehicle.GetVehicleType())
}
if p.CurrentVehicle != nil {
if ps.CurrentVehicle != nil {
return fmt.Errorf("parking spot already occupied")
}

p.CurrentVehicle = &vehicle
ps.CurrentVehicle = &vehicle
return nil
}

func (p *ParkingSpot) RemoveVehicle() {
p.CurrentVehicle = nil
func (ps *ParkingSpot) RemoveVehicle() {
ps.CurrentVehicle = nil
}
47 changes: 39 additions & 8 deletions parking_lot/parking_ticket.go
Original file line number Diff line number Diff line change
@@ -1,36 +1,67 @@
package main

import (
"fmt"
"lld_go_parking_lot/vehicles"
"time"

"github.com/google/uuid"
)

const baseCharge = 100.00

type TicketStatus string

const (
Active TicketStatus = "ACTIVE"
Closed TicketStatus = "CLOSED"
)

type ParkingTicket struct {
TicketId string
EntryTime time.Time
ExitTime time.Time
ExitTime *time.Time
Vehicle vehicles.VehicleInterface
Spot *ParkingSpot
TotalCharge float64
Status TicketStatus
}

func NewParkingTicket(vehicle vehicles.VehicleInterface, spot *ParkingSpot) *ParkingTicket {
return &ParkingTicket{EntryTime: time.Now(), ExitTime: time.Time{}, Vehicle: vehicle, Spot: spot, TotalCharge: 0.00}
return &ParkingTicket{
TicketId: generateTicketID(),
EntryTime: time.Now(),
Vehicle: vehicle,
Spot: spot,
Status: Active,
}
}

func generateTicketID() string {
return "TICKET-" + uuid.New().String()
}

func (p *ParkingTicket) SetExitTime(exitTime time.Time) {
p.ExitTime = exitTime
p.ExitTime = &exitTime
}

func (p *ParkingTicket) CalculateTotalCharge() float64 {
if p.ExitTime == (time.Time{}) {
p.TotalCharge = baseCharge
return p.TotalCharge
func (p *ParkingTicket) SetTotalCharge(totalCharge float64) {
p.TotalCharge = totalCharge
}

func (p *ParkingTicket) SetTicketStatus(status TicketStatus) {
p.Status = status
}

func (p *ParkingTicket) CalculateTotalCharge() (float64, error) {
if p.ExitTime == nil {
return 0, fmt.Errorf("exit time not set")
}

duration := p.ExitTime.Sub(p.EntryTime)
hours := duration.Hours()
additionalCharge := hours * p.Vehicle.GetVehicleCost()
p.TotalCharge = baseCharge + additionalCharge
return p.TotalCharge

return p.TotalCharge, nil
}