use {io, poll, Evented, Ready, Poll, PollOpt, Token};
use libc;
use magenta;
use magenta::HandleBase;
use sys::fuchsia::{DontDrop, poll_opts_to_wait_async, sys};
use std::mem;
use std::os::unix::io::RawFd;
use std::sync::{Arc, Mutex};

/// Properties of an `EventedFd`'s current registration
#[derive(Debug)]
pub struct EventedFdRegistration {
    token: Token,
    handle: DontDrop<magenta::Handle>,
    rereg_signals: Option<(magenta::Signals, magenta::WaitAsyncOpts)>,
}

impl EventedFdRegistration {
    unsafe fn new(token: Token,
                  raw_handle: sys::mx_handle_t,
                  rereg_signals: Option<(magenta::Signals, magenta::WaitAsyncOpts)>,
                  ) -> Self
    {
        EventedFdRegistration {
            token: token,
            handle: DontDrop::new(magenta::Handle::from_raw(raw_handle)),
            rereg_signals: rereg_signals
        }
    }

    pub fn rereg_signals(&self) -> Option<(magenta::Signals, magenta::WaitAsyncOpts)> {
        self.rereg_signals
    }
}

/// An event-ed file descriptor. The file descriptor is owned by this structure.
#[derive(Debug)]
pub struct EventedFdInner {
    /// Properties of the current registration.
    registration: Mutex<Option<EventedFdRegistration>>,

    /// Owned file descriptor.
    ///
    /// `fd` is closed on `Drop`, so modifying `fd` is a memory-unsafe operation.
    fd: RawFd,

    /// Owned `mxio_t` ponter.
    mxio: *const sys::mxio_t,
}

impl EventedFdInner {
    pub fn rereg_for_level(&self, port: &magenta::Port) {
        let registration_opt = self.registration.lock().unwrap();
        if let Some(ref registration) = *registration_opt {
            if let Some((rereg_signals, rereg_opts)) = registration.rereg_signals {
                let _res =
                    registration
                        .handle.inner_ref()
                        .wait_async(port,
                                    registration.token.0 as u64,
                                    rereg_signals,
                                    rereg_opts);
            }
        }
    }

    pub fn registration(&self) -> &Mutex<Option<EventedFdRegistration>> {
        &self.registration
    }

    pub fn mxio(&self) -> &sys::mxio_t {
        unsafe { &*self.mxio }
    }
}

impl Drop for EventedFdInner {
    fn drop(&mut self) {
        unsafe {
            sys::__mxio_release(self.mxio);
            let _ = libc::close(self.fd);
        }
    }
}

// `EventedInner` must be manually declared `Send + Sync` because it contains a `RawFd` and a
// `*const sys::mxio_t`. These are only used to make thread-safe system calls, so accessing
// them is entirely thread-safe.
//
// Note: one minor exception to this are the calls to `libc::close` and `__mxio_release`, which
// happen on `Drop`. These accesses are safe because `drop` can only be called at most once from
// a single thread, and after it is called no other functions can be called on the `EventedFdInner`.
unsafe impl Sync for EventedFdInner {}
unsafe impl Send for EventedFdInner {}

#[derive(Clone, Debug)]
pub struct EventedFd {
    pub inner: Arc<EventedFdInner>
}

impl EventedFd {
    pub unsafe fn new(fd: RawFd) -> Self {
        let mxio = sys::__mxio_fd_to_io(fd);
        assert!(mxio != ::std::ptr::null(), "FileDescriptor given to EventedFd must be valid.");

        EventedFd {
            inner: Arc::new(EventedFdInner {
                registration: Mutex::new(None),
                fd: fd,
                mxio: mxio,
            })
        }
    }

    fn handle_and_signals_for_events(&self, interest: Ready, opts: PollOpt)
                -> (sys::mx_handle_t, magenta::Signals)
    {
        let epoll_events = ioevent_to_epoll(interest, opts);

        unsafe {
            let mut raw_handle: sys::mx_handle_t = mem::uninitialized();
            let mut signals: sys::mx_signals_t = mem::uninitialized();
            sys::__mxio_wait_begin(self.inner.mxio, epoll_events, &mut raw_handle, &mut signals);

            (raw_handle, signals)
        }
    }

    fn register_with_lock(
        &self,
        registration: &mut Option<EventedFdRegistration>,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt) -> io::Result<()>
    {
        if registration.is_some() {
            return Err(io::Error::new(
                io::ErrorKind::AlreadyExists,
                "Called register on an already registered file descriptor."));
        }

        let (raw_handle, signals) = self.handle_and_signals_for_events(interest, opts);

        let needs_rereg = opts.is_level() && !opts.is_oneshot();

        // If we need to reregister, then each registration should be `oneshot`
        let opts = opts | if needs_rereg { PollOpt::oneshot() } else { PollOpt::empty() };

        let rereg_signals = if needs_rereg {
            Some((signals, poll_opts_to_wait_async(opts)))
        } else {
            None
        };

        *registration = Some(
            unsafe { EventedFdRegistration::new(token, raw_handle, rereg_signals) }
        );

        // We don't have ownership of the handle, so we can't drop it
        let handle = DontDrop::new(unsafe { magenta::Handle::from_raw(raw_handle) });

        let registered = poll::selector(poll)
            .register_fd(handle.inner_ref(), self, token, signals, opts);

        if registered.is_err() {
            *registration = None;
        }

        registered
    }

    fn deregister_with_lock(
        &self,
        registration: &mut Option<EventedFdRegistration>,
        poll: &Poll) -> io::Result<()>
    {
        let old_registration = if let Some(old_reg) = registration.take() {
            old_reg
        } else {
            return Err(io::Error::new(
                io::ErrorKind::NotFound,
                "Called rereregister on an unregistered file descriptor."))
        };

        poll::selector(poll)
            .deregister_fd(old_registration.handle.inner_ref(), old_registration.token)
    }
}

impl Evented for EventedFd {
    fn register(&self,
                poll: &Poll,
                token: Token,
                interest: Ready,
                opts: PollOpt) -> io::Result<()>
    {
        self.register_with_lock(
            &mut *self.inner.registration.lock().unwrap(),
            poll,
            token,
            interest,
            opts)
    }

    fn reregister(&self,
                  poll: &Poll,
                  token: Token,
                  interest: Ready,
                  opts: PollOpt) -> io::Result<()>
    {
        // Take out the registration lock
        let mut registration_lock = self.inner.registration.lock().unwrap();

        // Deregister
        self.deregister_with_lock(&mut *registration_lock, poll)?;

        self.register_with_lock(
            &mut *registration_lock,
            poll,
            token,
            interest,
            opts)
    }

    fn deregister(&self, poll: &Poll) -> io::Result<()> {
        let mut registration_lock = self.inner.registration.lock().unwrap();
        self.deregister_with_lock(&mut *registration_lock, poll)
    }
}

fn ioevent_to_epoll(interest: Ready, opts: PollOpt) -> u32 {
    use event_imp::ready_from_usize;
    const HUP: usize   = 0b01000;

    let mut kind = 0;

    if interest.is_readable() {
        kind |= libc::EPOLLIN;
    }

    if interest.is_writable() {
        kind |= libc::EPOLLOUT;
    }

    if interest.contains(ready_from_usize(HUP)) {
        kind |= libc::EPOLLRDHUP;
    }

    if opts.is_edge() {
        kind |= libc::EPOLLET;
    }

    if opts.is_oneshot() {
        kind |= libc::EPOLLONESHOT;
    }

    if opts.is_level() {
        kind &= !libc::EPOLLET;
    }

    kind as u32
}
