use std::sync::{Arc, mpsc, Mutex};
use std::{io, thread};
use std::thread::JoinHandle;

type Job = Box<dyn FnOnce() -> io::Result<()> + 'static + Send>;

enum Message {
    End,
    NewJob(Job),
}


struct Worker {
    _id: usize,
    t: Option<JoinHandle<io::Result<()>>>,
}

impl Worker {
    fn new(id: usize, receiver: Arc::<Mutex<mpsc::Receiver<Message>>>) -> Worker {
        let t = thread::spawn(move || -> io::Result<()> {
            loop {
                match receiver.lock().unwrap().recv().unwrap() {
                    Message::NewJob(job) => {
                        let _ = job();
                    }
                    Message::End => {
                        break Ok(())
                    }
                }
            }
        });
        Worker {
            _id: id,
            t: Some(t),
        }
    }
}

pub struct Pool {
    workers: Vec<Worker>,
    max_workers: usize,
    sender: mpsc::Sender<Message>,
}

impl Pool {
    pub fn new(max_workers: usize) -> Pool {
        if max_workers == 0 {
            println!("max_workers 必须大于0")
        }
        let (tx, rx) = mpsc::channel();
        let mut workers = Vec::with_capacity(max_workers);
        let receiver = Arc::new(Mutex::new(rx));
        for i in 0..max_workers {
            workers.push(Worker::new(i, Arc::clone(&receiver)));
        }
        Pool { workers, max_workers, sender: tx }
    }
    pub fn execute<F>(&self, f: F)
    where
        F: 'static + Send + FnOnce() -> io::Result<()>,
    {
        let job = Message::NewJob(Box::new(f));
        self.sender.send(job).unwrap();
    }
    pub fn end(&mut self) {
        for _ in 0..self.max_workers {
            self.sender.send(Message::End).unwrap();
        }
        for w in &mut self.workers {
            if let Some(t) = w.t.take() {
                let _ = t.join().unwrap();
            }
        }
    }
}