use ezcad::{
    objects::{hatch::HatchSetting, Object},
    FP,
};
use itertools::Itertools;
use log::debug;
use serde::{Deserialize, Serialize};

use super::double_window_mut;

#[derive(Debug, Serialize, Deserialize)]

pub enum PatternHatchField {
    Count(u32),
    LineSpacing(f64),
    EdgeOffset(f64),
    StartOffset(f64),
    EndOffset(f64),
    Angle(f64),
    RotateAngle(f64),
    LineReduction(f64),
    LoopDistance(f64),
    LoopCount(u32),
}

impl PatternHatchField {
    pub fn pattern(&self, objects: &mut dyn Iterator<Item = (usize, &mut Object)>) {
        let mut objects: Vec<(usize, &mut Object)> = objects.collect_vec();

        double_window_mut(&mut objects[..], |prev, next| {
            let (_prev_idx, prev): (usize, &mut HatchSetting) = match prev.1 {
                Object::Hatch(hatch) => (
                    prev.0,
                    hatch
                        .hatch_settings
                        .iter_mut()
                        .find(|h| h.enabled.into())
                        .expect("Hatch missing enabled setting"),
                ),
                _ => panic!("Object #{} not a hatch object", prev.0),
            };

            let (next_idx, next): (usize, &mut HatchSetting) = match next.1 {
                Object::Hatch(hatch) => (
                    next.0,
                    hatch
                        .hatch_settings
                        .iter_mut()
                        .find(|h| h.enabled.into())
                        .expect("Hatch missing enabled setting"),
                ),
                _ => panic!("Object #{} not a hatch object", next.0),
            };

            match self {
                PatternHatchField::Count(incr) => {
                    let value: u32 = *prev.count + incr;
                    debug!("Patching hatch count for object #{} to {}", next_idx, value);
                    *next.count = value;
                }
                PatternHatchField::LineSpacing(incr) => {
                    let value: f64 = *prev.line_spacing + incr;
                    debug!(
                        "Patching line spacing for object #{} to {:.FP$}",
                        next_idx, value
                    );
                    *next.line_spacing = value;
                }
                PatternHatchField::EdgeOffset(incr) => {
                    let value: f64 = *prev.edge_offset + incr;
                    debug!(
                        "Patching edge offset for object #{} to {:.FP$}",
                        next_idx, value
                    );
                    *next.edge_offset = value;
                }
                PatternHatchField::StartOffset(incr) => {
                    let value: f64 = *prev.start_offset + incr;
                    debug!(
                        "Patching start offset for object #{} to {:.FP$}",
                        next_idx, value
                    );
                    *next.start_offset = value;
                }
                PatternHatchField::EndOffset(incr) => {
                    let value: f64 = *prev.end_offset + incr;
                    debug!(
                        "Patching end offset for object #{} to {:.FP$}",
                        next_idx, value
                    );
                    *next.end_offset = value;
                }
                PatternHatchField::Angle(incr) => {
                    let value: f64 = *prev.angle + incr;
                    debug!("Patching angle for object #{} to {:.FP$}", next_idx, value);
                    *next.angle = value;
                }
                PatternHatchField::RotateAngle(incr) => {
                    let value: f64 = *prev.rotate_angle + incr;
                    debug!(
                        "Patching rotate angle for object #{} to {:.FP$}",
                        next_idx, value
                    );
                    *next.rotate_angle = value;
                }
                PatternHatchField::LineReduction(incr) => {
                    let value: f64 = *prev.line_reduction + incr;
                    debug!(
                        "Patching line reduction for object #{} to {:.FP$}",
                        next_idx, value
                    );
                    *next.line_reduction = value;
                }
                PatternHatchField::LoopDistance(incr) => {
                    let value: f64 = *prev.loop_distance + incr;
                    debug!(
                        "Patching loop distance for object #{} to {:.FP$}",
                        next_idx, value
                    );
                    *next.loop_distance = value;
                }
                PatternHatchField::LoopCount(incr) => {
                    let value: u32 = *prev.loop_count + incr;
                    debug!("Patching loop count for object #{} to {}", next_idx, value);
                    *next.loop_count = value;
                }
            }
        });
    }
}
