/// <summary> /// Note : the list of events to find is treated as 1 event here /// </summary> public static List <Event> FindCombinedEventsInTimePeriod(DateTimeOffset startStdTime, DateTimeOffset endStdTime, GeoLocation geoLocation, Person person, double precisionInHours, List <EventData> eventDataList) { //get data to instantiate //get start & end times var startTime = new Time(startStdTime, geoLocation); var endTime = new Time(endStdTime, geoLocation); //split time into slices based on precision List <Time> timeList = GetTimeListFromRange(startTime, endTime, precisionInHours); //takes time slices and check if all the events is occurig for each time slice, //the list of events is treated as 1 event here var precalculatedList = GetCalculatedTimeEventOccuringList(eventDataList); //create a new combined event data type (used when extracting events) var combinedEvent = CreateNewEventData(eventDataList); //go through time slices and identify start & end of events //and place them in a event list var eventList = ExtractEventsFromTimeSlices(timeList, precalculatedList, combinedEvent); return(eventList); //----------------------FUNCTIONS-------------------------- //takes time list and checks if event is occurig for each time slice, //and returns it in dictionary list, done in parallel ConcurrentDictionary <Time, bool> GetCalculatedTimeEventOccuringList(List <EventData> combinedEvents) { //time is "key", and "is occuring" is "value" var returnList = new ConcurrentDictionary <Time, bool>(); Parallel.ForEach(timeList, (time, state) => { //check if all events are occuring in this time slice var isEventOccuring = isAllEventsOccuring(time, person, combinedEvents); //add to the dictionary returnList[time] = isEventOccuring; }); return(returnList); } //check if all events are occuring for a time slice bool isAllEventsOccuring(Time timeSlice, Person person, List <EventData> combinedEvents) { //makes sure all the events are occuring for this time slice //else false is returned even if 1 event is not occuring foreach (var _event in combinedEvents) { var isEventOccuring = _event.IsEventOccuring(timeSlice, person); if (isEventOccuring == false) { return(false); } } //if control reaches here, then all events are occuring return(true); } //creates a new event data type for the particular custom search EventData CreateNewEventData(List <EventData> eventDatas) { //if only looking for 1 event, then no need to create a new merged event //just use that event data if (eventDatas.Count == 1) { return(eventDatas[0]); } //but if more than 1, create a merged/combined type var eventName = EventName.CombinedEvent; var description = "Combined event of:\n"; eventDatas.ForEach(eventData => description += $"-{eventData.Name}\n"); //name of each event is added to description var combinedEvent = new EventData(eventName, EventNature.Neutral, description, null, null); //no need tag & calculator since only used visualy return(combinedEvent); } }
/** PUBLIC METHODS **/ /// <summary> /// Get list of events occurig in a time periode for all the /// inputed event types aka "event data" /// Note : Cancelation token caught here /// </summary> public static List <Event> GetEventsInTimePeriod(DateTimeOffset startStdTime, DateTimeOffset endStdTime, GeoLocation geoLocation, Person person, double precisionInHours, List <EventData> eventDataList) { //get data to instantiate muhurtha time period //get start & end times var startTime = new Time(startStdTime, geoLocation); var endTime = new Time(endStdTime, geoLocation); //initialize empty list of event to return List <Event> eventList = new(); //split time into slices based on precision var timeList = GetTimeListFromRange(startTime, endTime, precisionInHours); var sync = new object();//to lock thread access to list //var count = 0; try { Parallel.ForEach(eventDataList, (eventData) => { //get list of occuring events for a sigle event type var eventListForThisEvent = GetListOfEventsByEventDataParallel(eventData, person, timeList); //TODO Progress show code WIP //count++; //double percentDone = ((double)count / (double)eventDataList.Count) * 100.0; //debug print //LogManager.Debug($"\r Completed : {percentDone}%"); //adding to list needs to be synced for thread safety lock (sync) { //add events to main list of event eventList.AddRange(eventListForThisEvent); } }); } //catches only exceptions that idicates that user canceled the calculation (caller lost interest in the result) //since the error is not thrown here, we use InnerException catch (Exception e) when(e.InnerException.GetType() == typeof(OperationCanceledException)) { //log it LogManager.Debug("User canceled event calculation halfway!"); //return empty list return(new List <Event>()); } //return calculated event list return(eventList); }