/* * Rohmer Maxime * STD Project * 25/01/2023 * V1.0 * GraphicalStore.cs * The model of the application that setups all the clients and the checkouts while communicating everything to the vue */ using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Caisses { internal class GraphicalStore { public static readonly int[] ATTENDANCE = { 0, 0, 0, 0, 0, 0, 0, 30, 30, 40, 50, 60, 100, 80, 50, 30, 80, 100, 50, 50, 80, 0, 0, 0 }; public int CrossoverTime = 10; private List _checkouts; private List _clients; private int _timeOfTheDayInMinuts; private Random rnd; private int _clientsMultiplier; /// Stats private int _AverageWaitingTime; private int _OpenCheckoutCount; private int _PlacesLeftCount; private List _NotFullCheckouts; private List _WaitingClients; public int AverageWaitingTime { get => _AverageWaitingTime; set => _AverageWaitingTime = value; } public int OpenCheckoutCount { get => _OpenCheckoutCount; set => _OpenCheckoutCount = value; } public int TotalPlacesLeftCount { get => _PlacesLeftCount; set => _PlacesLeftCount = value; } internal List NotFullCheckouts { get => _NotFullCheckouts; set => _NotFullCheckouts = value; } public List WaitingClients { get => _WaitingClients; set => _WaitingClients = value; } /// Stats public int TimeOfTheDayInMinuts { get => _timeOfTheDayInMinuts; set => _timeOfTheDayInMinuts = value; } public List Clients { get => _clients; set => _clients = value; } internal List Checkouts { get => _checkouts; set => _checkouts = value; } public int TimeOfTheDayInHours { get { return _timeOfTheDayInMinuts / 60; } } public int ClientsMultiplier { get => _clientsMultiplier; set => _clientsMultiplier = value; } public GraphicalStore(int startingHour, int checkoutNumber, Size checkoutsRoom) { TimeOfTheDayInMinuts = startingHour * 60; Clients = new List(); Checkouts = new List(); rnd = new Random(); ClientsMultiplier = 1; FillStore(ATTENDANCE[TimeOfTheDayInHours]); populateCheckouts(checkoutsRoom, checkoutNumber); Tick(); } public void populateCheckouts(Size checkoutRoom, int checkoutNumber) { int checkoutWidth = checkoutRoom.Width / checkoutNumber + 1; if (Checkouts.Count > 0) { //We are resizing if (Checkouts.Count > checkoutNumber) { int checkoutsToRemove = Checkouts.Count - checkoutNumber; for (int i = 0; i < checkoutsToRemove; i++) { Checkouts.RemoveAt(Checkouts.Count - 1); } } else { int checkoutsToAdd = checkoutNumber - Checkouts.Count; for (int i = 0; i < checkoutsToAdd; i++) { Checkouts.Add(new GraphicalCheckout()); } } } else { //We are creating for (int i = 0; i < checkoutNumber; i++) { Checkouts.Add(new GraphicalCheckout()); } } } private void RefreshStoreFilling() { if (TimeOfTheDayInMinuts % 60 == 0) { if (TimeOfTheDayInMinuts >= 24 * 60) { TimeOfTheDayInMinuts = 0; } //Its a new Hour so we can send the new clients int amountOfNewCLients = ATTENDANCE[TimeOfTheDayInHours]; FillStore(amountOfNewCLients * ClientsMultiplier); } } public void Tick() { TimeOfTheDayInMinuts++; RefreshStoreFilling(); int cumulatedWaitingTime = 0; int waitingClients = 0; AverageWaitingTime = 0; WaitingClients = new List(); if (NotFullCheckouts == null) NotFullCheckouts = new List(); //Clients that will leave the store List clientsToRemove = new List(); foreach (GraphicalClient client in Clients) { //Tick client.Tick(); // Calculating average waiting time if (Clients.Count == 0 || waitingClients == 0) { AverageWaitingTime = 0; } else { AverageWaitingTime = cumulatedWaitingTime / waitingClients; } //Waiting time incrementation if (Clients.Count != 0 && client.State == Client.ClientState.Waiting) { cumulatedWaitingTime += client.WaitingTime; waitingClients += 1; WaitingClients.Add(client); //Checkout process if (TotalPlacesLeftCount > 0 && NotFullCheckouts.Count > 0) { //Now we select a random one to put our waiting client int index = 0; int count = NotFullCheckouts.Count; if (count > 0) { index = rnd.Next(0, count - 1); } else { index = 0; } if (NotFullCheckouts[index].Clients.Count < Checkout.MAX_CAPACITY) { //We need to check that because a client could have been already added and so the checkout could not have any places left even tho she is listed as not full NotFullCheckouts[index].Clients.Add(client); //Clients.Remove(client); clientsToRemove.Add(client); client.State = Client.ClientState.Inline; } } } } foreach (GraphicalClient client in clientsToRemove) { Clients.Remove(client); } OpenCheckoutCount = 0; TotalPlacesLeftCount = 0; NotFullCheckouts = new List(); foreach (GraphicalCheckout checkout in Checkouts) { //Tick checkout.Tick(this); if (checkout.Open) { //Calculate amount of open Checkouts OpenCheckoutCount++; //Calculate amount of places left int CheckoutPlacesLeft = Checkout.MAX_CAPACITY - checkout.Clients.Count(); TotalPlacesLeftCount += CheckoutPlacesLeft; //Collecting every non full checkout if (CheckoutPlacesLeft > 0) { NotFullCheckouts.Add(checkout); } //Checkout behaviour if (checkout.Clients.Count > 0) { Client cClient = checkout.Clients[0]; if (cClient.State != Client.ClientState.Checkout) cClient.State = Client.ClientState.Checkout; if (cClient.CheckoutTime <= 0) { checkout.Clients.Remove(cClient); //We dont load the next because he should be loaded the next time this function is loaded } foreach (GraphicalClient ccClient in checkout.Clients) { ccClient.Tick(); } } } } } public List Draw(Size shelvesRoom, Size waitRoom, Size checkoutsRoom) { Bitmap shelvesImage = new Bitmap(shelvesRoom.Width, shelvesRoom.Height); Bitmap waitingRoomImage = new Bitmap(waitRoom.Width, waitRoom.Height); Bitmap checkoutsImage = new Bitmap(checkoutsRoom.Width, checkoutsRoom.Height); foreach (GraphicalClient client in Clients) { client.Draw(shelvesImage, waitingRoomImage); } for (int i = 0; i < Checkouts.Count; i++) { Checkouts[i].Draw(checkoutsImage, Checkouts.Count, i); foreach (GraphicalClient client in Checkouts[i].Clients) { client.Draw(shelvesImage, waitingRoomImage); } } /* foreach (GraphicalCheckout checkout in Checkouts) { checkout.Draw(checkoutsImage,Checkouts.Count, ); foreach (GraphicalClient client in checkout.Clients) { client.Draw(shelvesImage,waitingRoomImage); } } */ return new List { shelvesImage, waitingRoomImage, checkoutsImage }; } public virtual void FillStore(int amountOfNewClients) { for (int i = 0; i < amountOfNewClients; i++) { Clients.Add(new GraphicalClient(new Point(0, 0), rnd)); } } public int GetEmptyCheckoutCount() { int result = 0; foreach (GraphicalCheckout checkout in Checkouts) { if (checkout.Open && checkout.Clients.Count == 0) { result += 1; } } return result; } public void AddClients(int amount) { for (int i = 0; i < amount; i++) { Clients.Add(new GraphicalClient(new Point(0, 0), rnd)); } } public void ClearStore() { List clientsToRemove = new List(); foreach (GraphicalClient client in Clients) { if (client.State == Client.ClientState.Shopping) { clientsToRemove.Add(client); } } foreach (GraphicalClient client in clientsToRemove) { Clients.Remove(client); } } public void ClearWaitingRoom() { List clientsToRemove = new List(); foreach (GraphicalClient client in Clients) { if (client.State == Client.ClientState.Waiting) { clientsToRemove.Add(client); } } foreach (GraphicalClient client in clientsToRemove) { Clients.Remove(client); } } public void AddTime(int time) { TimeOfTheDayInMinuts += time; } public void UpdateCheckoutNumber(int newCheckoutNumber, Size checkoutRoom) { populateCheckouts(checkoutRoom, newCheckoutNumber); } public void ChangeClientMultiplier(int newMultiplier) { ClientsMultiplier = newMultiplier; } public void ChangeCrossoverTime(int newCrossoverTime) { CrossoverTime = newCrossoverTime; } } }