use std::collections::HashSet;

struct GroupedLines<I> {
    inner: I,
}

impl<I> GroupedLines<I> {
    fn new(inner: I) -> Self {
        GroupedLines { inner: inner }
    }
}

impl<I: Iterator<Item = S>, S: AsRef<str>> Iterator for GroupedLines<I> {
    type Item = Vec<String>;
    fn next(&mut self) -> Option<Self::Item> {
        let mut r = Vec::new();
        loop {
            match self.inner.next() {
                Some(l) => {
                    if l.as_ref().len() == 0 {
                        break;
                    } else {
                        r.push(String::from(l.as_ref()));
                    }
                }
                None => break,
            }
        }
        if r.len() == 0 {
            None
        } else {
            Some(r)
        }
    }
}

fn any_checked(input: Vec<String>) -> HashSet<char> {
    input.iter().flat_map(|l| l.chars()).collect()
}

fn all_checked(input: Vec<String>) -> HashSet<char> {
    let mut i = input.iter();
    match i.next() {
        None => HashSet::new(),
        Some(l0) => {
            let mut r: HashSet<char> = l0.chars().collect();
            for l in i {
                r = r
                    .intersection(&l.chars().collect())
                    .map(Clone::clone)
                    .collect();
            }
            r
        }
    }
}

fn main() {
    use std::env;
    use std::io::BufRead;
    let args: Vec<_> = env::args().collect();
    let counts: usize = GroupedLines::new(
        std::io::BufReader::new(std::fs::File::open(&args[1]).unwrap())
            .lines()
            .map(Result::unwrap),
    )
    .map(match args[2].as_ref() {
        "any" => any_checked,
        "all" => all_checked,
        _ => panic!("No such aggregator"),
    })
    .map(|c| c.len())
    .sum();
    println!("{}", counts);
}