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

 Copyright (C) 2000-2006 Keith Godfrey and Maxym Mykhalchuk
               2006 Henry Pijffers
               2009 Didier Briel
               2010 Martin Fleurke, Antonio Vilei, Alex Buloichik, Didier Briel
               2012 Thomas Cordonnier
               2013 Aaron Madlon-Kay, Alex Buloichik
               2014 Alex Buloichik, Piotr Kulik, 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.search;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.omegat.core.Core;
import org.omegat.core.data.ParseEntry;
import org.omegat.core.data.ProtectedPart;
import org.omegat.core.data.ProjectOptions;
import org.omegat.core.data.SourceTextEntry;
import org.omegat.core.data.IProject.FileInfo;
import org.omegat.filters2.FilterContext;
import org.omegat.filters2.IParseCallback;
import org.omegat.filters2.TranslationException;
import org.omegat.filters2.master.FilterMaster;
import org.omegat.util.StaticUtils;
import org.omegat.gui.search.DirectorySearchWindow;

/**
 * Specific searcher for search in directory
 * 
 * @author Keith Godfrey
 * @author Maxym Mykhalchuk
 * @author Henry Pijffers
 * @author Didier Briel
 * @author Martin Fleurke
 * @author Antonio Vilei
 * @author Alex Buloichik (alex73mail@gmail.com)
 * @author Aaron Madlon-Kay
 * @author Piotr Kulik
 * @author Thomas Cordonnier
 */
public class DirectorySearcher extends Searcher {

    /**
     * Create new searcher instance.
     * 
     * @param properties
     *            Set of project properties, used by file filters. 
     *            Not necessarily from a real project, but all options must be correctly filled.
     */
    public DirectorySearcher(final DirectorySearchWindow window, final ProjectOptions properties, 
         TextExpression text, boolean removeDup, int numberOfResults, String rootDir, boolean recursive) {
        super(window, removeDup, numberOfResults);
        this.m_properties = properties;
        this.m_searchDir = rootDir;
        this.m_searchRecursive = recursive;	
        this.m_textExpr = text;
    }

    // /////////////////////////////////////////////////////////
    // thread main loop
    @Override
    protected void doSearch() throws Exception {
        if (!m_searchDir.endsWith(File.separator))
            m_searchDir += File.separator;

        final FilterMaster fm = Core.getFilterMaster();
        final SearchCallback searchCallback = new SearchCallback(m_properties);
        final FilterContext ctxt = new FilterContext(m_properties);
        
        StaticUtils.iterateFileTree(new File(m_searchDir), m_searchRecursive, 
            (File file) -> {
                 String filename = file.getPath();
                 FileInfo fi = new FileInfo();
                 // determine actual file name w/ no root path info
                 fi.filePath = filename.substring(m_searchDir.length());
 
                 searchCallback.setCurrentFile(fi);
                 fm.loadFile(filename, ctxt, searchCallback);
                 searchCallback.fileFinished();
 
                 checkInterrupted();
             });
    }

    protected class SearchCallback extends ParseEntry implements IParseCallback {
        private File currentFile;

        public SearchCallback(ProjectOptions config) {
            super(config);
        }

        @Override
        public void setCurrentFile(FileInfo fi) {
            super.setCurrentFile(fi);
            currentFile = new File (m_searchDir, fi.filePath);
        }

        @Override
        protected void fileFinished() {
            super.fileFinished();
        }

        @Override
        protected void addSegment(String id, short segmentIndex, String segmentSource,
                List<ProtectedPart> protectedParts, SourceTextEntry.SourceTranslationInfo traInfo, 
                String prevSegment, String nextSegment, String path) {
            if (m_numFinds >= m_maxResults) return;

            checkInterrupted();

            List<SearchMatch> matches = m_textExpr.searchString(segmentSource);
			if (matches != null) {
                String segmentTranslation = traInfo == null ? null : traInfo.getTranslation();
				if ((traInfo != null) && traInfo.sourceTranslationFuzzy && (segmentTranslation != null))
					segmentTranslation += " " + org.omegat.util.OStrings.getString("WF_DEFAULT_PREFIX");
                // found a match - do something about it
                DirectorySearcher.this.addEntry(new FileSearchResultEntry(
					currentFile, segmentSource, segmentTranslation, 
					traInfo == null ? null : traInfo.comment, matches));
            }
        }
    }

    private ProjectOptions m_properties;
    private TextExpression m_textExpr;
    private String m_searchDir;
    private boolean m_searchRecursive;
    
    protected static final int ENTRY_ORIGIN_TEXT = -5;
}
