use crate::{
shell,
structs::{CurrentTime, LogEntry, LogEntryEncrypted, Task, TaskEncrypted},
};
use rayon::prelude::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator};
use std::{thread, time::Duration};
fn get_logs_table(key: Vec<u8>) -> Option<Vec<LogEntry>> {
let log_table = LogEntryEncrypted::read_logs(key.clone());
if let Some(logs_table) = log_table.clone() {
Some(logs_table)
} else {
None
}
}
fn get_tasks_table(key: Vec<u8>) -> Option<Vec<Task>> {
let tasks_vec: Vec<Task> = TaskEncrypted::read_db(key.clone());
if tasks_vec.is_empty() {
None
} else {
Some(tasks_vec)
}
}
fn entry_point(key: Vec<u8>) {
loop {
let mut time_sleep: i32 = 3_600;
let logs_table: Option<Vec<LogEntry>> = get_logs_table(key.clone());
let tasks_table: Option<Vec<Task>> = get_tasks_table(key.clone());
if let Some(tasks_table_opt) = tasks_table.clone() {
if let Some(logs_table_opt) = logs_table {
time_sleep = filter_table(tasks_table_opt, Some(logs_table_opt), key.clone());
} else if logs_table.is_none() && tasks_table.is_some() {
time_sleep = filter_table(tasks_table_opt, None, key.clone());
}
}
thread::sleep(Duration::from_secs(time_sleep as u64));
}
}
fn should_execute_now(task: Task) -> bool {
let now = CurrentTime::now();
let mut month: bool = false;
let mut day_of_month: bool = false;
let mut day_of_week: bool = false;
let mut hour: bool = false;
let mut minute: bool = false;
let mut to_execute: bool = true;
if task.month.is_some() {
if task.month.unwrap() == now.month {
month = true;
}
} else if task.month.is_none() {
month = true;
}
if task.day_of_month.is_some() {
if task.day_of_month.unwrap() == now.day_of_month {
day_of_month = true;
}
} else if task.day_of_month.is_none() {
day_of_month = true;
}
if task.day_of_week.is_some() {
if task.day_of_week.unwrap() == now.day_of_week_num {
day_of_week = true;
}
} else if task.day_of_week.is_none() {
day_of_week = true;
}
if task.hour.is_some() {
if task.hour.unwrap() == now.hour {
hour = true;
}
} else if task.hour.is_none() {
hour = true;
}
if task.minute.is_some() {
if task.minute.unwrap() == now.min {
minute = true;
}
} else if task.minute.is_none() {
minute = true;
}
let truth_table = [month, day_of_month, day_of_week, hour, minute];
for time in truth_table {
if time == false {
to_execute = false
}
}
if to_execute {
true
} else {
false
}
}
fn is_daily_task_missed_logged(task: &Task, log: &LogEntry) -> bool {
if task.month.is_none() && task.day_of_month.is_none() && task.day_of_week.is_none() {
if task.hour.is_some() || task.hour.is_some() && task.minute.is_some() {
if log.execution_day_of_month != CurrentTime::now().day_of_month {
return true;
}
}
}
false
}
fn filter_table(tasks_table: Vec<Task>, log_table: Option<Vec<LogEntry>>, key: Vec<u8>) -> i32 {
let mut execution_table: Vec<Task> = Vec::new();
if log_table.is_some() {
let log_table_unwarped = log_table.clone().unwrap();
for task in tasks_table.clone() {
let mut task_in_logs: bool = false;
for log in log_table_unwarped.clone() {
if task.name == Some(log.clone().name) {
task_in_logs = true;
let to_execute = should_execute_now(task.clone());
let daily_missed: bool = is_daily_task_missed_logged(&task, &log);
if to_execute
&& !was_task_executed(&task, &log)
&& !execution_table.contains(&task)
|| daily_missed
{
execution_table.push(task.clone());
}
}
}
if log_table.is_some()
&& !task_in_logs
&& should_execute_now(task.clone())
&& !execution_table.contains(&task)
{
execution_table.push(task.clone());
}
}
}
if log_table.is_none() {
for task in tasks_table.clone() {
let to_execute = should_execute_now(task.clone());
if to_execute && !execution_table.contains(&task) {
execution_table.push(task.clone());
}
}
}
execute_tasks(execution_table.clone(), key);
time_until_next_task(tasks_table)
}
fn time_until_next_task(tasks_table: Vec<Task>) -> i32 {
let mut sleep_month: Option<i32> = None;
let mut sleep_dom: Option<i32> = None;
let mut sleep_dow: Option<i32> = None;
let mut sleep_hour: Option<i32> = None;
let mut sleep_min: Option<i32> = None;
let mut seconds_until_task_cmp: i32 = 64_281_600;
for task in tasks_table {
let mut seconds_until_task: i32 = 0;
let now = CurrentTime::now();
let task_arr = [
task.month,
task.day_of_month,
task.day_of_week,
task.hour,
task.minute,
];
let mut idx: i32 = -1;
for field in task_arr {
idx += 1;
if field.is_some() {
if idx == 0 {
if sleep_month.is_some() {
if sleep_month.unwrap() > task.month.unwrap() {
sleep_month = Some(task.month.unwrap());
}
} else if sleep_month.is_none() {
sleep_month = Some(task.month.unwrap());
}
let month = task.month.unwrap();
if month > now.month {
let time_until_in_month: i32 = month - now.month;
let month_in_secs: i32 = time_until_in_month * 2_628_000;
seconds_until_task += month_in_secs;
} else if month < now.month {
let time_until_month: i32 = 12 - now.month + month;
let month_in_seconds: i32 = time_until_month * 2_628_000;
seconds_until_task += month_in_seconds;
}
} else if idx == 1 {
if sleep_dom.is_some() {
if sleep_dom.unwrap() > task.day_of_month.unwrap() {
sleep_dom = Some(task.day_of_month.unwrap())
}
} else if sleep_dom.is_none() {
sleep_dom = Some(task.day_of_month.unwrap());
}
let dom: i32 = task.day_of_month.unwrap();
if dom > now.day_of_month {
let dom_secs: i32 = dom * 86_400;
seconds_until_task += dom_secs;
} else if dom < now.day_of_month {
let time_until_dom: i32 = 29 - now.day_of_month + dom;
let dom_secs: i32 = time_until_dom * 86_400;
seconds_until_task += dom_secs;
}
} else if idx == 2 {
if sleep_dow.is_some() {
if sleep_dow.unwrap() > task.day_of_week.unwrap() {
sleep_dow = Some(task.day_of_week.unwrap());
}
} else if sleep_dow.is_none() {
sleep_dow = Some(task.day_of_week.unwrap());
}
let dow: i32 = task.day_of_week.unwrap();
if dow > now.day_of_week_num {
let time_until_dow: i32 = dow - now.day_of_week_num;
let dow_secs: i32 = time_until_dow * 86_400;
seconds_until_task += dow_secs;
} else if dow < now.day_of_week_num {
let time_until_dow: i32 = 7 - now.day_of_week_num + dow;
let dow_secs: i32 = time_until_dow * 86_400;
seconds_until_task += dow_secs;
}
} else if idx == 3 {
if sleep_hour.is_some() {
if sleep_hour.unwrap() > task.hour.unwrap() {
sleep_hour = Some(task.hour.unwrap());
}
} else if sleep_hour.is_none() {
sleep_hour = Some(task.hour.unwrap());
}
let hour: i32 = task.hour.unwrap();
if hour > now.hour {
let time_until_hour: i32 = hour - now.hour;
let hour_secs: i32 = time_until_hour * 3_600;
seconds_until_task += hour_secs;
} else if hour < now.hour {
let time_until_hour: i32 = 24 - now.hour + hour;
let hour_secs: i32 = time_until_hour * 36_000;
seconds_until_task += hour_secs;
}
} else if idx == 4 {
if sleep_min.is_some() {
if sleep_min.unwrap() > task.minute.unwrap() {
sleep_min = Some(task.minute.unwrap());
}
} else if sleep_min.is_none() {
sleep_min = Some(task.minute.unwrap());
}
let minute: i32 = task.minute.unwrap();
if minute > now.min {
let time_until_min: i32 = minute - now.min;
let min_secs: i32 = time_until_min * 60;
seconds_until_task += min_secs;
} else if minute < now.min {
let time_until_min: i32 = 60 - now.min + minute;
let min_secs: i32 = time_until_min * 60;
seconds_until_task += min_secs;
}
}
}
}
if seconds_until_task < seconds_until_task_cmp {
seconds_until_task_cmp = seconds_until_task;
}
}
if seconds_until_task_cmp > 3_600 {
3_600
} else if seconds_until_task_cmp == 0 {
60
} else {
seconds_until_task_cmp
}
}
fn was_task_executed(task: &Task, log: &LogEntry) -> bool {
let now = CurrentTime::now();
if task.month == Some(log.execution_month) && Some(log.execution_year) == Some(now.year) {
return true;
} else if task.day_of_month == Some(log.execution_day_of_month)
&& Some(log.execution_week) == Some(now.week)
{
return true;
} else if task.day_of_week == Some(log.execution_day_of_week)
&& Some(log.execution_week) == Some(now.week)
{
return true;
} else if task.hour == Some(log.execution_hour)
&& log.execution_week == now.week
&& log.execution_day_of_month == now.day_of_month
&& log.execution_month == now.month
{
return true;
} else if task.minute == Some(log.execution_minute)
&& log.execution_week == now.week
&& log.execution_day_of_month == now.month
&& log.execution_hour == now.hour
{
return true;
} else {
false
}
}
fn execute_tasks(mut tasks: Vec<Task>, key: Vec<u8>) {
let tasks_iter = tasks.par_iter_mut().enumerate();
tasks_iter.for_each(|task| {
shell::execute_and_log(task.1.to_owned(), key.clone());
let _res
= crate::notify::notify(&task.1.clone().name.unwrap());
});
}
pub fn main_execution_loop(key: Vec<u8>) {
entry_point(key);
}