use chrono::{Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone};
use sqlite::Connection;
use crate::{data_layer, entities::*, enums::*};
pub struct App {
pub current_screen: CurrentScreen,
pub current_widget: CurrentWidget,
pub acc_list: AccountList,
pub trx_table: TrxTable,
pub new_account: Account,
pub new_transaction: Transaction,
pub selected_transaction_input: TransactionInput,
pub selected_account_input: AccountInput,
pub current_input: String,
pub tr_types: Vec<TransactionType>,
pub selected_tab: usize,
pub tabs: Vec<String>,
pub error: String,
pub error_showing: bool,
pub selected_tr_type_chart: i64,
pub selected_tr_type_chart_desc: String,
pub connection: Connection,
}
impl App {
pub fn new(path: &str) -> App {
let con = match Connection::open(path) {
Ok(con) => con,
Err(e) => {
eprintln!("Error opening database: {}", e);
panic!("stopping");
}
};
let mut error = String::new();
data_layer::setup(&con);
let tr_types = match data_layer::get_transaction_types(&con) {
Ok(tt) => tt,
Err(e) => {
error = e.to_string();
Vec::new()
}
};
return App {
current_screen: CurrentScreen::Main,
current_widget: CurrentWidget::AccountList,
acc_list: AccountList::new(),
trx_table: TrxTable::new(),
new_account: Account::new_empty(),
new_transaction: Transaction::new_empty(),
selected_transaction_input: TransactionInput::Type,
selected_account_input: AccountInput::Asset,
current_input: String::new(),
tr_types: tr_types.clone(),
selected_tab: 0,
tabs: [
"Transactions".to_string(),
"Amnt by Type".to_string(),
"Total".to_string(),
"Chart 3".to_string(),
]
.to_vec(),
error: if error.is_empty() {
String::new()
} else {
error
},
error_showing: false,
selected_tr_type_chart: 1,
selected_tr_type_chart_desc: tr_types
.iter()
.filter(|x| x.get_id() == 1)
.next()
.unwrap_or(&TransactionType::new(0, String::new()))
.get_description(),
connection: con,
};
}
pub fn get_list_accounts(&mut self) -> Vec<Account> {
return match self.acc_list.get_accounts(&self.connection) {
Ok(a) => a,
Err(e) => {
self.error = e.to_string();
return Vec::new();
}
};
}
pub fn next_ac(&mut self) {
self.acc_list.state.select_next();
}
pub fn previous_ac(&mut self) {
self.acc_list.state.select_previous();
}
pub fn get_list_trx(&mut self) -> Vec<Transaction> {
return match self
.trx_table
.get_trx(self.acc_list.get_selected_id(), &self.connection)
{
Ok(t) => t,
Err(e) => {
self.error = e.to_string();
Vec::new()
}
};
}
pub fn next_tr(&mut self) {
self.trx_table.state.select_next();
}
pub fn previous_tr(&mut self) {
self.trx_table.state.select_previous();
}
pub fn save_new_account(&mut self) {
let new = self.new_account.get_id() == 0;
self.next_ac_input();
let ac = match data_layer::upsert_account(&self.connection, self.new_account.clone()) {
Ok(a) => a,
Err(e) => {
self.error = e.to_string();
return;
}
};
if new {
self.acc_list.add_account(ac);
}
self.new_account = Account::new_empty();
self.current_input = String::new();
self.selected_account_input = AccountInput::Asset;
}
pub fn save_new_tr(&mut self) {
let new = self.new_transaction.get_id() == 0;
self.next_tr_input();
let tr =
match data_layer::upsert_transaction(&self.connection, self.new_transaction.clone()) {
Ok(tr) => tr,
Err(e) => {
self.error = e.to_string();
return;
}
};
if new {
self.trx_table.add_tr(tr);
}
self.new_transaction = Transaction::new_empty();
self.current_input = String::new();
self.selected_transaction_input = TransactionInput::Type;
}
pub fn next_tr_input(&mut self) {
self.set_tr_from_input();
self.selected_transaction_input = match self.selected_transaction_input {
TransactionInput::Type => TransactionInput::Amount,
TransactionInput::Amount => TransactionInput::Date,
TransactionInput::Date => TransactionInput::Description,
TransactionInput::Description => TransactionInput::Asset,
TransactionInput::Asset => TransactionInput::Asset,
};
self.set_current_input_tr();
}
pub fn previous_tr_input(&mut self) {
self.set_tr_from_input();
self.selected_transaction_input = match self.selected_transaction_input {
TransactionInput::Type => TransactionInput::Type,
TransactionInput::Amount => TransactionInput::Type,
TransactionInput::Date => TransactionInput::Amount,
TransactionInput::Description => TransactionInput::Date,
TransactionInput::Asset => TransactionInput::Description,
};
self.set_current_input_tr();
}
pub fn set_current_input_tr(&mut self) {
match self.selected_transaction_input {
TransactionInput::Type => {
self.current_input = self.new_transaction.get_type().get_id().to_string()
}
TransactionInput::Amount => {
self.current_input = self.new_transaction.get_amount().to_string()
}
TransactionInput::Date => {
self.current_input = self
.new_transaction
.get_date()
.format("%Y-%m-%d")
.to_string()
}
TransactionInput::Description => self.current_input = self.new_transaction.get_desc(),
TransactionInput::Asset => {
self.current_input = self.new_transaction.get_asset_amnt().to_string()
}
}
}
pub fn set_tr_from_input(&mut self) {
match self.selected_transaction_input {
TransactionInput::Type => {
let type_id = match self.current_input.parse::<i64>() {
Ok(t) => t,
Err(e) => {
self.error = e.to_string();
0
}
};
self.new_transaction.set_type(type_id, &self.connection);
}
TransactionInput::Amount => {
let amnt = match self.current_input.parse::<f64>() {
Ok(a) => a,
Err(e) => {
self.error = e.to_string();
0.0
}
};
self.new_transaction.set_amount(amnt);
}
TransactionInput::Date => {
let date = match NaiveDate::parse_from_str(&self.current_input, "%Y-%m-%d") {
Ok(d) => d,
Err(e) => {
self.error = e.to_string();
NaiveDate::default()
}
};
let time = NaiveTime::from_hms_opt(5, 0, 0).unwrap_or_default(); // to account for my local datetime
self.new_transaction
.set_date(Local.from_utc_datetime(&NaiveDateTime::new(date, time)));
}
TransactionInput::Description => {
self.new_transaction.set_desc(self.current_input.clone());
}
TransactionInput::Asset => {
let ast = match self.current_input.parse::<f64>() {
Ok(a) => a,
Err(e) => {
self.error = e.to_string();
0.0
}
};
self.new_transaction.set_asset_amnt(ast);
}
}
}
pub fn next_ac_input(&mut self) {
self.set_ac_from_input();
self.selected_account_input = match self.selected_account_input {
AccountInput::Asset => AccountInput::Name,
AccountInput::Name => AccountInput::Type,
AccountInput::Type => AccountInput::Type,
};
self.set_current_input_ac();
}
pub fn previous_ac_input(&mut self) {
self.set_ac_from_input();
self.selected_account_input = match self.selected_account_input {
AccountInput::Asset => AccountInput::Asset,
AccountInput::Name => AccountInput::Asset,
AccountInput::Type => AccountInput::Name,
};
self.set_current_input_ac();
}
pub fn set_current_input_ac(&mut self) {
match self.selected_account_input {
AccountInput::Asset => {
self.current_input = self.new_account.get_asset_price().to_string();
}
AccountInput::Name => {
self.current_input = self.new_account.get_name();
}
AccountInput::Type => {
let ac_type = self.new_account.get_ac_type() as usize;
self.current_input = ac_type.to_string();
}
}
}
pub fn set_ac_from_input(&mut self) {
match self.selected_account_input {
AccountInput::Asset => {
let ast = match self.current_input.parse::<f64>() {
Ok(a) => a,
Err(e) => {
self.error = e.to_string();
0.0
}
};
self.new_account.set_asset_price(ast);
}
AccountInput::Name => {
self.new_account.set_name(self.current_input.clone());
}
AccountInput::Type => {
let ac_type = match self.current_input.parse::<usize>() {
Ok(a) => a,
Err(e) => {
self.error = e.to_string();
0
}
};
self.new_account.set_type(AccountType::from_usize(ac_type));
}
}
}
pub fn next_tab(&mut self) {
if self.selected_tab < self.tabs.len() {
self.selected_tab += 1;
}
}
pub fn previous_tab(&mut self) {
if self.selected_tab > 0 {
self.selected_tab -= 1;
}
}
pub fn get_cumulative_total(&mut self) -> Vec<(f64, f64)> {
return match data_layer::get_cumulative_account_sum(
&self.connection,
self.acc_list.get_selected_id(),
) {
Ok(d) => d,
Err(e) => {
self.error = e.to_string();
Vec::new()
}
};
}
pub fn get_trtype_data(&mut self) -> Vec<(f64, f64)> {
return match data_layer::get_tr_type_price_over_time(
&self.connection,
self.acc_list.get_selected_id(),
self.selected_tr_type_chart,
) {
Ok(d) => d,
Err(e) => {
self.error = e.to_string();
Vec::new()
}
};
}
pub fn select_tr_type_chart(&mut self, id: i64) {
self.selected_tr_type_chart = id;
self.selected_tr_type_chart_desc = self
.tr_types
.iter()
.filter(|x| x.get_id() == id)
.next()
.unwrap_or(&TransactionType::new(0, String::new()))
.get_description();
}
}