use std::fmt;

#[derive(Clone, Debug)]
pub struct Square {
    pub col: usize,
    pub row: usize,
}

impl fmt::Display for Square {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let col_name = match &self.col {
            0 => "a",
            1 => "b",
            2 => "c",
            3 => "d",
            4 => "e",
            5 => "f",
            6 => "g",
            7 => "h",
            _ => panic!("Illegal coordinate"),
        };

        write!(f, "{}{}", col_name, self.row + 1)
    }
}

impl PartialEq for Square {
    fn eq(&self, other: &Self) -> bool {
        self.col == other.col && self.row == other.row
    }
}
impl Eq for Square {}

impl Square {
    pub fn from(name: &str) -> Result<Square, &'static str> {
        let name = name.to_lowercase();
        let chars: Vec<char> = name.chars().collect();
        if chars.len() == 2 {
            let col = match chars[0] {
                'a' => 0,
                'b' => 1,
                'c' => 2,
                'd' => 3,
                'e' => 4,
                'f' => 5,
                'g' => 6,
                'h' => 7,
                _ => {
                    return Err("Invalid square definition");
                }
            };
            let row = match chars[1] {
                '1' => 0,
                '2' => 1,
                '3' => 2,
                '4' => 3,
                '5' => 4,
                '6' => 5,
                '7' => 6,
                '8' => 7,
                _ => {
                    return Err("Invalid square definition");
                }
            };
            return Ok(Square { col, row });
        }
        Err("Invalid square definition")
    }
}

// Return size of horizontal gap between start and finish
pub fn step_h(start: &Square, finish: &Square) -> usize {
    if start.col > finish.col {
        start.col - finish.col
    } else {
        finish.col - start.col
    }
}

// Return size of vertical gap between start and finish
pub fn step_v(start: &Square, finish: &Square) -> usize {
    if start.row > finish.row {
        start.row - finish.row
    } else {
        finish.row - start.row
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_square() {
        assert_eq!(Err("Invalid square definition"), Square::from("E"));
        assert_eq!(Err("Invalid square definition"), Square::from("5E"));
        assert_eq!(Err("Invalid square definition"), Square::from("E9"));
        assert_eq!(Err("Invalid square definition"), Square::from("T3"));
        assert_eq!(Ok(Square { col: 0, row: 7 }), Square::from("A8"));
        assert_eq!(Ok(Square { col: 7, row: 0 }), Square::from("H1"));
        assert_eq!(Ok(Square { col: 4, row: 4 }), Square::from("E5"));
    }
}
