//
//  AWFastCheck.cpp
//  aho-corasick
//
//  Created by chenguanglv on 15/12/20.
//  Copyright © 2015年 ibrain. All rights reserved.
//

#include <fstream>
#include <sstream>
#include <cstring>
#include "AWFastCheck.hpp"
#include "ac/ac.h"

using namespace AIWriter;

AWFastCheck::AWFastCheck()
: _trie(new ac::Trie<char, CheckItem>())
, _hasBuild(false)
{
    
}

AWFastCheck::~AWFastCheck()
{
    
}

void AWFastCheck::reset()
{
    _trie.reset(new ac::Trie<char, CheckItem>());
    _checkItems.clear();
    _hasBuild = false;
}

bool AWFastCheck::addDictionary(const char *dicfile)
{
    if (_hasBuild)
    {
        printf("AWERROR:can not add dic file after build.\n");
        return false;
    }
    
    if (!dicfile || dicfile[0] == '\0')
    {
        printf("AWERROR:dicfile can not be NULL or Length = 0.\n");
        return false;
    }
    
    std::fstream f(dicfile);
    if (!f)
    {
        printf("AWERROR:dicfile can not be open.\n");
        return false;
    }
    
    std::string line;
    std::string wrong;
    std::string right;
    std::string wrongType;
    size_t lineCount = 0;
    while (std::getline(f,line))
    {
        lineCount++;
        if (parseDicLine(line,wrong,right,wrongType))
        {
            addCheckItem(wrong.c_str(), right.c_str(), wrongType.c_str());
        }
        else
        {
            printf("AWERROR:%lu line format error.\n",lineCount);
            return false;
        }
    }
    
    return true;
}

bool AWFastCheck::addCheckItem(const char *wrong,const char *right,const char *wrongType)
{
    if (_hasBuild)
    {
        printf("AWERROR:can not add check item after build.\n");
        return false;
    }
    
    if (!wrong || !right || !wrongType || wrong[0] == '\0' || right[0] == '\0' || wrongType[0] == '\0')
    {
        printf("AWERROR:addCheckItem params can not be NULL or Length = 0.\n");
        return false;
    }
    
    _checkItems.push_back(CheckItem(wrong,right,wrongType));
    
    return true;
}

bool AWFastCheck::parseDicLine(std::string& line,std::string& wrong,std::string& right,std::string& wrongType)
{
    std::stringstream ss;
    ss.str(line);
    
    if(ss >> wrong >> right >> wrongType)
    {
        return true;
    }
    
    return false;
}

void AWFastCheck::buildChecker()
{
    if (_hasBuild)
    {
        printf("AWERROR:has build.\n");
        return ;
    }
    
    for (auto& item : _checkItems)
    {
        _trie->insert(ac::ACDef<char>::ACData(item.wrong.cbegin(),item.wrong.cend()),&item);
    }
    
    _trie->build();
    _hasBuild = true;
}

void AWFastCheck::checkText(const char *text,CheckResultVector& result)
{
    if (!text || text[0] == '\0')
    {
        printf("AWERROR:text can not be NULL or Length = 0.\n");
        return ;
    }
    
    checkTextContent(text, result);
}

void AWFastCheck::checkTextFile(const char *textfile,CheckResultVector& result)
{
    if (!textfile || textfile[0] == '\0')
    {
        printf("AWERROR:textfile can not be NULL or Length = 0.\n");
        return ;
    }
    
    std::fstream f(textfile);
    
    if (!f)
    {
        printf("AWERROR:textfile can not be opened.\n");
        return ;
    }
    
    std::istreambuf_iterator<char> begin(f);
    std::istreambuf_iterator<char> end;
    std::string text(begin,end);
    
    checkTextContent(text.c_str(), result);
}

void AWFastCheck::checkTextContent(const char *text,CheckResultVector& result)
{
    auto results = _trie->parse(ac::ACDef<char>::ACData(text,text + std::strlen(text)));
    
    for (auto &r : results)
    {
        result.push_back(CheckResult(std::string(r.getEmitResult().cbegin(),r.getEmitResult().cend()).c_str(), r.getUserData()->right.c_str(), r.getUserData()->wrongType.c_str(), r.getBegin(), r.getEnd()));
    }
}

