use std::io;
use std::io::BufRead;
use std::str::FromStr;

struct Point {
    x: usize,
    y: usize
}

struct Claim {
    id: i16,
    origin: Point,
    size: Point
}

impl FromStr for Claim {
    type Err = std::num::ParseIntError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let bytes = s.as_bytes();
        let mut cursor = 1;
        let mut idx = 1;

        while bytes[idx].is_ascii_digit() { idx += 1; }
        let id = s[cursor..idx].parse()?;

        idx = idx + 3;
        cursor = idx;
        while bytes[idx].is_ascii_digit() { idx += 1; }
        let ox = s[cursor..idx].parse()?;

        idx = idx + 1;
        cursor = idx;
        while bytes[idx].is_ascii_digit() { idx += 1; }
        let oy = s[cursor..idx].parse()?;

        idx = idx + 2;
        cursor = idx;
        while bytes[idx].is_ascii_digit() { idx += 1; }
        let sx = s[cursor..idx].parse()?;

        let sy = s[idx+1..].parse()?;

        Ok(Claim {
            id: id,
            origin: Point {x: ox, y: oy},
            size: Point {x: sx, y: sy}
        })
    }
}

pub fn main<T: BufRead>(reader: T) -> io::Result<(String, String)> {
    let w = 1000;
    let maxnum = 1500;

    let mut sheet: Vec<i16> = vec![0; w * w];
    let mut double: i64 = 0;
    let mut free: Vec<bool> = vec![false; maxnum as usize];

    for line in reader.lines() {
        let claim = line.unwrap().parse::<Claim>().unwrap();
        assert!(0 < claim.id && claim.id < maxnum);

        free[claim.id as usize] = true;

        for y in claim.origin.y .. claim.origin.y + claim.size.y {
            for x in claim.origin.x .. claim.origin.x + claim.size.x {
                let val = sheet[w * y + x];
                if val > 0 {
                    free[val as usize] = false;
                    free[claim.id as usize] = false;
                    double += 1;
                    sheet[w * y + x] = -1;
                } else if val == 0 {
                    sheet[w * y + x] = claim.id;
                } else {
                    free[claim.id as usize] = false;
                }
            }
        }
    }

    let part1 = double;

    for i in 1 .. maxnum as usize {
        if free[i] {
            return Ok((part1.to_string(), i.to_string()));
        }
    }

    Err(io::Error::new(io::ErrorKind::Other, "Invalid input"))
}