open Unix
open Scanf
(* Chargeable interface *)
module type Chargeable = sig
val calculateFare : unit -> float
val calculateFire : unit -> float
end
(* Vehicle abstract class *)
module type Vehicle = sig
val getLicensePlate : unit -> string
val setLicensePlate : string -> unit
val getBaseTime : unit -> int
val setBaseTime : int -> unit
val getTotalParkingTime : unit -> int
val setTotalParkingTime : int -> unit
val toString : unit -> string
end
module Vehicle : Vehicle = struct
let licensePlate = ref ""
let baseTime = ref 0
let totalParkingTime = ref 0
let getLicensePlate () = !licensePlate
let setLicensePlate lp = licensePlate := lp
let getBaseTime () = !baseTime
let setBaseTime bt = baseTime := bt
let getTotalParkingTime () = !totalParkingTime
let setTotalParkingTime tpt = totalParkingTime := tpt
let toString () = ""
end
(* Car class *)
module Car : Vehicle = struct
include Vehicle
let calculateFare () = 500.0
let calculateFire () =
if getTotalParkingTime () <= getBaseTime () then
0.0
else
calculateFare () *. 0.3
let toString () =
"Car [License Plate=" ^ getLicensePlate () ^ ", Base Time=" ^ string_of_int (getBaseTime ()) ^
", Total Parking Time=" ^ string_of_int (getTotalParkingTime ()) ^ ", Fare Fee=" ^
string_of_float (calculateFare ()) ^ ", Fire Fee=" ^ string_of_float (calculateFire ()) ^ "]"
end
(* Motorbike class *)
module Motorbike : Vehicle = struct
include Vehicle
let calculateFare () = 300.0
let calculateFire () =
if getTotalParkingTime () <= getBaseTime () then
0.0
else
calculateFare () *. 0.2
let toString () =
"Motorbike [License Plate=" ^ getLicensePlate () ^ ", Base Time=" ^ string_of_int (getBaseTime ()) ^
", Total Parking Time=" ^ string_of_int (getTotalParkingTime ()) ^ ", Fare Fee=" ^
string_of_float (calculateFare ()) ^ ", Fire Fee=" ^ string_of_float (calculateFire ()) ^ "]"
end
(* Wheelchair class *)
module Wheelchair : Vehicle = struct
include Vehicle
let calculateFare () = 200.0
let calculateFire () =
if getTotalParkingTime () <= getBaseTime () then
0.0
else
calculateFare () *. 0.2
let toString () =
"Wheelchair [License Plate=" ^ getLicensePlate () ^ ", Base Time=" ^ string_of_int (getBaseTime ()) ^
", Total Parking Time=" ^ string_of_int (getTotalParkingTime ()) ^ ", Fare Fee=" ^
string_of_float (calculateFare ()) ^ ", Fire Fee=" ^ string_of_float (calculateFire ()) ^ "]"
end
(* Ticket class *)
module Ticket = struct
let id = ref 0L
let startTime = ref (Unix.time ())
let endTime = ref (Unix.time ())
let vehicle = ref (Obj.magic ())
let setId i = id := i
let setStartTime st = startTime := st
let setVehicle v = vehicle := v
let addVehicle licensePlate =
try
id := Int64.of_float (Unix.time ());
let rec loop () =
print_string "What kind of vehicle: {0-Car, 1-Motobike, 2-Wheelchair, -1-Exit}? ";
let kind = read_int () in
if kind < -1 || kind > 2 then begin
print_string "Invalid vehicle!\n";
loop ()
end else begin
match kind with
| 0 -> vehicle := Car
| 1 -> vehicle := Motorbike
| 2 -> vehicle := Wheelchair
| _ -> ()
end
in
loop ();
let rec parseDate () =
print_string "Input start time (format yyyy-MM-dd hh:mm): ";
let input = read_line () in
try
startTime := Unix.(
let tm = strptime input "%Y-%m-%d %H:%M" in
mktime tm
);
with _ ->
print_string "Invalid start time!\n";
parseDate ()
in
true
with _ ->
print_string "An error occurs!\n";
false
let removeVehicle () =
try
let rec parseDate () =
print_string "Input end time (format yyyy-MM-dd hh:mm): ";
let input = read_line () in
try
endTime := Unix.(
let tm = strptime input "%Y-%m-%d %H:%M" in
mktime tm
);
if !endTime < !startTime then begin
print_string "End time must be after start time!\n";
parseDate ()
end else
true
with _ ->
print_string "Invalid end time!\n";
parseDate ()
in
true
with _ ->
print_string "An error occurs!\n";
false
let getVehicle () = !vehicle
let toString () =
if !endTime = !startTime then begin
let now = Unix.time () in
let diff = now -. !startTime in
let minutes = int_of_float (diff /. 60.0) in
Vehicle.setTotalParkingTime minutes
end;
"Ticket [ID=" ^ Int64.to_string !id ^ ", Start Time=" ^ string_of_float !startTime ^
", End Time=" ^ string_of_float !endTime ^ ", Vehicle=" ^ Vehicle.toString () ^
", Total Fee=" ^ string_of_float (Vehicle.calculateFare () +. Vehicle.calculateFire ()) ^ "]"
let getId () = !id
let getStartTime () = !startTime
let getEndTime () = !endTime
end
(* TicketIterator class *)
module TicketIterator : sig
val hasNext : unit -> bool
val next : unit -> Ticket.t
end = struct
let currentIndex = ref 0
let tickets = ref []
let hasNext () =
while !currentIndex < List.length !tickets do
if List.nth !tickets !currentIndex <> Obj.magic () then
true
else
currentIndex := !currentIndex + 1
done;
false
let next () =
if not (hasNext ()) then
raise Not_found
else
let ticket = List.nth !tickets !currentIndex in
currentIndex := !currentIndex + 1;
ticket
end
(* TicketComparatorByTypeVehicle class *)
module TicketComparatorByTypeVehicle : sig
val compare : Ticket.t -> Ticket.t -> int
end = struct
let compare t1 t2 =
compare (Obj.magic (Ticket.getVehicle t1)) (Obj.magic (Ticket.getVehicle t2))
end
(* TicketComparatorByParkingTime class *)
module TicketComparatorByParkingTime : sig
val compare : Ticket.t -> Ticket.t -> int
end = struct
let compare t1 t2 =
compare (Ticket.getStartTime t1) (Ticket.getStartTime t2)
end
(* ParkingManagementOcaml class *)
module ParkingManagementOcaml = struct
let tickets = ref []
let fileName = "data.csv"
let menu () =
print_string "-------------------MENU-------------------\n";
print_string "1. Vehicle in/out\n";
print_string "2. Print all parking vehicle\n";
print_string "3. Sort tickets by type vehicle\n";
print_string "4. Sort tickets by parking time\n";
print_string "5. Find a vehicle\n";
print_string "6. Save data to file " ^ fileName ^ "\n";
print_string "7. Read data from file " ^ fileName ^ "\n";
print_string "0. Exit!\n";
print_string "Please choose an option: ";
let rec loop () =
try
let option = read_int () in
if option >= 0 && option <= 7 then
option
else
loop ()
with _ ->
print_string "Invalid option!\n";
print_string "Please choose an option: ";
loop ()
in
loop ()
let checkExists licensePlate =
let rec loop index = function
| [] -> -1
| ticket :: tickets ->
if Ticket.getVehicle ticket = licensePlate then
index
else
loop (index + 1) tickets
in
loop 0 !tickets
let parkVehicle () =
try
print_string "Please enter the license plate: ";
let licensePlate = read_line () in
let index = checkExists licensePlate in
if index = -1 then
begin
print_string "Adding new ticket....\n";
let ticket = Ticket.(setId (Int64.of_float (Unix.time ())));
if addVehicle licensePlate then
begin
tickets := ticket :: !tickets;
print_string "Parking vehicle successfully....\n"
end
else
print_string "Fail to add new ticket! Try again!\n"
end
else
begin
print_string "Removing existing ticket....\n";
let ticket = List.nth !tickets index in
tickets := List.filter (fun t -> t <> ticket) !tickets;
if Ticket.removeVehicle ticket then
begin
let diff = Ticket.getEndTime ticket -. Ticket.getStartTime ticket in
let minutes = int_of_float (diff /. 60.0) in
Vehicle.setTotalParkingTime minutes;
print_string "Payment ticket information....\n";
print_string (Ticket.toString ticket ^ "\n")
end
else
begin
print_string "Fail to remove existing ticket! Try again!\n";
tickets := ticket :: !tickets
end
end
with _ ->
print_string "An error occurs!\n"
let printListTicket () =
print_string "-------------------LIST TICKET-------------------\n";
let rec loop = function
| [] -> ()
| ticket :: tickets ->
print_string (Ticket.toString ticket ^ "\n");
loop tickets
in
loop !tickets
let sortTicketByType () =
print_string "Sorting tickets by type increasement.....\n";
tickets := List.sort TicketComparatorByTypeVehicle.compare !tickets;
print_string "List tickets after sorting....\n";
printListTicket ()
let sortTicketByParkingTime () =
print_string "Sorting tickets by parking time increasement.....\n";
tickets := List.sort TicketComparatorByParkingTime.compare !tickets;
print_string "List tickets after sorting....\n";
printListTicket ()
let searchTicket () =
print_string "Searching a ticket by license plate.....\n";
print_string "Enter license plate to search: ";
let licensePlate = read_line () in
let index = checkExists licensePlate in
if index = -1 then
print_string ("Oooops! We can not find the ticket with license plate " ^ licensePlate ^ "\n")
else begin
print_string "The ticket is: \n";
print_string (Ticket.toString (List.nth !tickets index) ^ "\n")
end
let writeCSV () =
let fileWriter = open_out fileName in
let rec loop = function
| [] -> ()
| ticket :: tickets ->
output_string fileWriter (Int64.to_string (Ticket.getId ticket) ^ ",");
output_string fileWriter (string_of_float (Ticket.getStartTime ticket) ^ ",");
output_string fileWriter (string_of_int (if Ticket.getVehicle ticket = Car then 0 else if Ticket.getVehicle ticket = Motorbike then 1 else 2) ^ ",");
output_string fileWriter (Vehicle.getLicensePlate () ^ ",");
output_string fileWriter (string_of_int (Vehicle.getBaseTime ()) ^ "\n");
loop tickets
in
output_string fileWriter "id,startTime,type,licensePlate,baseTime\n";
loop !tickets;
close_out fileWriter;
print_string "Write data to CSV file successfully!\n"
let readCSV () =
tickets := [];
let fileReader = open_in fileName in
let rec loop () =
try
let line = input_line fileReader in
let fields = String.split_on_char ',' line in
let ticket = Ticket.(setId (Int64.of_string (List.nth fields 0));
setStartTime (float_of_string (List.nth fields 1));
let vehicle = match int_of_string (List.nth fields 2) with
| 0 -> Car
| 1 -> Motorbike
| _ -> Wheelchair
in
setVehicle vehicle);
tickets := ticket :: !tickets;
loop ()
with _ -> ()
in
loop ();
close_in fileReader;
print_string "Read data from CSV file successfully!\n"
let run () =
let functions = [
(fun () -> parkVehicle ());
(fun () -> printListTicket ());
(fun () -> sortTicketByType ());
(fun () -> sortTicketByParkingTime ());
(fun () -> searchTicket ());
(fun () -> writeCSV ());
(fun () -> readCSV ());
] in
let rec loop () =
let option = menu () in
if option = 0 then
print_string "Good bye!\n"
else
let runFunction = List.nth functions (option - 1) in
runFunction ();
print_string "------------------------------------------\n";
loop ()
in
loop ()
let main () =
run ()
end
let () = ParkingManagementOcaml.main ()