/**
 * 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/>.
 */
use std::collections::HashSet;
use std::iter::FromIterator;

// 文字列 → [文字列配列]
const ARR_ELM: [&str; 38] = [
    // ※ は空白に関してブロック要素のように振る舞うタグ
    "address",    // 連絡先情報
    "article",    // 記事コンテンツ
    "aside",      // 本論から外れたコンテンツ
    "blockquote", // 長い「ブロック」の引用
    "br",         // ※ (改行)
    "dd",         // 定義リストで用語を説明
    "details",    // 折りたたみウィジェット
    "dialog",     // ダイアログボックス
    "div",        // 文書の一部
    "dl",         // 定義リスト
    "dt",         // 定義語リストの用語
    "fieldset",   // フィールドセットのラベル
    "figcaption", // 図表のキャプション
    "figure",     // キャプション(figcaption)を伴うメディアコンテンツをグループ化
    "footer",     // セクションまたはページのフッター
    "form",       // 入力フォーム
    "h1",         // 見出しレベル 1-6
    "h2",         //
    "h3",         //
    "h4",         //
    "h5",         //
    "h6",         //
    "header",     // セクションまたはページのヘッダー
    "hgroup",     // 見出し情報をグループ化
    "hr",         // 水平線 (区切り線)
    "li",         // リストの項目
    "main",       // この文書で固有の中心的なコンテンツを含む
    "nav",        // ナビゲーションのリンクを含む
    "ol",         // 番号付きリスト
    "pre",        // 整形済みテキスト
    "p",          // 段落
    "section",    // ウェブページのセクション
    "table",      // 表
    "td",         // ※ (表のデータ)
    "th",         // ※ (表のヘッダ)
    "tr",         // ※ (表の行部分)
    "title",      // ※ (文書の題名)
    "ul",         // 番号なしリスト
];

/*
 * LAZY initialization - 遅延初期化
 */
lazy_static! {
    /*
    // 文字列 → Vector → HashSet
    static ref LAZY_ARR: Vec<&'static str> = vec!["a", "c", "e", "g"];
    static ref LAZY_SET: HashSet<&'static str> = HashSet::from_iter(LAZY_ARR.iter().cloned());
     */
    // [文字列配列] → HashSet
    static ref LAZY_SET: HashSet<&'static str> = HashSet::from_iter(ARR_ELM.iter().cloned());
}
// find block element
pub fn find(tag: &str) -> String {
    let input: String = tag.to_lowercase(); // copyed and new ownership
    let key: &str = &input; // cast
    let boo: bool = (*LAZY_SET).contains(key);
    if boo {
        input
    } else {
        "".to_string()
    }
}

/**
* const、static どちらも値に対してそれらが定数式でなければならないという要件があります。
* 言い換えると、関数の呼び出しのような複雑なものや実行時の値を指定することはできません。
* すなわち、初期化に使う式はコンパイル時に評価できるものでなくてはなりません。
*
  const empty_str: String = "".to_string(); // コンパイルエラー
*/

/* Local value - 変数定義はできるがローカル変数では実用的でない
 * 文字列 → Vector → HashSet
 */
fn _lazy_test01() {
    // let arr: Vec<&str> = vec!["a", "c", "e", "g"]; // グローバル定義できない
    // let set: HashSet<&str> = HashSet::from_iter(arr.iter().cloned());
    // println!("arr: {:?}", arr);
    // println!("set: {:?}", set);
}

/*
 * [ソート済み文字列配列] → リニアサーチ
 * ※ 実装を諦めかけて書いたルーチン
 */
fn _lazy_test02(tag: &str) -> String {
    let input: String = tag.to_lowercase().to_owned(); // clone and new ownership
    let key: &str = input.as_str(); // cast
    for xx in &ARR_ELM {
        let x: &str = xx; // cast
        if key <= x {
            // compareTO() は無さげ
            if key == x {
                println!("match: {:?}", key);
                return input;
            } else {
                // これより後では一致しない場合
                println!("exit: {:?}", key);
                return "".to_string();
            }
        }
    }
    "".to_string() // 参照(&str)を返すと怒られるので(String)を返す
}
#[test]
fn test() {
    // println!("ARR_ELM: {:?}", ARR_ELM); // "a", "c", "e", "g"
    // println!("LAZY_SET: {:?}", *LAZY_SET);
    // println!("Test: Sequential search");
    assert_eq!("br", _lazy_test02("br"));
    assert_eq!("", _lazy_test02("h7"));
    assert_eq!("", _lazy_test02("z"));

    // println!("Test:  block element");
    assert_eq!("br", find("BR"));
    assert_eq!("", find("h7"));
    assert_eq!("", find("b"));
}

pub fn run() {
    assert_eq!("br", find("BR"));
    assert_eq!("", find("h7"));
    assert_eq!("", find("b"));
}
