Documentation
use std::collections::HashMap;
use std::fs;
use json::{JsonValue, object};
use crate::mode::OcrMode;

mod mode;

#[derive(Clone)]
pub struct Ocr {
    default: String,
    connections: HashMap<String, Connection>,
}

impl Ocr {
    pub fn new(path: &str) -> Self {
        let text = fs::read_to_string(path).unwrap_or("".to_string());
        let json = {
            if text.is_empty() {
                let mut def = Ocr::news();
                let json = def.json();
                fs::write(path, json.to_string()).unwrap();
                json
            } else {
                json::parse(&text.clone()).unwrap()
            }
        };
        Ocr::from(json)
    }
    pub fn from(data: JsonValue) -> Self {
        let default = data["default"].to_string();
        let mut connections = HashMap::new();
        for (key, value) in data["connections"].entries() {
            let connection = Connection::new().from(value.clone()).clone();
            connections.insert(key.to_string(), connection.clone());
        }
        Self {
            default,
            connections,
        }
    }
    pub fn news() -> Self {
        let mut connections = HashMap::new();
        connections.insert("my_name".to_string(), Connection::new());
        Self {
            default: "my_name".to_string(),
            connections,
        }
    }
    fn json(&mut self) -> JsonValue {
        let mut data = object! {};
        data["default"] = self.default.clone().into();
        let mut connections = object! {};
        for (name, connection) in self.connections.iter_mut() {
            connections[name.clone()] = connection.json().clone();
        }
        data["connections"] = connections;
        data
    }
    pub fn connection(&mut self, name: &str) -> &mut Self {
        self.default = name.to_string();
        self
    }

    pub fn ocr(&mut self, file_path: &str, file_b64: &str) -> JsonValue {
        match self.connections.get(&*self.default).unwrap().mode {
            Mode::Aliyun => mode::aliyun::Aliyun::new(self.connections.get(&*self.default).unwrap().clone()).ocr(file_path, file_b64),
            Mode::Baidu => mode::baidu::Baidu::new(self.connections.get(&*self.default).unwrap().clone()).ocr(file_path, file_b64)
        }
    }

    pub fn get_mail(&mut self, list: JsonValue) -> String {
        let ocr_res = list.clone();
        let mut res = String::new();

        for member in ocr_res.members() {
            let temp = member.to_string();
            if temp.contains("@") {
                let item = temp.trim();
                if item.contains(":") {
                    let temp_vec: Vec<&str> = item.split(":").collect();
                    for i in temp_vec {
                        if i.contains("@") {
                            res = i.trim().to_string();
                        }
                    }
                    break
                } else if item.contains("") {
                    let temp_vec: Vec<&str> = item.split("").collect();
                    for i in temp_vec {
                        if i.contains("@") {
                            res = i.trim().to_string();
                        }
                    }
                    break
                } else {
                    res = item.to_string();
                    break
                }
            } else {
                continue
            }
        }
        res
    }

    pub fn translate(&mut self, text: &str) -> JsonValue {
        match self.connections.get(&*self.default).unwrap().mode {
            Mode::Aliyun => mode::aliyun::Aliyun::new(self.connections.get(&*self.default).unwrap().clone()).translate(text),
            Mode::Baidu => mode::baidu::Baidu::new(self.connections.get(&*self.default).unwrap().clone()).translate(text),
        }
    }

}


#[derive(Clone)]
pub struct Connection {
    pub mode: Mode,
    pub appid: String,
    pub secret: String,
}

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

impl Connection {
    pub fn new() -> Connection {
        Self {
            mode: Mode::Aliyun,
            appid: "".to_string(),
            secret: "".to_string(),
        }
    }
    pub fn json(&mut self) -> JsonValue {
        let mut data = object! {};
        data["mode"] = self.mode.str().into();
        data["appid"] = self.appid.clone().into();
        data["secret"] = self.secret.clone().into();
        data
    }
    pub fn from(&mut self, data: JsonValue) -> &mut Connection {
        self.mode = Mode::from(data["mode"].as_str().unwrap());
        self.appid = data["appid"].to_string();
        self.secret = data["secret"].to_string();
        self
    }
}


#[derive(Clone)]
pub enum Mode {
    Aliyun,
    Baidu,
}

impl Mode {
    pub fn str(&mut self) -> &'static str {
        match self {
            Mode::Aliyun => "aliyun",
            Mode::Baidu => "baidu"
        }
    }
    pub fn from(name: &str) -> Self {
        match name {
            "aliyun" => Mode::Aliyun,
            "baidu" => Mode::Baidu,
            _ => Mode::Aliyun
        }
    }
}