use crate::printer::PrinterProvider;
use crate::message::Operator;
use p101_is::Register;
use rust_decimal::Decimal;

pub struct CliPrinter {
    value: Option<Decimal>,
    register: Option<Register>,
    operator: Option<Operator>
}

impl CliPrinter {
    pub fn new() -> Self {
        Self {
            value: None,
            register: None,
            operator: None,
        }
    }

    fn print_line(&self) {
        let mut output = String::from("");

        match &self.value {
            Some(value) => {
                output.push_str(&value.to_string());
                output.push(' ')
            },
            None => output.push(' ')
        }

        match &self.register {
            Some(register) => output.push_str(&register.to_string()),
            None => output.push(' ')
        }

        match self.operator {
            Some(Operator::Add) => output.push('+'),
            Some(Operator::Sub) => output.push('-'),
            Some(Operator::Mul) => output.push('x'),
            Some(Operator::Div) => output.push(':'),
            Some(Operator::Sqr) => output.push(' '),
            Some(Operator::CopyM) => output.push(' '),
            Some(Operator::CopyToA) => output.push(' '),
            Some(Operator::SwapA) => output.push(' '),
            Some(Operator::Print) => output.push(' '),
            Some(Operator::Reset) => output.push(' '),
            None => output.push(' ')
        }

        println!("PRN: |{}|", output);
    }

    fn clear(&mut self) {
        self.value = None;
        self.register = None;
        self.operator = None;
    }
}

impl Default for CliPrinter {
    fn default() -> Self {
        Self::new()
    }
}

impl PrinterProvider for CliPrinter {
    fn get_name(&self) -> &str {
        "CliPrinter"
    }

    fn print_value(&mut self, value: Decimal) {
        self.value = Some(value);
    }

    /// Prints the register in the register column.
    fn print_register(&mut self, register: Register) {
        self.register = Some(register);
    }

    /// Prints the operator in the operator column.
    fn print(&mut self, value: Decimal, register: Register, operator: Operator) {
        self.value = Some(value);
        self.register = Some(register);
        self.operator = Some(operator);
        self.print_line();
        self.clear();
    }

    /// Advance the "paper" to a new line.
    fn newline(&mut self) {
        self.clear();
        self.print_line();
    }
}

