use std::{
collections::HashMap,
fs::File,
io::{Read, Write},
sync::{Arc, OnceLock},
thread::spawn,
};
use eframe::egui::{
self, mutex::RwLock, vec2, Button, Color32, Frame, Label, RichText, Stroke, Vec2,
};
use egui_flex::{item, Flex, FlexInstance};
use serde::{Deserialize, Serialize};
use crate::{
tabs::{
activities::{
activities, acts_frames, get_classes_name, get_teachers_name, partnered_act,
teachers_acts_hours, Activity,
},
classes::{classes_acts, get_classes, selected_class},
generating::{available_days, create_available_days, data, Schedule, TimetableData},
get_school, school_hour,
teachers::{get_teachers, selected_teacher, teachers_acts},
SubPage,
},
DAYS,
};
use super::get_page;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ClassLimitation {
pub class_id: i32,
pub limitations: Vec<Vec<bool>>,
}
impl ClassLimitation {
pub fn new(id: i32) -> Self {
let hour = school_hour().read().parse::<usize>().unwrap_or(8);
Self {
class_id: id,
limitations: vec![vec![true; hour]; 7],
}
}
fn validation(&mut self) {
let hour = &*school_hour().read();
let hour = hour.parse::<usize>().unwrap_or(8);
while self.limitations.len() > 7 {
self.limitations.pop();
}
while self.limitations.len() < 7 {
self.limitations.push(vec![true; hour]);
}
self.limitations.iter_mut().for_each(|l| {
while l.len() > hour {
l.pop();
}
while l.len() < hour {
l.push(true);
}
})
}
}
pub fn classes_volumes() -> &'static Arc<RwLock<HashMap<i32, Vec<Vec<i32>>>>> {
static PAGE: OnceLock<Arc<RwLock<HashMap<i32, Vec<Vec<i32>>>>>> = OnceLock::new();
PAGE.get_or_init(|| Arc::new(RwLock::new(create_classes_volumes())))
}
fn create_classes_volumes() -> HashMap<i32, Vec<Vec<i32>>> {
let clss = get_classes().read();
let s_hour = get_school().read().hour;
let acts = classes_acts().read().clone();
let mut map = HashMap::new();
for c in &*clss {
let c_acts = acts.get(c.0).unwrap();
let mut days = vec![];
for day in DAYS.iter().enumerate() {
let mut hours = vec![0; s_hour as usize];
for act in c_acts {
let h_lim = s_hour - act.hour + 1;
for h in 0..h_lim as usize {
if act.hour + h <= s_hour
&& act.classes_available(h, day.0)
&& act.teachers_available(h, day.0)
{
(0..act.hour).for_each(|hh| hours[h + hh as usize] += 1);
}
}
}
days.push(hours);
}
map.insert(*c.0 as i32, days);
}
map
}
pub fn teachers_volumes() -> &'static Arc<RwLock<HashMap<i32, Vec<Vec<i32>>>>> {
static PAGE: OnceLock<Arc<RwLock<HashMap<i32, Vec<Vec<i32>>>>>> = OnceLock::new();
PAGE.get_or_init(|| Arc::new(RwLock::new(create_teachers_volumes())))
}
fn create_teachers_volumes() -> HashMap<i32, Vec<Vec<i32>>> {
let teachers = get_teachers().read();
let s_hour = get_school().read().hour;
let acts = teachers_acts().read().clone();
let mut map = HashMap::new();
for t in &*teachers {
let t_acts = acts.get(t.0).unwrap();
let mut days = vec![];
for day in DAYS.iter().enumerate() {
let mut hours = vec![0; s_hour as usize];
for h in 0..s_hour as usize {
for act in t_acts {
if act.hour + h <= s_hour
&& act.classes_available(h, day.0)
&& act.teachers_available(h, day.0)
{
hours[h] += 1;
}
}
}
days.push(hours);
}
map.insert(*t.0 as i32, days);
}
map
}
pub fn schedules() -> &'static Arc<RwLock<Vec<Schedule>>> {
static PAGE: OnceLock<Arc<RwLock<Vec<Schedule>>>> = OnceLock::new();
PAGE.get_or_init(|| Arc::new(RwLock::new(vec![])))
}
pub fn classes_limitations() -> &'static Arc<RwLock<HashMap<i32, ClassLimitation>>> {
static PAGE: OnceLock<Arc<RwLock<HashMap<i32, ClassLimitation>>>> = OnceLock::new();
PAGE.get_or_init(|| Arc::new(RwLock::new(get_class_limitations())))
}
pub fn get_class_limitations() -> HashMap<i32, ClassLimitation> {
let lims = File::open("./db/classes_limitations.json");
if let Ok(mut lims) = lims {
let mut content: String = String::new();
lims.read_to_string(&mut content).unwrap();
let mut cls: Vec<ClassLimitation> = serde_json::from_str(content.as_str()).unwrap();
cls.iter_mut().for_each(|l| l.validation());
let mut lims: HashMap<i32, ClassLimitation> = HashMap::new();
for c in cls {
lims.insert(c.class_id, c);
}
return lims;
} else {
let mut lims: HashMap<i32, ClassLimitation> = HashMap::new();
for c in &*get_classes().read() {
lims.insert(c.1.id, ClassLimitation::new(c.1.id));
}
return lims;
}
}
type ClassSched = Arc<RwLock<HashMap<i32, Vec<Vec<Option<Activity>>>>>>;
pub fn classes_sched() -> &'static ClassSched {
static ACT: OnceLock<ClassSched> = OnceLock::new();
ACT.get_or_init(|| Arc::new(RwLock::new(create_classes_sched())))
}
fn get_class_scheds(id: i32) -> Vec<Vec<Option<Activity>>> {
let scheds = &*classes_sched().read();
let scheds = scheds.get(&id);
if let Some(scheds) = scheds {
return scheds.clone();
} else {
create_classes_sched();
return get_class_scheds(id);
}
}
fn get_class_lims(id: i32) -> Vec<Vec<bool>> {
let lims = classes_limitations().read();
let lims = lims.get(&id);
if let Some(lims) = lims {
return lims.limitations.clone();
} else {
std::thread::spawn(move || {
classes_limitations()
.write()
.insert(id, ClassLimitation::new(id));
});
return get_class_lims(id);
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct TeacherLimitation {
pub teacher_id: i32,
pub limitations: Vec<Vec<bool>>,
}
impl TeacherLimitation {
pub fn new(id: i32) -> Self {
let hour = school_hour().read().parse::<usize>().unwrap_or(8);
Self {
teacher_id: id,
limitations: vec![vec![true; hour]; 7],
}
}
fn validation(&mut self) {
let hour = &*school_hour().read();
let hour = hour.parse::<usize>().unwrap_or(8);
while self.limitations.len() > 7 {
self.limitations.pop();
}
while self.limitations.len() < 7 {
self.limitations.push(vec![true; hour]);
}
self.limitations.iter_mut().for_each(|l| {
while l.len() > hour {
l.pop();
}
while l.len() < hour {
l.push(true);
}
})
}
}
fn get_teacher_lims(id: i32) -> Vec<Vec<bool>> {
let lims = teachers_limitations().read();
let lims = lims.get(&id);
if let Some(lims) = lims {
return lims.limitations.clone();
} else {
let lims = TeacherLimitation::new(id);
let lims2 = lims.clone();
std::thread::spawn(move || {
teachers_limitations().write().insert(id, lims2);
});
return lims.limitations;
}
}
pub fn teachers_limitations() -> &'static Arc<RwLock<HashMap<i32, TeacherLimitation>>> {
static PAGE: OnceLock<Arc<RwLock<HashMap<i32, TeacherLimitation>>>> = OnceLock::new();
PAGE.get_or_init(|| Arc::new(RwLock::new(get_teacher_limitations())))
}
pub fn get_teacher_limitations() -> HashMap<i32, TeacherLimitation> {
let lims = File::open("./db/teachers_limitations.json");
if let Ok(mut lims) = lims {
let mut content: String = String::new();
lims.read_to_string(&mut content).unwrap();
let mut cls: Vec<TeacherLimitation> = serde_json::from_str(content.as_str()).unwrap();
cls.iter_mut().for_each(|l| l.validation());
let mut lims: HashMap<i32, TeacherLimitation> = HashMap::new();
for c in cls {
lims.insert(c.teacher_id, c);
}
return lims;
} else {
let tchrs = get_teachers().read();
let mut lims: HashMap<i32, TeacherLimitation> = HashMap::new();
for t in &*tchrs {
lims.insert(t.1.id, TeacherLimitation::new(t.1.id));
}
return lims;
}
}
type TeacherSched = Arc<RwLock<HashMap<i32, Vec<Vec<Option<Activity>>>>>>;
pub fn teachers_scheds() -> &'static TeacherSched {
static ACT: OnceLock<TeacherSched> = OnceLock::new();
ACT.get_or_init(|| Arc::new(RwLock::new(create_teachers_sched())))
}
fn get_teacher_scheds(id: i32) -> Vec<Vec<Option<Activity>>> {
let scheds = teachers_scheds().read();
let scheds = scheds.get(&id);
if let Some(scheds) = scheds {
return scheds.clone();
} else {
create_teachers_sched();
return get_teacher_scheds(id);
}
}
fn _update_teacher_limitation() {
}
pub fn limitations_ui(ui: &mut egui::Ui) {
let page = &*get_page().read();
let acts = if let SubPage::Teachers = page {
let id = selected_teacher().read().unwrap_or(1);
let activities = teachers_acts().read().clone();
let act = activities.get(&id).unwrap();
act.clone()
} else {
let id = selected_class().read().unwrap_or(1);
let activities = classes_acts().read().clone();
let act = activities.get(&id).unwrap();
act.clone()
};
match page {
super::SubPage::Teachers => {
if let Some(teacher_id) = *selected_teacher().read() {
ui.set_width(1024.);
Flex::vertical()
.gap(Vec2::new(0., 0.))
.show(ui, |flex| {
flex.add(
item(),
Label::new(
RichText::new(format!(
"{}: {} saat",
get_teachers_name(&[teacher_id]),
teachers_acts_hours()
.read()
.clone()
.get(&teacher_id)
.unwrap()
))
.size(24.),
),
);
flex.add_ui(item(), |ui| ui.add_space(10.));
hours_frame(flex);
days_frame(
flex,
get_teacher_lims(teacher_id),
get_teacher_scheds(teacher_id),
teachers_volumes().read().get(&teacher_id).unwrap(),
);
flex.add_ui(item(), |ui| ui.add_space(10.));
flex.add_ui(item(), |ui| {
ui.horizontal(|ui| {
if ui
.add_sized(Vec2::new(150., 50.), Button::new("Kaydet"))
.clicked()
{
save_teachers_limitations();
}
if ui
.add_sized(Vec2::new(150., 50.), Button::new("Tümüne Uygula"))
.clicked()
{
change_all();
}
});
});
});
} else {
ui.label("Sol listeden seçim yapın");
}
}
super::SubPage::Classes => {
if let Some(class_id) = *selected_class().read() {
ui.set_width(1024.);
Flex::vertical()
.gap(Vec2::new(0., 0.))
.show(ui, |flex| {
flex.add(
item().grow(1.),
Label::new(RichText::new(get_classes_name(&[class_id])).size(24.)),
);
flex.add_ui(item(), |ui| ui.add_space(10.));
hours_frame(flex);
days_frame(
flex,
get_class_lims(class_id),
get_class_scheds(class_id),
classes_volumes().read().get(&class_id).unwrap(),
);
flex.add_ui(item(), |ui| ui.add_space(10.));
flex.add_ui(item(), |ui| {
ui.horizontal(|ui| {
if ui
.add_sized(Vec2::new(150., 50.), Button::new("Kaydet"))
.clicked()
{
save_classes_limitations();
}
if ui
.add_sized(Vec2::new(150., 50.), Button::new("Tümüne Uygula"))
.clicked()
{
change_all();
}
});
});
});
} else {
ui.label("Sol listeden seçim yapın");
}
}
}
acts_frames(ui, &acts);
}
fn hours_frame(flex: &mut FlexInstance) {
let hour = school_hour().read().parse::<usize>().unwrap_or(8);
let frame = Frame::none().stroke(Stroke::new(1., Color32::LIGHT_GRAY));
flex.add_flex(
item().grow(1.),
Flex::horizontal().gap(vec2(0., 0.)),
|flex| {
flex.add_flex(item().frame(frame), Flex::new(), |flex| {
flex.add_ui(item(), |ui| {
ui.add_sized(Vec2::new(100., 50.), Label::new("Günler ve Saatler"));
});
});
for i in 0..hour {
flex.add_flex(item().frame(frame), Flex::new(), |flex| {
flex.add_ui(item(), |ui| {
if ui
.add_sized(Vec2::new(100., 50.), Label::new((i + 1).to_string()))
.clicked()
{
change_all_hours(i);
};
})
});
}
},
);
}
fn days_frame(
flex: &mut FlexInstance,
_lims: Vec<Vec<bool>>,
_scheds: Vec<Vec<Option<Activity>>>,
vol: &Vec<Vec<i32>>,
) {
let hour = school_hour().read().parse::<usize>().unwrap_or(8);
let frame = Frame::none().stroke(Stroke::new(1., Color32::LIGHT_GRAY));
for (index, day) in DAYS.iter().enumerate() {
flex.add_flex(item(), Flex::horizontal().gap(Vec2::splat(0.)), |flex| {
flex.add_flex(item().frame(frame), Flex::new(), |flex| {
flex.add_ui(item(), |ui| {
if ui
.add_sized(Vec2::new(100., 50.), Label::new(*day))
.clicked()
{
change_all_day(index);
};
});
});
for i in 0..hour {
let v: u8 = if vol[index][i] > 100 {
100
} else {
vol[index][i] as u8
};
let f_color = if _lims[index][i] {
Color32::from_rgb(50 + v * 2, 0, 0)
} else {
Color32::default()
};
let frame = Frame::none()
.stroke(Stroke::new(1., Color32::LIGHT_GRAY))
.fill(f_color);
flex.add_flex(item().grow(1.).frame(frame), Flex::vertical(), |ui| {
ui.add_ui(item(), |ui| {
ui.visuals_mut().widgets.inactive.bg_fill = egui::Color32::TRANSPARENT;
let (_, payl) = ui.dnd_drop_zone::<Activity, ()>(Frame::none(), |ui| {
sched_act(ui, &_scheds[index][i], index, i)
});
if let Some(p) = payl {
if p.teachers_available(i, index) && p.classes_available(i, index) {
std::thread::spawn(move || {
if let Some(p_id) = partnered_act().read().get(&p.id) {
let a = activities().read();
let a = a.get(p_id).unwrap();
data().write().put_act(index, i, &a.clone(), false);
} else {
data().write().put_act(index, i, &p.clone(), false);
}
data().write().replace_act(index, i, p.id, p.hour);
});
}
}
});
});
}
});
}
}
pub fn create_teachers_sched() -> HashMap<i32, Vec<Vec<Option<Activity>>>> {
let mut t_scheds = HashMap::new();
let acts = activities().read().clone();
let p_acts = partnered_act().read().clone();
for teacher in &*get_teachers().read() {
let mut teacher_acts = activities()
.read()
.iter()
.filter(|a| a.1.teachers.iter().any(|c| c == &teacher.1.id))
.map(|a| a.1.clone())
.collect::<Vec<Activity>>();
let p_ids = p_acts
.iter()
.filter(|pa| teacher_acts.iter().any(|ta| pa.0 == &ta.id))
.map(|pa| pa.1.clone())
.collect::<Vec<i32>>();
for p_id in p_ids {
if let Some(act) = acts.get(&p_id) {
teacher_acts.push(act.clone());
}
}
let scs = (*schedules().read()).clone();
let sched = scs
.iter()
.filter(|s| teacher_acts.iter().any(|a| a.id == s.activity))
.map(|s| s.clone())
.collect::<Vec<Schedule>>();
let mut scheduls: Vec<Vec<Option<Activity>>> =
vec![vec![None; get_school().read().hour as usize]; 7];
sched.iter().for_each(|s| {
scheduls[s.day_id][s.hour as usize] = teacher_acts
.clone()
.into_iter()
.find(|ca| ca.id == s.activity);
});
let t = teacher.1.clone();
t_scheds.insert(t.id, scheduls);
}
t_scheds
}
pub fn create_classes_sched() -> HashMap<i32, Vec<Vec<Option<Activity>>>> {
let mut t_scheds = HashMap::new();
for class in &*get_classes().read() {
let class_acts = activities()
.read()
.iter()
.filter(|a| a.1.classes.iter().any(|c| c == &class.1.id))
.map(|a| a.1.clone())
.collect::<Vec<Activity>>();
let scs = (*schedules().read()).clone();
let sched = scs
.iter()
.filter(|s| class_acts.iter().any(|a| a.id == s.activity))
.map(|s| s.clone())
.collect::<Vec<Schedule>>();
let mut scheduls: Vec<Vec<Option<Activity>>> =
vec![vec![None; get_school().read().hour as usize]; 7];
sched.iter().for_each(|s| {
scheduls[s.day_id][s.hour as usize] = class_acts
.clone()
.into_iter()
.find(|ca| ca.id == s.activity);
});
let t = class.1.clone();
t_scheds.insert(t.id, scheduls);
}
t_scheds
}
fn sched_act(ui: &mut egui::Ui, a: &Option<Activity>, index: usize, i: usize) {
let Some(a) = a else {
if ui
.add_sized(Vec2::new(100., 50.), Label::new(""))
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
change_row(index, i);
};
return ();
};
let rtext = RichText::new(&a.lectures_name()).size(12.).strong();
if ui
.add_sized(Vec2::new(100., 15.), Label::new(rtext))
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
change_row(index, i);
};
match *get_page().read() {
SubPage::Teachers => {
let rtext = RichText::new(&a.classes_name()).size(16.).strong();
if ui
.add_sized(vec2(100., 20.), Label::new(rtext))
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
change_row(index, i);
};
}
SubPage::Classes => {
let rtext = RichText::new(&a.teachers_short_name()).size(10.).strong();
if ui
.add_sized(vec2(100., 15.), Label::new(rtext))
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
change_row(index, i);
};
}
}
ui.horizontal(|ui| {
let rtext = RichText::new("🗑").size(16.).strong();
if ui
.add_sized(Vec2::new(45., 15.), Label::new(rtext))
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
del_tt(a.id);
};
let color = if is_lock_tt(a.id) {
Color32::BLUE
} else {
Color32::GRAY
};
let ltext = RichText::new("🔒").size(16.).color(color).strong();
if ui
.add_sized(Vec2::new(45., 15.), Label::new(ltext))
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
lock_tt(a.id);
};
});
}
fn lock_tt(act_id: i32) {
std::thread::spawn(move || {
let dt: &mut TimetableData = &mut *data().write();
let scheds = &mut dt.timetables;
let sched = scheds.get_mut(&act_id);
if let Some(tt) = sched {
tt.iter_mut().for_each(|t| t.locked = !t.locked);
}
update_tt();
});
}
fn del_tt(act_id: i32) {
std::thread::spawn(move || {
let dt: &mut TimetableData = &mut *data().write();
let scheds = &mut dt.timetables;
let sched = scheds.remove(&act_id);
update_tt();
});
}
pub fn update_tt() {
std::thread::spawn(move || {
let dt: &mut TimetableData = &mut *data().write();
let scheds = &mut dt.timetables;
let mut sch = vec![];
scheds.values().for_each(|tt| sch.append(&mut tt.clone()));
*schedules().write() = sch.clone();
*classes_sched().write() = create_classes_sched();
*teachers_scheds().write() = create_teachers_sched();
*classes_volumes().write() = create_classes_volumes();
*teachers_volumes().write() = create_teachers_volumes();
});
}
fn is_lock_tt(act_id: i32) -> bool {
let scheds: &Vec<Schedule> = &*schedules().write();
let sched = scheds.iter().find(|a| a.activity == act_id);
if let Some(tt) = sched {
return tt.locked;
}
return false;
}
fn change_all_day(day: usize) {
std::thread::spawn(move || {
let page = &*get_page().read();
match page {
super::SubPage::Teachers => {
let lims = &*teachers_limitations();
let lim = Arc::clone(lims);
std::thread::spawn(move || {
let lims = &mut lim.write();
let day = &mut lims
.get_mut(&selected_teacher().read().unwrap())
.unwrap()
.limitations[day];
if day.iter().any(|h| !*h) {
*day = vec![true; 10];
} else {
*day = vec![false; 10];
}
});
}
super::SubPage::Classes => {
let lims = &*classes_limitations();
let lim = Arc::clone(lims);
std::thread::spawn(move || {
let lims = &mut lim.write();
let day = &mut lims
.get_mut(&selected_class().read().unwrap())
.unwrap()
.limitations[day];
if day.iter().any(|h| !*h) {
*day = vec![true; 10];
} else {
*day = vec![false; 10];
}
});
}
}
});
}
fn change_all_hours(hour: usize) {
std::thread::spawn(move || {
let page = &*get_page().read();
match page {
super::SubPage::Teachers => {
let lims = &*teachers_limitations();
let lim = Arc::clone(lims);
std::thread::spawn(move || {
let lims = &mut lim.write();
let lims = &mut lims
.get_mut(&selected_teacher().read().unwrap())
.unwrap()
.limitations;
if lims.iter().any(|h| !h[hour]) {
lims.iter_mut().for_each(|d| d[hour] = true);
} else {
lims.iter_mut().for_each(|d| d[hour] = false);
}
});
}
super::SubPage::Classes => {
let lims = &*classes_limitations();
let lim = Arc::clone(lims);
std::thread::spawn(move || {
let lims = &mut lim.write();
let lims = &mut lims
.get_mut(&selected_class().read().unwrap())
.unwrap()
.limitations;
if lims.iter().any(|h| !h[hour]) {
lims.iter_mut().for_each(|d| d[hour] = true);
} else {
lims.iter_mut().for_each(|d| d[hour] = false);
}
});
}
}
});
}
pub fn save_teachers_limitations() {
spawn(move || {
let lims = &*teachers_limitations().read();
let lims = lims.values().collect::<Vec<&TeacherLimitation>>();
let mut f = File::create("./db/teachers_limitations.json").unwrap();
f.write_all(serde_json::to_string(&lims).unwrap().as_bytes())
.unwrap();
*available_days().write() = create_available_days();
});
}
pub fn save_classes_limitations() {
let lims = &*classes_limitations().read();
let lims = lims.values().collect::<Vec<&ClassLimitation>>();
let mut f = File::create("./db/classes_limitations.json").unwrap();
f.write_all(serde_json::to_string(&lims).unwrap().as_bytes())
.expect("Sınıf Kısıtları Yazılamadı");
}
fn change_row(day: usize, hour: usize) {
std::thread::spawn(move || {
let page = &*get_page().read();
match page {
SubPage::Teachers => {
let c_id = selected_teacher().read().unwrap();
let mut lims = teachers_limitations().write();
let row = lims.get_mut(&c_id);
if let Some(r) = row {
r.limitations[day][hour] = !r.limitations[day][hour];
}
}
SubPage::Classes => {
let c_id = selected_class().read().unwrap();
let mut lims = classes_limitations().write();
let row = lims.get_mut(&c_id);
if let Some(r) = row {
r.limitations[day][hour] = !r.limitations[day][hour];
}
}
}
});
}
fn change_all() {
let page = get_page();
match &*page.read() {
SubPage::Teachers => {
change_all_teachers();
}
SubPage::Classes => {
change_all_classes();
}
}
}
fn change_all_teachers() {
let t_id = selected_teacher().read().unwrap();
let teachers_lims = teachers_limitations().read().clone();
let t_lims = teachers_lims.get(&t_id).unwrap().clone();
std::thread::spawn(move || {
let t_lims = t_lims.clone();
let teachers = &*get_teachers().read();
for t in teachers {
let lims = &mut *teachers_limitations().write();
if let Some(lims) = lims.get_mut(&t.1.id) {
lims.limitations = t_lims.limitations.clone();
}
}
});
}
fn change_all_classes() {
let c_id = selected_class().read().unwrap();
let classes_lims = classes_limitations().read().clone();
let c_lims = classes_lims.get(&c_id).unwrap().clone();
std::thread::spawn(move || {
let c_lims = c_lims.clone();
let classes = &*get_classes().read();
for c in classes {
let lims = &mut *classes_limitations().write();
if let Some(lims) = lims.get_mut(&c.1.id) {
lims.limitations = c_lims.limitations.clone();
}
}
});
}