use crate::files::FileService;
use crate::project::ProjectService;

use dbui_core::Result;
use slog;
use std::sync::{Arc, RwLock};

/// Contains information about the running application
#[derive(Clone, Debug)]
pub struct AppConfig {
  address: String,
  port: i32,
  verbose: bool,
  files: Arc<FileService>,
  projects: Arc<RwLock<ProjectService>>,
  root_logger: slog::Logger
}

impl AppConfig {
  pub fn new(cfg_dir: String, address: String, port: i32, verbose: bool, root_logger: slog::Logger) -> AppConfig {
    let files = Arc::new(FileService::new(&cfg_dir, &root_logger));
    AppConfig {
      address,
      port,
      verbose,
      files: Arc::clone(&files),
      projects: Arc::new(RwLock::new(ProjectService::new(files, &root_logger))),
      root_logger
    }
  }

  pub fn address(&self) -> &String {
    &self.address
  }

  pub fn port(&self) -> i32 {
    self.port
  }

  pub fn verbose(&self) -> bool {
    self.verbose
  }

  pub fn files(&self) -> &FileService {
    &self.files
  }

  pub fn projects(&self) -> &RwLock<ProjectService> {
    &self.projects
  }

  pub fn get_all_projects(&self) -> Result<Vec<dbui_core::project::Project>> {
    let mut x = self.projects().read().unwrap().get_all_projects()?;
    x.sort_by(|l, r| l.key().cmp(r.key()));
    Ok(x)
  }

  pub fn get_project(&self, key: &str) -> Result<dbui_core::Project> {
    self.projects().write().unwrap().get_project(key)
  }

  pub fn set_project(&self, p: &dbui_core::Project) -> Result<()> {
    self.projects().write().unwrap().set_project(p)
  }

  pub fn remove_project(&self, key: &str) -> Result<()> {
    self.projects().write().unwrap().remove_project(key)
  }

  pub fn open_db(&self, key: &str) -> Result<postgres::Client> {
    self.projects().write().unwrap().open_connection(key.into())
  }

  pub fn root_logger(&self) -> &slog::Logger {
    &self.root_logger
  }
}
