Documentation
use core::ops::DerefMut;

use super::*;
use self::OrthogonalAttitude::*;

pub struct Split<Ev: Positional, Surface: Surfacial, A,
                 W: DerefMut<Target = Widget<Ev, Surface, Output = A>>,
                 Ws: DerefMut<Target = [(u32, W)]>, F: Fn() -> A> {
    pub widgets: Ws,
    pub attitude: OrthogonalAttitude,
    pub default: F,
}

pub enum OrthogonalAttitude { Vertical, Lateral, }

impl OrthogonalAttitude {
    pub fn flip(self) -> Self { match self { Vertical => Lateral, Lateral => Vertical, } }
}

impl<Ev: Positional, Surface: Surfacial, A,
     W: DerefMut<Target = Widget<Ev, Surface, Output = A>>,
     Ws: DerefMut<Target = [(u32, W)]>, F: Fn() -> A>
     Widget<Ev, Surface> for Split<Ev, Surface, A, W, Ws, F> {
    type Output = A;
    fn take_event(&self, ev: Ev, size: (u32, u32)) -> A {
        let f = |(x, y)| match self.attitude { Vertical => x, Lateral => y, } as u64;
        let t = self.widgets.iter().map(|&(r, _)|r).sum::<u32>() as u64;
        self.widgets.iter()
            .scan(0, |st, &(r, ref w)| { *st += r; Some((*st as u64, r as u64, w)) })
            .find(|&(s, _, _)| f(size)*s > t*f(ev.pos()))
            .map_or_else(&self.default,
                         |(_, r, w)| w.take_event(ev, {
                                                      let c = |s| ((s as u64)*r/t) as u32;
                                                      match self.attitude {
                                                          Vertical => (c(size.0), size.1),
                                                          Lateral => (size.0, c(size.1)),
                                                      }
                                                  }))
    }
    fn draw(&self, surface: &mut Surface) {
        let t = self.widgets.iter().map(|&(r, _)|r).sum::<u32>() as u64;
        let (w, h) = surface.size();
        let f = |r, b| {
            let c = |s| ((s as u64)*r/t) as u32;
            match self.attitude {
                Vertical => (c(w), if b { 0 } else { h }),
                Lateral => (if b { 0 } else { w }, c(h)),
            }
        };
        self.widgets.iter()
            .scan(0, |st, &(r, ref w)| {
                      let r = r as u64;
                      w.draw(surface.sect_mut(f(*st, false), f(*st + r, true)));
                      *st += r;
                      Some(())
                  }).count();
    }
}