use libc::{c_char, c_int};
use std::ffi::CString;
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use crate::foundation::{id, nil, AutoReleasePool, NSString, NSUInteger, NO, YES};
use crate::notification_center::Dispatcher;
use crate::uikit::scene::{register_window_scene_delegate_class, WindowSceneDelegate};
use crate::utils::activate_cocoa_multithreading;
mod class;
use class::register_app_class;
mod delegate;
use delegate::register_app_delegate_class;
mod enums;
pub use enums::*;
mod traits;
pub use traits::AppDelegate;
pub(crate) static mut APP_DELEGATE: usize = 0;
pub(crate) static mut SCENE_DELEGATE_VENDOR: usize = 0;
extern "C" {
fn UIApplicationMain(argc: c_int, argv: *const *const c_char, principal_class_name: id, delegate_class_name: id);
}
#[inline]
fn shared_application<F: Fn(id)>(handler: F) {
let app: id = unsafe { msg_send![register_app_class(), sharedApplication] };
handler(app);
}
pub struct App<T = (), W = (), F = ()> {
pub delegate: Box<T>,
pub vendor: Box<F>,
pub pool: AutoReleasePool,
_w: std::marker::PhantomData<W>
}
impl<W, T, F> std::fmt::Debug for App<W, T, F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("App<W, T, F>").finish()
}
}
impl<T, W, F> App<T, W, F>
where
T: AppDelegate + 'static,
W: WindowSceneDelegate,
F: Fn() -> Box<W>
{
pub fn new(delegate: T, scene_delegate_vendor: F) -> Self {
activate_cocoa_multithreading();
let pool = AutoReleasePool::new();
let cls = register_app_class();
let dl = register_app_delegate_class::<T>();
let w = register_window_scene_delegate_class::<W, F>();
let app_delegate = Box::new(delegate);
let vendor = Box::new(scene_delegate_vendor);
unsafe {
let delegate_ptr: *const T = &*app_delegate;
APP_DELEGATE = delegate_ptr as usize;
let scene_delegate_vendor_ptr: *const F = &*vendor;
SCENE_DELEGATE_VENDOR = scene_delegate_vendor_ptr as usize;
}
App {
delegate: app_delegate,
vendor,
pool,
_w: std::marker::PhantomData
}
}
}
impl<T, W, F> App<T, W, F> {
pub fn run(&self) {
let args = std::env::args()
.map(|arg| CString::new(arg).unwrap())
.collect::<Vec<CString>>();
let c_args = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<*const c_char>>();
let mut s = NSString::new("RSTApplication");
let mut s2 = NSString::new("RSTAppDelegate");
unsafe {
UIApplicationMain(c_args.len() as c_int, c_args.as_ptr(), s.into(), s2.into());
}
self.pool.drain();
}
}