use std::collections::HashMap;
use std::path::Path;
use install_framework_core::interface::Interface;
use install_framework_core::interface::Installer;
use install_framework_core::interface::InstallMethod;
use install_framework_core::interface::PostInstall;
use install_framework_core::interface::PostUninstall;
use install_framework_core::interface::Component;
use install_framework_base::interface::BaseInterface;
use async_channel::Sender;
use async_channel::Receiver;
use crate::interpreter::ThreadedInterpreter;
use crate::messages::RenderMessage;
use crate::messages::ThreadMessage;
use crate::messages::Page;
use crate::error::GuiError;
use crate::ext::SenderSync;
use crate::ext::ReceiverSync;
pub struct ThreadLinker
{
sender: Sender<RenderMessage>,
receiver: Receiver<ThreadMessage>
}
impl ThreadLinker
{
pub fn new(sender: Sender<RenderMessage>, receiver: Receiver<ThreadMessage>) -> ThreadLinker
{
return ThreadLinker
{
sender: sender,
receiver: receiver
};
}
pub fn recv(&mut self) -> Result<ThreadMessage, GuiError>
{
match self.receiver.recv_sync()
{
Ok(v) => return Ok(v),
Err(e) => return Err(GuiError::channel_recv(e))
};
}
pub fn send(&mut self, msg: RenderMessage) -> Result<(), GuiError>
{
if let Err(e) = self.sender.send_sync(msg)
{
return Err(GuiError::channel_send(e));
}
return Ok(());
}
pub fn clone_sender(&self) -> Sender<RenderMessage>
{
return self.sender.clone();
}
pub fn clone_receiver(&self) -> Receiver<ThreadMessage>
{
return self.receiver.clone();
}
}
pub struct GuiInterface
{
base: BaseInterface<ThreadedInterpreter, GuiError>,
thread: ThreadLinker,
uninstall: bool,
method: InstallMethod
}
impl GuiInterface
{
pub fn new(thread: ThreadLinker) -> GuiInterface
{
return GuiInterface
{
base: BaseInterface::new(ThreadedInterpreter::new(thread.clone_sender(), thread.clone_receiver())),
thread: thread,
uninstall: false,
method: InstallMethod::SystemInstall
};
}
fn wait_next_or_error(&mut self) -> Result<Option<(InstallMethod, bool)>, GuiError>
{
loop
{
match self.thread.recv()?
{
ThreadMessage::Next(data) => return Ok(data),
ThreadMessage::Terminate => return Err(GuiError::Interupted),
_ => return Err(GuiError::IllegalMessage)
}
}
}
fn wait_install_components(&mut self) -> Result<Vec<Component>, GuiError>
{
loop
{
match self.thread.recv()?
{
ThreadMessage::InstallComponents(data) => return Ok(data),
ThreadMessage::Terminate => return Err(GuiError::Interupted),
_ => return Err(GuiError::IllegalMessage)
}
}
}
fn wait_terminate(&mut self) -> Result<(), GuiError>
{
loop
{
if let Ok(v) = self.thread.recv()
{
match v
{
ThreadMessage::Terminate => return Ok(()),
_ => return Err(GuiError::IllegalMessage)
}
}
return Ok(());
}
}
}
impl Interface for GuiInterface
{
type ErrorType = GuiError;
fn welcome(&mut self, name: &'static str, version: &'static str, author: &'static str) -> Result<(), GuiError>
{
self.base.set_static_info(name, version, author);
self.thread.send(RenderMessage::SwitchPage(Page::Welcome(name, version, author)))?;
match self.wait_next_or_error()?
{
Some((method, uninstall)) =>
{
self.method = method;
self.uninstall = uninstall;
return Ok(());
},
None => return Err(GuiError::IllegalMessage)
};
}
fn get_install_method(&mut self) -> Result<InstallMethod, GuiError>
{
return Ok(self.method);
}
fn should_uninstall(&self) -> Result<bool, GuiError>
{
return Ok(self.uninstall);
}
fn run_install(&mut self, installer: &mut dyn Installer, dir: &Path, method: InstallMethod, resources: &HashMap<&'static str, &'static [u8]>) -> Result<(), GuiError>
{
self.thread.send(RenderMessage::SwitchPage(Page::Processing))?;
let components = self.base.get_components(installer, resources)?;
let copy = components.clone();
let state = self.base.get_installation_state(components, installer, dir)?;
self.thread.send(RenderMessage::SwitchPage(Page::ComponentView(copy, state, false)))?;
let comps = self.wait_install_components()?;
self.thread.send(RenderMessage::SwitchPage(Page::Processing))?;
for v in comps
{
self.base.install_component(&v, installer, dir, method, resources)?;
}
return Ok(());
}
fn run_post_install(&mut self, post: &mut dyn PostInstall, dir: &Path) -> Result<(), GuiError>
{
self.base.run_post_install(post, dir)?;
return Ok(());
}
fn run_uninstall(&mut self, installer: &mut dyn Installer, dir: &Path, method: InstallMethod, resources: &HashMap<&'static str, &'static [u8]>) -> Result<(), GuiError>
{
self.thread.send(RenderMessage::SwitchPage(Page::Processing))?;
let components = self.base.get_components(installer, resources)?;
let copy = components.clone();
let state = self.base.get_installation_state(components, installer, dir)?;
self.thread.send(RenderMessage::SwitchPage(Page::ComponentView(copy, state, true)))?;
let comps = self.wait_install_components()?;
self.thread.send(RenderMessage::SwitchPage(Page::Processing))?;
for v in comps
{
self.base.uninstall_component(&v, installer, dir, method)?;
}
return Ok(());
}
fn run_post_uninstall(&mut self, post: &mut dyn PostUninstall, dir: &Path) -> Result<(), GuiError>
{
self.base.run_post_uninstall(post, dir)?;
return Ok(());
}
fn error(&mut self, e: GuiError) -> i32
{
let (_, code) = e.translate();
if let Err(e) = self.thread.send(RenderMessage::SwitchPage(Page::Error(e)))
{
return handle_low_level_error(&e);
}
if let Err(e) = self.wait_terminate()
{
return handle_low_level_error(&e);
}
return code;
}
fn finish(&mut self) -> i32
{
let msg =
{
if self.uninstall
{
String::from("Uninstall complete!")
}
else
{
String::from("Install complete!")
}
};
if let Err(e) = self.thread.send(RenderMessage::SwitchPage(Page::Finish(msg)))
{
return handle_low_level_error(&e);
}
if let Err(e) = self.wait_terminate()
{
return handle_low_level_error(&e);
}
return 0;
}
}
fn handle_low_level_error(e: &GuiError) -> i32
{
let (s, exit) = e.translate();
eprintln!("{}", s);
return exit;
}