#[cfg(all(feature = "rt", feature = "tokio"))]
mod gate {
  use std::time::Duration;

  use tokio::{sync::mpsc, time};

  use qsu::{
    async_trait,
    rt::{
      InitCtx, RunCtx, RunEnv, SrvAppRt, SvcEvt, TermCtx, TokioServiceHandler,
      UserSig
    },
    tracing
  };

  #[derive(Debug)]
  enum MyError {}

  struct MyService {
    rx_term: mpsc::UnboundedReceiver<()>
  }

  #[async_trait]
  impl TokioServiceHandler for MyService {
    type AppErr = MyError;

    async fn init(&mut self, ictx: &mut InitCtx) -> Result<(), Self::AppErr> {
      ictx.report(Some("Initializing service handler"));

      // .. do initialization here ..

      ictx.report(Some("Finalized service handler initialization"));

      Ok(())
    }

    async fn run(&mut self, _re: &RunEnv) -> Result<(), Self::AppErr> {
      tracing::info!("Running TokioServiceHandler::run()");

      tracing::info!("Wait for termination event for up to 4 seconds ..");
      tokio::select! {
        _ = self.rx_term.recv() => {
          tracing::info!("Got kill signal from svc");
        }
        () = time::sleep(Duration::from_secs(4)) => {
          tracing::info!("Got timeout");
        }
      }

      Ok(())
    }

    async fn shutdown(
      &mut self,
      tctx: &mut TermCtx
    ) -> Result<(), Self::AppErr> {
      tracing::info!("Running TokioServiceHandler::shutdown()");
      tctx.report(Some("Terminating service handler"));

      // .. do termination here ..

      tctx.report(Some("Finalized service handler termination"));

      Ok(())
    }
  }


  pub fn main() {
    let svcname = qsu::default_service_name().unwrap();

    // Channel used to signal termination from service event handler to main
    // application
    let (tx, rx) = mpsc::unbounded_channel::<()>();

    // Service event handler
    let svcevt_handler = move |msg| match msg {
      SvcEvt::Shutdown(_) => {
        tracing::debug!("Shutdown event from service subsystem");

        // Once a Shutdown or Termination event has been received, signal to
        // the main service callback to terminate.
        let _ = tx.send(());
      }
      SvcEvt::User(us) => match us {
        UserSig::Sig1 => {
          log::info!("User signal 1");
        }
        UserSig::Sig2 => {
          log::info!("User signal 2");
        }
      },
      _ => {}
    };

    // Set up main service runtime handler
    let svcrt = MyService { rx_term: rx };

    // Define service application runtime components
    let apprt = SrvAppRt::Tokio {
      rtbldr: None,
      svcevt_handler: Box::new(svcevt_handler),
      rt_handler: Box::new(svcrt)
    };

    // Launch service
    let rctx = RunCtx::new(&svcname);
    rctx.run(apprt).unwrap();
  }
}

fn main() {
  #[cfg(all(feature = "rt", feature = "tokio"))]
  gate::main();

  #[cfg(not(all(feature = "rt", feature = "tokio")))]
  println!("simpletokio example requires the rt and tokio features");
}

// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :
