use std::io::{Cursor, SeekFrom, Seek};
use byteorder::{NativeEndian, ReadBytesExt};
use defs::{Header, SkylaneError, Task};
use object::{Object, ObjectId};
use bundle::{Bundle, BundleInternal};
use sockets::Socket;
pub struct Controller {
    bundle: Bundle,
}
impl Controller {
        fn new(bundle: Bundle) -> Self {
        Controller {
            bundle: bundle,
        }
    }
        pub fn get_socket(&self) -> Socket {
        self.bundle.get_socket()
    }
                pub fn get_next_available_client_object_id(&self) -> ObjectId {
        self.bundle.get_next_available_client_object_id()
    }
                pub fn get_next_available_server_object_id(&self) -> ObjectId {
        self.bundle.get_next_available_server_object_id()
    }
                pub fn add_object(&mut self, id: ObjectId, object: Box<Object>) {
        self.bundle.add_object(id, object);
    }
                pub fn add_next_client_object(&mut self, object: Box<Object>) -> ObjectId {
        self.bundle.add_next_client_object(object)
    }
                pub fn add_next_server_object(&mut self, object: Box<Object>) -> ObjectId {
        self.bundle.add_next_server_object(object)
    }
}
impl Clone for Controller {
    fn clone(&self) -> Self {
        Controller::new(self.bundle.duplicate())
    }
}
pub struct Connection {
    bundle: Bundle,
}
impl Connection {
        pub fn new(socket: Socket) -> Connection {
        Connection {
            bundle: Bundle::new(socket),
        }
    }
        pub fn get_socket(&self) -> Socket {
        self.bundle.get_socket()
    }
        pub fn get_controller(&self) -> Controller {
        Controller::new(self.bundle.duplicate())
    }
                pub fn get_next_available_client_object_id(&self) -> ObjectId {
        self.bundle.get_next_available_client_object_id()
    }
                pub fn get_next_available_server_object_id(&self) -> ObjectId {
        self.bundle.get_next_available_server_object_id()
    }
                pub fn add_object(&mut self, id: ObjectId, object: Box<Object>) {
        self.bundle.add_object(id, object);
    }
                pub fn add_next_client_object(&mut self, object: Box<Object>) -> ObjectId {
        self.bundle.add_next_client_object(object)
    }
                pub fn add_next_server_object(&mut self, object: Box<Object>) -> ObjectId {
        self.bundle.add_next_server_object(object)
    }
                pub fn remove_object(&mut self, id: ObjectId) {
        self.bundle.remove_object(id);
    }
        pub fn process_events(&mut self) -> Result<(), SkylaneError> {
                        let mut bytes: [u8; 1024] = [0; 1024];
        let mut fds: [u8; 24] = [0; 24];
        let (bytes_size, _fds_size) = self.bundle.get_socket()
                                                 .receive_message(&mut bytes, &mut fds)?;
        let mut bytes_buf = Cursor::new(&bytes[..]);
        let mut fds_buf = Cursor::new(&fds[..]);
        let mut position = 0;
        while position < bytes_size {
            bytes_buf.seek(SeekFrom::Start(position as u64))?;
            let header = Header {
                object_id: bytes_buf.read_u32::<NativeEndian>()?,
                opcode: bytes_buf.read_u16::<NativeEndian>()?,
                size: bytes_buf.read_u16::<NativeEndian>()?,
            };
            self.process_event(&header, &mut bytes_buf, &mut fds_buf)?;
            position += header.size as usize;
        }
        Ok(())
    }
}
impl Connection {
                                fn process_event(&mut self,
                     header: &Header,
                     mut bytes_buf: &mut Cursor<&[u8]>,
                     mut fds_buf: &mut Cursor<&[u8]>)
                     -> Result<(), SkylaneError> {
        let task = {
            let object_id = ObjectId::new(header.object_id);
            let handler_ref = self.bundle.get_handler(object_id)?;
            let mut handler = handler_ref.borrow_mut();
            handler.dispatch(&mut self.bundle, &header, bytes_buf, fds_buf)?
        };
        match task {
            Task::Create { id, object } => {
                self.add_object(id, object);
            }
            Task::Destroy { id } => {
                self.remove_object(id);
            }
            Task::None => {}
        }
        Ok(())
    }
}