#pragma once

// Copyright (C) 2019 Wolf Garbe
// Version: 6.5
// Author: Wolf Garbe wolf.garbe@faroo.com
// Maintainer: Wolf Garbe wolf.garbe@faroo.com
// URL: https://github.com/wolfgarbe/symspell
// Description: https://medium.com/@wolfgarbe/1000x-faster-spelling-correction-algorithm-2012-8701fcd87a5f
//
// MIT License
// Copyright (c) 2019 Wolf Garbe
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// https://opensource.org/licenses/MIT

// algorithm come from https://github.com/AtheS21/SymspellCPP
// MODIFY: I re-implemented the whole algorithm
// @CppCXY: 我修改了整个算法的实现，精简了不需要的部分，修改了不够简练的部分

#include "EditDistance.h"
#include "SuggestItem.h"
#include <map>
#include <cstddef>
#include <cstdint>
#include <unordered_map>
#include <unordered_set>
#include <vector>

class SymSpell {
public:
    enum class Strategy {
        Normal,
        LazyLoaded
    };


    SymSpell(Strategy strategy,
             int maxDictionaryEditDistance = 2,
             int prefixLength = 3);

    bool LoadWordDictionary(std::string path);

    bool LoadWordDictionaryFromBuffer(std::string_view buffer);

    bool CreateDictionaryEntry(const std::string &key, int count);

    bool IsCorrectWord(const std::string &word) const;

    std::vector<SuggestItem> LookUp(const std::string &input);

    std::vector<SuggestItem> LookUp(const std::string &input, int maxEditDistance);

private:
    bool BuildDeletesWords(const std::string &key);

    bool BuildAllDeletesWords();

    std::unordered_set<std::string> EditsPrefix(std::string_view key);

    void Edits(std::string_view word, int editDistance, std::unordered_set<std::string> &deleteWord);

    int GetStringHash(std::string_view source);

    bool DeleteInSuggestionPrefix(std::string_view deleteSuggest, std::size_t deleteLen, std::string_view suggestion,
                                  std::size_t suggestionLen);

    std::size_t _prefixLength;//prefix length  5..7
    uint32_t _compactMask;
    // DistanceAlgorithm distanceAlgorithm = DistanceAlgorithm::DamerauOSADistance;
    std::size_t _maxDictionaryWordLength;//maximum dictionary term length

    int _maxDictionaryEditDistance;
    // Dictionary that contains a mapping of lists of suggested correction words to the hashCodes
    // of the original words and the deletes derived from them. Collisions of hashCodes is tolerated,
    // because suggestions are ultimately verified via an edit distance function.
    // A list of suggestions might have a single suggestion, or multiple suggestions.
    std::map<int, std::vector<std::string>> _deletes;
    // Dictionary of unique correct spelling words, and the frequency count for each word.
    std::unordered_map<std::string, int> _words;

    EditDistance _editDistance;

    Strategy _strategy;
};
