//! e7: method returning Option, accessing multiple fields

use fieldwork_borrow::with_;

pub struct Database {
    pub animations: Vec<Animation>,
}

pub struct Connection {
    pub models: Vec<ModelConnection>,
}

pub struct ModelConnection {
    pub animations: Vec<usize>,
}

pub struct Animation {
    pub objects_curves: Vec<TRSCurves>,
}

pub struct TRSCurves {
    value: f64,
}

impl TRSCurves {
    pub fn sample_at(&self) -> f64 {
        self.value
    }
}

pub struct Viewer {
    db: Database,
    conn: Connection,
    model_id: usize,
    object_mats: Vec<f64>,
}

impl Viewer {
    // Original problem code (won't compile):
    // fn problem(&mut self) {
    //     if let Some(anim) = self.cur_animation() {
    //         for i in 0..self.object_mats.len() {
    //             self.object_mats[i] = anim.objects_curves[i].sample_at();
    //         }
    //     }
    // }

    fn problem(&mut self) {
        with_!(self, {
            methods {
                cur_animation(&db, &conn, copy model_id) -> Option<&Animation> {
                    conn.models[model_id].animations.get(0).map(|&id| &db.animations[id])
                }
            }
            fields {
                mut object_mats
            }
            body {
                if let Some(anim) = self.cur_animation() {
                    for i in 0..object_mats.len() {
                        object_mats[i] = anim.objects_curves[i].sample_at();
                    }
                }
            }
        });
    }

    // Original methods for reference
    fn _cur_animation(&self) -> Option<&Animation> {
        Some(&self.db.animations[self._animation_id()?])
    }

    fn _animation_id(&self) -> Option<usize> {
        Some(self.conn.models[self.model_id].animations[0])
    }
}

#[test]
fn test_e7() {
    let mut viewer = Viewer {
        db: Database {
            animations: vec![Animation {
                objects_curves: vec![
                    TRSCurves { value: 1.0 },
                    TRSCurves { value: 2.0 },
                ],
            }],
        },
        conn: Connection {
            models: vec![ModelConnection {
                animations: vec![0], // points to animations[0]
            }],
        },
        model_id: 0,
        object_mats: vec![0.0, 0.0],
    };

    viewer.problem();

    assert_eq!(viewer.object_mats, vec![1.0, 2.0]);
}
