#[cfg(not(feature = "std"))]
use core::cmp;
#[cfg(feature = "std")]
use std::sync::Arc;
use crate::channel;
use crate::error::{Error, ErrorCode};
use crate::fuse_handlers::FuseHandlers;
use crate::internal::fuse_io::{
	self,
	AlignedBuffer,
	DecodeRequest,
	EncodeResponse,
};
use crate::internal::fuse_kernel;
use crate::internal::types::ProtocolVersion;
use crate::protocol::common::{RequestHeader, UnknownRequest};
use crate::protocol::{FuseInitRequest, FuseInitResponse};
use crate::server;
const FUSE: fuse_io::Semantics = fuse_io::Semantics::FUSE;
pub trait FuseServerChannel: server::ServerChannel {}
pub struct FuseServerBuilder<Channel, Handlers, Hooks> {
	channel: Channel,
	handlers: Handlers,
	hooks: Option<Hooks>,
}
impl<C, Handlers, Hooks> FuseServerBuilder<C, Handlers, Hooks>
where
	C: FuseServerChannel,
	Handlers: FuseHandlers,
	Hooks: server::ServerHooks,
{
	pub fn new(
		channel: C,
		handlers: Handlers,
	) -> FuseServerBuilder<C, Handlers, Hooks> {
		Self {
			channel,
			handlers,
			hooks: None,
		}
	}
	pub fn set_hooks(mut self, hooks: Hooks) -> Self {
		self.hooks = Some(hooks);
		self
	}
	pub fn build(mut self) -> Result<FuseServer<C, Handlers, Hooks>, C::Error> {
		let init_response = self.fuse_handshake()?;
		FuseServer::new(self.channel, self.handlers, self.hooks, &init_response)
	}
	fn fuse_handshake(&mut self) -> Result<FuseInitResponse, C::Error> {
		let mut read_buf = fuse_io::MinReadBuffer::new();
		loop {
			let request_size = self.channel.receive(read_buf.get_mut())?;
			let request_buf = fuse_io::aligned_slice(&read_buf, request_size);
			let request_decoder = fuse_io::RequestDecoder::new(
				request_buf,
				ProtocolVersion::LATEST,
				FUSE,
			)?;
			let request_header = request_decoder.header();
			if request_header.opcode != fuse_kernel::FUSE_INIT {
				return Err(
					Error::expected_fuse_init(request_header.opcode.0).into()
				);
			}
			let request_id = request_header.unique;
			let init_request =
				FuseInitRequest::decode_request(request_decoder)?;
			let encoder = fuse_io::ResponseEncoder::new(
				&self.channel,
				request_id,
				
				ProtocolVersion::LATEST,
			);
			let version =
				match server::negotiate_version(init_request.version()) {
					Some(x) => x,
					None => {
						let mut init_response = FuseInitResponse::new();
						init_response.set_version(ProtocolVersion::LATEST);
						init_response.encode_response(encoder)?;
						continue;
					},
				};
			#[allow(unused_mut)]
			let mut init_response = self.handlers.fuse_init(&init_request);
			init_response.set_version(version);
			#[cfg(not(feature = "std"))]
			init_response.set_max_write(cmp::min(
				init_response.max_write(),
				server::capped_max_write(),
			));
			init_response.encode_response(encoder)?;
			return Ok(init_response);
		}
	}
}
#[cfg(feature = "std")]
pub struct FuseServer<Channel, Handlers, Hooks> {
	executor: FuseServerExecutor<Channel, Handlers, Hooks>,
	channel: Arc<Channel>,
	handlers: Arc<Handlers>,
	hooks: Option<Arc<Hooks>>,
	version: ProtocolVersion,
	read_buf_size: usize,
}
#[cfg(not(feature = "std"))]
pub struct FuseServer<Channel, Handlers, Hooks> {
	executor: FuseServerExecutor<Channel, Handlers, Hooks>,
}
impl<C, Handlers, Hooks> FuseServer<C, Handlers, Hooks>
where
	C: FuseServerChannel,
	Handlers: FuseHandlers,
	Hooks: server::ServerHooks,
{
	#[cfg(feature = "std")]
	fn new(
		channel: C,
		handlers: Handlers,
		hooks: Option<Hooks>,
		init_response: &FuseInitResponse,
	) -> Result<FuseServer<C, Handlers, Hooks>, C::Error> {
		let channel = Arc::new(channel);
		let handlers = Arc::new(handlers);
		let hooks = hooks.map(|h| Arc::new(h));
		let version = init_response.version();
		let read_buf_size = server::read_buf_size(init_response.max_write());
		let executor = FuseServerExecutor {
			channel: channel.clone(),
			handlers: handlers.clone(),
			hooks: hooks.clone(),
			version,
			read_buf_size,
		};
		Ok(Self {
			executor,
			channel,
			handlers,
			hooks,
			version,
			read_buf_size,
		})
	}
	#[cfg(not(feature = "std"))]
	fn new(
		channel: C,
		handlers: Handlers,
		hooks: Option<Hooks>,
		init_response: &FuseInitResponse,
	) -> Result<FuseServer<C, Handlers, Hooks>, C::Error> {
		Ok(Self {
			executor: FuseServerExecutor {
				channel,
				handlers,
				hooks,
				version: init_response.version(),
			},
		})
	}
	pub fn executor_mut(
		&mut self,
	) -> &mut FuseServerExecutor<C, Handlers, Hooks> {
		&mut self.executor
	}
	#[cfg(feature = "std")]
	#[cfg_attr(doc, doc(cfg(feature = "std")))]
	pub fn new_executor(
		&self,
	) -> Result<FuseServerExecutor<C, Handlers, Hooks>, C::Error> {
		let channel = self.channel.as_ref().try_clone()?;
		Ok(FuseServerExecutor {
			channel: Arc::new(channel),
			handlers: self.handlers.clone(),
			hooks: self.hooks.as_ref().map(|h| h.clone()),
			version: self.version,
			read_buf_size: self.read_buf_size,
		})
	}
}
#[cfg(feature = "std")]
pub struct FuseServerExecutor<Channel, Handlers, Hooks> {
	channel: Arc<Channel>,
	handlers: Arc<Handlers>,
	hooks: Option<Arc<Hooks>>,
	version: ProtocolVersion,
	read_buf_size: usize,
}
#[cfg(not(feature = "std"))]
pub struct FuseServerExecutor<Channel, Handlers, Hooks> {
	channel: Channel,
	handlers: Handlers,
	hooks: Option<Hooks>,
	version: ProtocolVersion,
}
impl<C, Handlers, Hooks> FuseServerExecutor<C, Handlers, Hooks>
where
	C: FuseServerChannel,
	Handlers: FuseHandlers,
	Hooks: server::ServerHooks,
{
	#[cfg(feature = "std")]
	pub fn run(&mut self) -> Result<(), C::Error>
	where
		C: Send + Sync + 'static,
		Hooks: Send + Sync + 'static,
	{
		let channel = self.channel.as_ref();
		let handlers = self.handlers.as_ref();
		let hooks = self.hooks.as_deref();
		let mut buf = fuse_io::AlignedVec::new(self.read_buf_size);
		server::main_loop(channel, &mut buf, self.version, FUSE, |dec| {
			let mut channel_err = Ok(());
			let respond = server::RespondRef::new(
				channel,
				hooks,
				&mut channel_err,
				RequestHeader::new_ref(dec.header()),
				self.version,
				&self.channel,
				self.hooks.as_ref(),
			);
			fuse_request_dispatch::<C, Handlers, Hooks>(
				dec,
				handlers,
				respond,
				self.hooks.as_ref(),
			)?;
			channel_err
		})
	}
	#[cfg(not(feature = "std"))]
	pub fn run(&mut self) -> Result<(), C::Error>
	where
		C: Send + Sync + 'static,
	{
		self.run_local()
	}
	#[cfg(any(doc, not(feature = "std")))]
	#[cfg_attr(doc, doc(cfg(not(feature = "std"))))]
	pub fn run_local(&mut self) -> Result<(), C::Error> {
		let channel = &self.channel;
		let handlers = &self.handlers;
		let hooks = self.hooks.as_ref();
		let mut buf = fuse_io::MinReadBuffer::new();
		server::main_loop(channel, &mut buf, self.version, FUSE, |dec| {
			let mut channel_error = Ok(());
			let respond = server::RespondRef::new(
				channel,
				hooks,
				&mut channel_error,
				RequestHeader::new_ref(dec.header()),
				self.version,
			);
			fuse_request_dispatch::<C, Handlers, Hooks>(
				dec, handlers, respond, hooks,
			)?;
			channel_error
		})
	}
}
fn fuse_request_dispatch<C, Handlers, Hooks>(
	request_decoder: fuse_io::RequestDecoder,
	handlers: &Handlers,
	respond: server::RespondRef<C::T, Hooks::T>,
	#[cfg(feature = "std")] hooks: Option<&Arc<Hooks::T>>,
	#[cfg(not(feature = "std"))] hooks: Option<&Hooks::T>,
) -> Result<(), <<C as server::MaybeSendChannel>::T as channel::Channel>::Error>
where
	C: server::MaybeSendChannel,
	Handlers: FuseHandlers,
	Hooks: server::MaybeSendHooks,
{
	use crate::server::ServerHooks;
	let header = request_decoder.header();
	let ctx = server::ServerContext::new(*header);
	if let Some(hooks) = hooks {
		hooks.request(ctx.request_header());
	}
	macro_rules! do_dispatch {
		($handler:tt) => {{
			match DecodeRequest::decode_request(request_decoder) {
				Ok(request) => handlers.$handler(ctx, &request, respond),
				Err(err) => {
					if let Some(hooks) = hooks {
						hooks.request_error(RequestHeader::new_ref(header), err)
					}
					respond.encoder().encode_error(ErrorCode::EIO)?;
				},
			}
		}};
	}
	match header.opcode {
		#[cfg(feature = "unstable_access")]
		fuse_kernel::FUSE_ACCESS => do_dispatch!(access),
		#[cfg(feature = "unstable_bmap")]
		fuse_kernel::FUSE_BMAP => do_dispatch!(bmap),
		#[cfg(feature = "unstable_create")]
		fuse_kernel::FUSE_CREATE => do_dispatch!(create),
		#[cfg(feature = "unstable_fallocate")]
		fuse_kernel::FUSE_FALLOCATE => do_dispatch!(fallocate),
		#[cfg(feature = "unstable_flush")]
		fuse_kernel::FUSE_FLUSH => do_dispatch!(flush),
		fuse_kernel::FUSE_FORGET | fuse_kernel::FUSE_BATCH_FORGET => {
			let request = DecodeRequest::decode_request(request_decoder)?;
			handlers.forget(ctx, &request);
		},
		#[cfg(feature = "unstable_fsync")]
		fuse_kernel::FUSE_FSYNC => do_dispatch!(fsync),
		#[cfg(feature = "unstable_fsyncdir")]
		fuse_kernel::FUSE_FSYNCDIR => do_dispatch!(fsyncdir),
		fuse_kernel::FUSE_GETATTR => do_dispatch!(getattr),
		#[cfg(feature = "unstable_getlk")]
		fuse_kernel::FUSE_GETLK => do_dispatch!(getlk),
		fuse_kernel::FUSE_GETXATTR => do_dispatch!(getxattr),
		#[cfg(feature = "unstable_ioctl")]
		fuse_kernel::FUSE_IOCTL => do_dispatch!(ioctl),
		fuse_kernel::FUSE_LINK => do_dispatch!(link),
		fuse_kernel::FUSE_LISTXATTR => do_dispatch!(listxattr),
		fuse_kernel::FUSE_LOOKUP => do_dispatch!(lookup),
		#[cfg(feature = "unstable_lseek")]
		fuse_kernel::FUSE_LSEEK => do_dispatch!(lseek),
		fuse_kernel::FUSE_MKDIR => do_dispatch!(mkdir),
		fuse_kernel::FUSE_MKNOD => do_dispatch!(mknod),
		fuse_kernel::FUSE_OPEN => do_dispatch!(open),
		fuse_kernel::FUSE_OPENDIR => do_dispatch!(opendir),
		fuse_kernel::FUSE_READ => do_dispatch!(read),
		fuse_kernel::FUSE_READDIR => do_dispatch!(readdir),
		fuse_kernel::FUSE_READLINK => do_dispatch!(readlink),
		fuse_kernel::FUSE_RELEASE => do_dispatch!(release),
		fuse_kernel::FUSE_RELEASEDIR => do_dispatch!(releasedir),
		#[cfg(feature = "unstable_removexattr")]
		fuse_kernel::FUSE_REMOVEXATTR => do_dispatch!(removexattr),
		fuse_kernel::FUSE_RENAME | fuse_kernel::FUSE_RENAME2 => {
			do_dispatch!(rename)
		},
		fuse_kernel::FUSE_RMDIR => do_dispatch!(rmdir),
		#[cfg(feature = "unstable_setattr")]
		fuse_kernel::FUSE_SETATTR => do_dispatch!(setattr),
		#[cfg(feature = "unstable_setlk")]
		fuse_kernel::FUSE_SETLK => do_dispatch!(setlk),
		#[cfg(feature = "unstable_setxattr")]
		fuse_kernel::FUSE_SETXATTR => do_dispatch!(setxattr),
		#[cfg(feature = "unstable_statfs")]
		fuse_kernel::FUSE_STATFS => do_dispatch!(statfs),
		fuse_kernel::FUSE_SYMLINK => do_dispatch!(symlink),
		fuse_kernel::FUSE_UNLINK => do_dispatch!(unlink),
		fuse_kernel::FUSE_WRITE => do_dispatch!(write),
		_ => {
			if let Some(hooks) = hooks {
				let request = UnknownRequest::decode_request(request_decoder)?;
				hooks.unknown_request(&request);
			}
			respond.encoder().encode_error(ErrorCode::ENOSYS)?;
		},
	}
	Ok(())
}