use std::fmt::Display;
use std::ops::{Add, Div, Mul, Sub};
use std::str;
use crate::utils::{self, from_string};
use crate::{uBase, NumberBase};
use super::operations::*;
use crate::graphemes::grapheme_creation::GRAPHEMES;
#[allow(non_camel_case_types)]
#[derive(Debug, Clone)]
pub struct iBase {
digits: Vec<u16>,
base: u16,
}
impl NumberBase for iBase {
type DecimalType = i128;
fn base(&self) -> u16 {
self.base
}
fn digits(&self) -> &Vec<u16> {
&self.digits
}
fn convert(&mut self, base: u16) -> Self {
let negative = self.digits[0] == 1;
let mut digits = self.digits.clone();
digits.remove(0);
let mut res = utils::convert(self.base, digits, base);
if negative {
res.insert(0, 1);
} else {
res.insert(0, 0);
}
self.digits = res;
self.base = base;
self.clone()
}
fn from_string(base: u16, number: &str) -> Self {
let negative = &number[0..1] == "-";
let digits = if negative {
let mut digits = from_string(base, &number[1..]);
digits.insert(0, 1);
digits
} else {
let mut digits = from_string(base, number);
digits.insert(0, 0);
digits
};
Self { digits, base }
}
fn from_vec(base: u16, number: Vec<u16>) -> Self {
Self {
digits: number,
base,
}
}
fn greater_than(&self, number: Self) -> bool {
let ne_self = self.digits[0] == 1;
let ne_other = self.digits[0] == 1;
let numb1 = abs(&self.digits);
let numb2 = abs(&number.digits);
if ne_self && !ne_other {
false
} else if !ne_self && ne_other {
true
} else if !ne_self && !ne_other {
utils::greater_than(&numb1, &numb2)
} else if ne_self && ne_other {
!utils::greater_than(&numb1, &numb2)
} else {
unreachable!()
}
}
fn as_binary(&self) -> Self::DecimalType {
let mut binding_value = self.clone();
binding_value.convert(2);
binding_value.display_sub10().unwrap()
}
fn as_octal(&self) -> Self::DecimalType {
let mut binding_value = self.clone();
binding_value.convert(8);
binding_value.display_sub10().unwrap()
}
fn as_decimal(&self) -> Self::DecimalType {
let mut binding_value = self.clone();
binding_value.convert(10);
binding_value.display_sub10().unwrap()
}
fn as_hex(&self) -> String {
let mut binding_value = self.clone();
binding_value.convert(16);
binding_value.display()
}
fn display(&self) -> String {
let negative = self.digits[0] == 1;
let mut digits = self.digits.clone();
digits.remove(0);
let mut res_string = String::new();
if negative {
res_string += "-";
}
let grapheme_collection: String = digits
.iter()
.map(|x| {
str::from_utf8(
GRAPHEMES
.get(x)
.expect("Internal error. Could not fetch digit from graphemes"),
)
.unwrap()
})
.collect();
res_string += &grapheme_collection;
if res_string.is_empty() || res_string == "-" {
String::from("0")
} else {
res_string.split('\0').collect()
}
}
}
impl iBase {
#[allow(non_snake_case)]
pub fn as_uBase(&self) -> Option<uBase> {
if self.digits[0] == 1 {
None
} else {
let mut digits = self.digits.clone();
digits.remove(0);
Some(uBase::from_vec(self.base, digits))
}
}
fn display_sub10(&mut self) -> Option<i128> {
if self.base > 10 {
return None;
}
let mut str = String::new();
str += &self.display();
let number: i128 = str.parse().unwrap();
Some(number)
}
}
impl Display for iBase {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.display())
}
}
impl Add for iBase {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
let mut rhs = rhs;
if self.base != rhs.base {
rhs.convert(self.base);
}
let digits = add(self.base, &self.digits, &rhs.digits);
Self {
digits,
base: self.base,
}
}
}
impl Sub for iBase {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
let mut rhs = rhs;
if self.base != rhs.base {
rhs.convert(self.base);
}
let digits = subtract(self.base, &self.digits, &rhs.digits);
Self {
digits,
base: self.base,
}
}
}
impl Div for iBase {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
let mut rhs = rhs;
if self.base != rhs.base {
rhs.convert(self.base);
}
let (digits, _) = div(self.base, &self.digits, &rhs.digits);
Self {
digits,
base: self.base,
}
}
}
impl Mul for iBase {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
let mut rhs = rhs;
if self.base != rhs.base {
rhs.convert(self.base);
}
let digits = mul(self.base, &self.digits, &rhs.digits);
Self {
digits,
base: self.base,
}
}
}