/**
 * Copyright (C) 2023 awk4j - https://ja.osdn.net/projects/awk4j/
 * <p>
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 * <p>
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * <p>
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#[macro_use]
extern crate lazy_static;
use std::env;
use std::io::Write;

mod atomic;
mod iomod;
mod lazyset;
mod parser;

const DIR_: &str = "_TMP/"; // 省略値
const INPUT_: &str = "SAMPLE.html";
const DEBUG_: &str = "~debug.html";
/**
 * Initialize - Command line parameter analysis
 */
fn initialize() -> (String, String, String) {
    let args: Vec<String> = env::args().collect();
    let len = args.len();
    if len < 3 {
        let message =
            iomod::red("パラメータが省略されているため、ディフォルト値を使用します".to_string());
        eprintln!("{}: {:?}", message, args);
    }
    let dir: &str = if len > 1 { &args[1] } else { DIR_ };
    let target: &str = if len > 2 { &args[2] } else { INPUT_ };
    if dir.is_empty() {
        let message = iomod::red("作業フォルダが指定されていません！".to_string());
        panic!("{} {:?}", message, dir);
    }
    let input_: String = iomod::new_path(dir, target);
    let debug_: String = iomod::new_path(dir, DEBUG_);
    println!("{}: {:?} → {:?}", iomod::blue("Input File"), target, input_);
    println!("{}: {:?}", iomod::blue("Output File"), target);
    println!("{}: {:?}", iomod::blue("Debug File"), debug_);
    iomod::mkdir(dir);
    iomod::copy(target, &input_);
    (input_, target.to_string(), debug_)
}

/**
 * main
 */
fn main() {
    let (input_, target_, debug_) = initialize();

    let mut message: String = String::new();
    let (mut rfd, mut reader) = iomod::open_reader(&input_);
    let (mut wfd, mut writer) = iomod::open_writer(&target_);
    let (mut dfd, mut debuger) = iomod::open_writer(&debug_);
    loop {
        let (_rfd, _reader) = iomod::read(rfd, reader);
        reader = _reader;
        rfd = _rfd.clone();
        if _rfd.eof {
            break;
        }
        let (output, debug, _message) = parser::parse(rfd.clone());
        wfd.buf = output;
        dfd.buf = debug;
        message = _message;

        let (_wfd, _writer) = iomod::write(wfd.clone(), writer);
        writer = _writer;
        wfd = _wfd.clone();
        let (_dfd, _debuger) = iomod::write(dfd.clone(), debuger);
        debuger = _debuger;
        dfd = _dfd.clone();
    }
    dfd.buf = message.clone();
    let (_dfd, _debuger) = iomod::write(dfd.clone(), debuger);
    debuger = _debuger;
    println!("{}", message);
    let _ = writer.flush();
    let _ = debuger.flush();

    run();
}

// Test
fn run() {
    atomic::run();
    iomod::run();
    lazyset::run();
}

/*
Rust には2つの文字列型があります。
&str - 文字列スライスとも呼ばれるプリミティブな文字列型。
String - 標準ライブラリの提供する文字列型。文字列操作などに使う。
ざっくり理解すると借用が &str で、所有権があるのが String と覚えておくとよさげです。
*/
fn _strings() {
    // 文字列リテラルは &str
    let _a: &str = "hello";

    // String -> &str
    let _b: &str = String::from("hello").as_str();

    // String の初期化
    let _c: String = String::from("hello");

    // &str -> String
    let _d: String = "hello".to_string();

    // String -> &str
    let _e: &str = _c.as_str();

    // String -> &str
    let _e: &str = &_c;

    // Mutable variable
    let mut _d: String = String::new();
    _d += "ABC";
    _d += "def";
    println!("mut String {:?}", _d);
    assert_eq!(_d, "ABCdef");

    let _ch1: char = _a.chars().nth(0).unwrap();
    let _ch2: &str = &_a[..3];
}
