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

 Copyright (C) 2009 Alex Buloichik
               2010 Arno Peters
               2013-2014 Alex Buloichik
               2015 Aaron Madlon-Kay
               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.statistics;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.omegat.core.Core;
import org.omegat.core.data.IProject.FileInfo;
import org.omegat.core.data.ParseEntry;
import org.omegat.core.data.ProjectOptions;
import org.omegat.core.data.ProtectedPart;
import org.omegat.core.data.SourceTextEntry;
import org.omegat.core.data.TMXEntry;
import org.omegat.filters2.master.FilterMaster;
import org.omegat.filters2.FilterContext;
import org.omegat.filters2.IParseCallback;
import org.omegat.util.OConsts;
import org.omegat.util.OStrings;
import org.omegat.util.StaticUtils;
import org.omegat.util.gui.TextUtil;

import gen.core.filters.Filters;

/**
 * Thread for calculate standard statistics.
 * 
 * Calculation requires two different tags stripping: one for calculate unique and remaining, and second for
 * calculate number of words and chars.
 * 
 * Number of words/chars calculation requires to just strip all tags, protected parts, placeholders(see StatCount.java).
 * 
 * Calculation of unique and remaining also requires to just strip all tags, protected parts, placeholders for
 * standard calculation.
 * 
 * @author Alex Buloichik (alex73mail@gmail.com)
 * @author Arno Peters
 * @author Aaron Madlon-Kay
 */
public class CalcStandardDirectoryStatistics extends CalcStandardStatistics {
    private File m_searchFile;
    private ProjectOptions m_properties;
    private final SearchCallback searchCallback;
    private final FilterMaster fm ;        
    private final FilterContext ctxt;    

    public CalcStandardDirectoryStatistics(IStatisticsPanel.Standard callback, File m_searchFile, final ProjectOptions properties) {
        super(callback); this.m_searchFile = m_searchFile; this.m_properties = properties;
        searchCallback = new SearchCallback(m_properties); ctxt = new FilterContext(m_properties); 
                
        Filters filterMasterConfig = FilterMaster.loadConfig(StaticUtils.getConfigDir());
        if (filterMasterConfig == null) filterMasterConfig = FilterMaster.createDefaultFiltersConfig();
        Core.setFilterMaster(fm = new FilterMaster(filterMasterConfig));
    }

    @Override
    public void run() {
        try {
            if (m_searchFile.isDirectory()) StaticUtils.iterateFileTree(m_searchFile, true, this::treatFile);
            else treatFile(m_searchFile);
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
    
        String result = searchCallback.buildProjectStats(callback);
        callback.setTextData(result);
        callback.finishData();

        File internalDir = m_searchFile.isDirectory() ? m_searchFile : m_searchFile.getParentFile();
        // removing old stats
        try {
            File oldstats = new File(internalDir, "word_counts");
            if (oldstats.exists()) oldstats.delete();
        } catch (Exception e) {
        }

        // now dump file based word counts to disk
        String fn = internalDir + "/" + OConsts.STATS_FILENAME;
        System.out.println("Writing statistics to " + fn);
        Statistics.writeStat(fn, result);
        callback.setDataFile(fn);
    }
    
    private void treatFile (File file) throws Exception {
        String filename = file.getPath();
        FileInfo fi = new FileInfo();
        // determine actual file name w/ no root path info
        fi.filePath = filename.substring(m_searchFile.toString().length());
 
        searchCallback.setCurrentFile(fi);
        fm.loadFile(filename, ctxt, searchCallback);
        searchCallback.fileFinished();
 
        checkInterrupted();    
    }

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

        private FileData global = new FileData(null);
        private List<FileData> counts = new ArrayList<FileData>();
        private FileData lastFileData;
    
        public SearchCallback(ProjectOptions config) {
            super(config);
        }

        @Override
        public void setCurrentFile(FileInfo fi) {
            super.setCurrentFile(fi);
            currentFile = new File (m_searchFile, fi.filePath);
            counts.add(lastFileData = new FileData(fi.filePath));
            global.addFile(lastFileData);
        }

        @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) {
            
            String src = segmentSource;
            if (protectedParts != null)
                for (ProtectedPart pp : protectedParts) 
                    src = src.replace(pp.getTextInSourceSegment(), pp.getReplacementUniquenessCalculation());            
            global.register(src, (traInfo != null) && traInfo.isTranslated());
            lastFileData.register(src, (traInfo != null) && traInfo.isTranslated());
        }
        
        /**
         * Builds a file with statistic info about the project. The total word &
         * character count of the project, the total number of unique segments, plus
         * the details for each file.
         */
        public String buildProjectStats(final IStatisticsPanel.Standard callback) {
            StringBuilder result = new StringBuilder();

            result.append(OStrings.getString("CT_STATS_Project_Statistics"));
            result.append("\n\n");

            String[][] headerTable = calcHeaderTable(new StatCount[] { global.total, global.remaining, global.unique, global.remainingUnique });
            if (callback != null) callback.setProjectTableData(htHeaders, headerTable);
            result.append(TextUtil.showTextTable(htHeaders, headerTable, htAlign));
            result.append("\n\n");

            // STATISTICS BY FILE
            result.append(OStrings.getString("CT_STATS_FILE_Statistics"));
            result.append("\n\n");
            String[][] filesTable = calcFilesTable((m_searchFile.isDirectory() ? m_searchFile : m_searchFile.getParentFile()).toString(), counts);
            if (callback != null) callback.setFilesTableData(ftHeaders, filesTable);
            result.append(TextUtil.showTextTable(ftHeaders, filesTable, ftAlign));

            return result.toString();
        }
        
    }    
}
