/**************************************************************************
 OmegaT - Computer Assisted Translation (CAT) tool 
          with fuzzy matching, translation memory, keyword search, 
          glossaries, and translation leveraging into updated projects.

 Copyright (C) 2010 Alex Buloichik
               2015 Thomas Cordonnier
               Home page: http://www.omegat.org/
               Support center: http://groups.yahoo.com/group/OmegaT/

 This file is part of OmegaT.

 OmegaT 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.

 OmegaT 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.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 **************************************************************************/

package org.omegat.core.spellchecker;

import java.util.ArrayList;
import java.util.List;

import javax.swing.event.DocumentEvent;
import javax.swing.text.Highlighter.HighlightPainter;

import org.omegat.core.Core;
import org.omegat.core.data.SourceTextEntry;
import org.omegat.gui.editor.MarkerController;
import org.omegat.gui.editor.UnderlineFactory;
import org.omegat.gui.editor.mark.IFastMarker;
import org.omegat.gui.editor.mark.Mark;
import org.omegat.tokenizer.ITokenizer.StemmingMode;
import org.omegat.util.Token;
import org.omegat.util.gui.Styles;

/**
 * Spell checker marker implementation. All words for displayed file will be
 * cached, because check spelling is enough long operation.
 * 
 * @author Alex Buloichik (alex73mail@gmail.com)
 * @author Thomas Cordonnier
 */
public class SpellCheckerMarker implements IFastMarker {
    protected static final HighlightPainter PAINTER = new UnderlineFactory.WaveUnderline(Styles.EditorColor.COLOR_SPELLCHECK.getColor());

    @Override
    public List<Mark> getMarksForEntry(SourceTextEntry ste, String sourceText, String translationText, boolean isActive)
            throws Exception {
        if (translationText == null) {
            // translation not displayed
            return null;
        }
        if (!Core.getEditor().getSettings().isAutoSpellChecking()) {
            // spell checker disabled
            return null;
        }
        return check (translationText, 0, translationText.length());
    }
    
    /** 
     * Returns markers for tokens which are, almost partially, in the checkStart-checkEnd interval
     **/
    private static List<Mark> check (String translationText, int checkStart, int checkEnd) throws Exception {
        List<Mark> result = new ArrayList<Mark>();
        for (Token tok : Core.getProject().getTargetTokenizer().tokenizeWords(translationText, StemmingMode.NONE)) {
            int tokStart = tok.getOffset();
            int tokEnd = tok.getOffset() + tok.getLength();
            if (tokStart > checkEnd) continue; if (tokEnd < checkStart) continue;
            String word = tok.getTextFromString(translationText);
            if (!Core.getSpellChecker().isCorrect(word)) {
                Mark m = new Mark(Mark.ENTRY_PART.TRANSLATION, tokStart, tokEnd);
                m.painter = PAINTER;
                result.add(m);
            }
        }
        return result;
    }
    
    /** Remove all markers which are, even partially, in the doc event bounds **/
    public List<MarkerController.MarkInfo> toRemove (DocumentEvent ev, List<MarkerController.MarkInfo> oriList) {
        if (!Core.getEditor().getSettings().isAutoSpellChecking()) return java.util.Collections.EMPTY_LIST;
        
        List<MarkerController.MarkInfo> res = new ArrayList<MarkerController.MarkInfo> (1 + ev.getLength() / 5);
        for (MarkerController.MarkInfo ori: oriList)
            if (ori.highlight != null)
                if (ori.highlight.getEndOffset() < ev.getOffset()) continue;
                else if ((ev.getType() == DocumentEvent.EventType.INSERT) && (ori.highlight.getStartOffset() > ev.getOffset() + ev.getLength())) continue;
                else if ((ev.getType() == DocumentEvent.EventType.REMOVE) && (ori.highlight.getStartOffset() > ev.getOffset())) continue;
                else res.add (ori);
        return res;
    }
    
    /** Calls spellchecker only for words which are, even partially, in the doc event bounds **/
    public List<Mark> toAdd (DocumentEvent ev) throws Exception {
        if (!Core.getEditor().getSettings().isAutoSpellChecking()) return java.util.Collections.EMPTY_LIST;
        
        org.omegat.gui.editor.Document3 doc = (org.omegat.gui.editor.Document3) ev.getDocument();
        String translationText = doc.getText(doc.getTranslationStart(), doc.getTranslationEnd() - doc.getTranslationStart());
        return check (translationText, ev.getOffset() - doc.getTranslationStart(), ev.getOffset() + ev.getLength() - doc.getTranslationStart());        
    }		

    /** Remove all markers which are, even partially, in the doc event bounds **/
    public List<MarkerController.MarkInfo> toRemove (String newTra, List<MarkerController.MarkInfo> oriList) {
        if (!Core.getEditor().getSettings().isAutoSpellChecking()) return java.util.Collections.EMPTY_LIST;        
        return oriList; // Since we put only markers on translation, better to remove everything
    }
    
    /** Calls spellchecker only for words which are, even partially, in the doc event bounds **/
    public List<Mark> toAdd (String newTra) throws Exception {
        if (!Core.getEditor().getSettings().isAutoSpellChecking()) return java.util.Collections.EMPTY_LIST;
        if (newTra == null) return java.util.Collections.EMPTY_LIST;
        // recalculate 
        return check (newTra, 0, newTra.length());
    }		
    
}
