vcard_tui 0.1.2

Terminal UI application for managing vCard contacts.
use std::borrow::BorrowMut;

use vcard_parser::constants::PropertyName;
use vcard_parser::vcard::property::Property;
use vcard_parser::vcard::Vcard;

use crate::state::extra::ExtraPropertiesState;
use crate::state::list::StatefulList;
use crate::state::properties::PropertiesState;
use crate::state::selected::{Select, Selected};

#[derive(Clone)]
pub struct ContactState {
    pub properties_adr: PropertiesState,
    pub property_bday: Option<Property>,
    pub properties_email: PropertiesState,
    pub properties_extra: ExtraPropertiesState,
    pub property_n: Option<Property>,
    pub properties_note: PropertiesState,
    pub properties_tel: PropertiesState,
    pub properties_url: PropertiesState,
    pub selected: Selected<ContactSelected>,
}

impl ContactState {
    pub fn get_selected_property(&mut self) -> Option<&Property> {
        match self.selected.get() {
            ContactSelected::Adr => self.properties_adr.current.as_ref(),
            ContactSelected::BDay => self.property_bday.as_ref(),
            ContactSelected::Email => self.properties_email.current.as_ref(),
            ContactSelected::Extra => self.properties_extra.current.as_ref(),
            ContactSelected::N => self.property_n.as_ref(),
            ContactSelected::Note => self.properties_note.current.as_ref(),
            ContactSelected::Tel => self.properties_tel.current.as_ref(),
            ContactSelected::Url => self.properties_url.current.as_ref(),
        }
    }
    pub fn get_selected_properties_state(&mut self) -> Option<&mut PropertiesState> {
        match self.selected.get() {
            ContactSelected::Adr => Some(self.properties_adr.borrow_mut()),
            ContactSelected::Email => Some(self.properties_email.borrow_mut()),
            ContactSelected::Note => Some(self.properties_note.borrow_mut()),
            ContactSelected::Tel => Some(self.properties_tel.borrow_mut()),
            ContactSelected::Url => Some(self.properties_url.borrow_mut()),
            _ => None,
        }
    }
    pub fn up(&mut self) {
        match self.selected.get() {
            ContactSelected::BDay | ContactSelected::N => {
                self.selected.prev();
                self.selected.prev();
                self.set_selected_properties_to_first();
            }
            ContactSelected::Extra => {
                if self.properties_extra.properties.len() <= 1 {
                    self.selected.prev();
                    self.selected.prev();
                    self.set_selected_properties_to_first();
                } else {
                    self.properties_extra.prev()
                }
            }
            _ => {
                if let Some(s) = self.get_selected_properties_state() {
                    if s.properties.len() <= 1 {
                        self.selected.prev();
                        self.selected.prev();
                        self.set_selected_properties_to_first();
                    } else {
                        s.prev()
                    }
                }
            }
        }
    }
    pub fn down(&mut self) {
        match self.selected.get() {
            ContactSelected::BDay | ContactSelected::N => {
                self.selected.next();
                self.selected.next();
                self.set_selected_properties_to_first();
            }
            ContactSelected::Extra => {
                if self.properties_extra.properties.len() <= 1 {
                    self.selected.next();
                    self.selected.next();
                    self.set_selected_properties_to_first();
                } else {
                    self.properties_extra.next()
                }
            }
            _ => {
                if let Some(s) = self.get_selected_properties_state() {
                    if s.properties.len() <= 1 {
                        self.selected.next();
                        self.selected.next();
                        self.set_selected_properties_to_first();
                    } else {
                        s.next()
                    }
                }
            }
        }
    }
    pub fn set_selected_properties_to_first(&mut self) {
        match self.selected.get() {
            ContactSelected::Email => self.properties_email.set_selected_index(0),
            ContactSelected::Tel => self.properties_tel.set_selected_index(0),
            ContactSelected::Adr => self.properties_adr.set_selected_index(0),
            ContactSelected::Url => self.properties_url.set_selected_index(0),
            ContactSelected::Note => self.properties_note.set_selected_index(0),
            ContactSelected::Extra => self.properties_extra.set_selected_index(0),
            _ => {}
        }
    }
}

impl Default for ContactState {
    fn default() -> Self {
        Self {
            properties_adr: PropertiesState::from(PropertyName::ADR),
            property_bday: None,
            properties_email: PropertiesState::from(PropertyName::EMAIL),
            properties_extra: ExtraPropertiesState::default(),
            property_n: None,
            properties_note: PropertiesState::from(PropertyName::NOTE),
            properties_tel: PropertiesState::from(PropertyName::TEL),
            properties_url: PropertiesState::from(PropertyName::URL),
            selected: Selected::from(ContactSelected::N),
        }
    }
}

impl From<&Vcard> for ContactState {
    fn from(vcard: &Vcard) -> Self {
        Self {
            properties_adr: PropertiesState::from((PropertyName::ADR, vcard)),
            property_bday: vcard.get_property_by_name(PropertyName::BDAY),
            properties_email: PropertiesState::from((PropertyName::EMAIL, vcard)),
            properties_extra: ExtraPropertiesState::from(vcard),
            property_n: vcard.get_property_by_name(PropertyName::N),
            properties_note: PropertiesState::from((PropertyName::NOTE, vcard)),
            properties_tel: PropertiesState::from((PropertyName::TEL, vcard)),
            properties_url: PropertiesState::from((PropertyName::URL, vcard)),
            selected: Selected::from(ContactSelected::N),
        }
    }
}

#[derive(Clone, PartialEq, Eq)]
pub enum ContactSelected {
    N,
    BDay,
    Email,
    Tel,
    Adr,
    Url,
    Note,
    Extra,
}

impl Select for Selected<ContactSelected> {
    fn prev(&mut self) {
        self.set(match self.get() {
            ContactSelected::N => ContactSelected::N,
            ContactSelected::BDay => ContactSelected::N,
            ContactSelected::Email => ContactSelected::BDay,
            ContactSelected::Tel => ContactSelected::Email,
            ContactSelected::Adr => ContactSelected::Tel,
            ContactSelected::Url => ContactSelected::Adr,
            ContactSelected::Note => ContactSelected::Url,
            ContactSelected::Extra => ContactSelected::Note,
        })
    }
    fn next(&mut self) {
        self.set(match self.get() {
            ContactSelected::N => ContactSelected::BDay,
            ContactSelected::BDay => ContactSelected::Email,
            ContactSelected::Email => ContactSelected::Tel,
            ContactSelected::Tel => ContactSelected::Adr,
            ContactSelected::Adr => ContactSelected::Url,
            ContactSelected::Url => ContactSelected::Note,
            ContactSelected::Note => ContactSelected::Extra,
            ContactSelected::Extra => ContactSelected::Extra,
        })
    }
}