package jp.ac.osaka_u.ist.sel.similarity.csv;

import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jp.ac.osaka_u.ist.sel.similarity.commons.ArgumentParser;
import jp.ac.osaka_u.ist.sel.similarity.commons.Settings;
import jp.ac.osaka_u.ist.sel.similarity.csv.database.CsvWriterDAOManager;
import jp.ac.osaka_u.ist.sel.similarity.csv.database.SelectionCloneDAO;
import jp.ac.osaka_u.ist.sel.similarity.csv.database.SelectionDomainDAO;
import jp.ac.osaka_u.ist.sel.similarity.csv.database.SelectionFileDAO;
import jp.ac.osaka_u.ist.sel.similarity.csv.database.SelectionHashDAO;
import jp.ac.osaka_u.ist.sel.similarity.csv.database.object.FileCsvInfo;
import jp.ac.osaka_u.ist.sel.similarity.database.ColumnName;
import jp.ac.osaka_u.ist.sel.similarity.fileclone.register.CloneRegisterMain;
import jp.ac.osaka_u.ist.sel.similarity.hash.HashRegisterMain;
import jp.ac.osaka_u.ist.sel.similarity.register.FileRegisterMain;

/**
 * Export information about file clones into a csv file.
 * (only if -o option is specified.)
 * 
 * @author Ares
 *
 */
public class CsvWriterMain {

    public static void main(String[] args) throws SQLException {
        if (!ArgumentParser.parseArgument(args)) {
            return;
        }

        Settings settings = Settings.getInstance();

        CloneRegisterMain.main(args);
        
        String csvPath = Settings.getInstance().getCsvPath();
        if (csvPath == null) {
            return;
        }
        
        CsvWriterDAOManager selectionDAOManager = null;
        try {
            selectionDAOManager = new CsvWriterDAOManager(settings.getDatabasePath());
            exportCsv(csvPath, selectionDAOManager);
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            try {
                if (selectionDAOManager != null) {
                    selectionDAOManager.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    
    private static void exportCsv(String csvPath, CsvWriterDAOManager selectionDAOManager) throws SQLException, IOException {
        SelectionCloneDAO cloneDAO = selectionDAOManager.getFileCloneDAO();
        Map<Integer,Integer> mappedIdData = cloneDAO.getMappedData();
        // get cloned files
        Map<Integer,List<Integer>> listedIdData = new HashMap<Integer,List<Integer>>();
        for (int fileId : mappedIdData.keySet()) {
            int cloneId = mappedIdData.get(fileId);
            
            List<Integer> fileIdList = listedIdData.get(cloneId);
            if (fileIdList == null) {
                fileIdList = new ArrayList<Integer>();
            }
            fileIdList.add(fileId);
            listedIdData.put(cloneId, fileIdList);
        }
        // header names
        List<String> headers = new ArrayList<String>();
        headers.add(ColumnName.GROUP_ID.toString());
        headers.add(ColumnName.DOMAIN_ID.toString());
        headers.add(ColumnName.PATH.toString());
        headers.add(ColumnName.EXT.toString());
        headers.add(ColumnName.FILE_SIZE.toString());
        headers.add(ColumnName.MD5_HASH.toString());
        // table data
        List<Map<String,String>> table = new ArrayList<Map<String,String>>();
        // get DAO instances
        SelectionDomainDAO domainDAO = selectionDAOManager.getDomainDAO();
        SelectionFileDAO fileDAO = selectionDAOManager.getFileDAO();
        SelectionHashDAO hashDAO = selectionDAOManager.getHashDAO();
        // specify cloned files
        for (int cloneId : listedIdData.keySet()) {
            List<Integer> fileIdList = listedIdData.get(cloneId);
            if (fileIdList.size() < 2) {
                continue;
            }
            for (int fileId : fileIdList) {
                Map<String,String> mappedData = new HashMap<String,String>();
                String columnName = null;
                String value = null;
                // group ID
                columnName = ColumnName.GROUP_ID.toString();
                value = String.valueOf(cloneId);
                mappedData.put(columnName, value);
                // get file details
                FileCsvInfo fileInfo = fileDAO.getData(fileId);
                // path
                columnName = ColumnName.PATH.toString();
                value = fileInfo.getPath();
                mappedData.put(columnName, value);
                // ext
                columnName = ColumnName.EXT.toString();
                value = fileInfo.getExt();
                mappedData.put(columnName, value);
                // size
                columnName = ColumnName.FILE_SIZE.toString();
                value = String.valueOf(fileInfo.getSize());
                mappedData.put(columnName, value);
                // domain name
                columnName = ColumnName.DOMAIN_ID.toString();
                int domainId = fileInfo.getDomainId();
                value = domainDAO.getName(domainId);
                mappedData.put(columnName, value);
                // hash value
                columnName = ColumnName.MD5_HASH.toString();
                value = asHexString(hashDAO.getHash(fileId));
                mappedData.put(columnName, value);
                // add data
                table.add(mappedData);
            }
        }
        // file for export
        File file = new File(csvPath);
        // export
        CloneCsvExporter.export(file, headers, table);
    }

    public static String asHexString(List<Byte> bytes) {
        StringBuffer buffer = new StringBuffer(bytes.size() * 2);

        for (int i=0;i<bytes.size();i++) {
            int code = bytes.get(i);
            code &= 0xff;
            if (code < 16) {
                buffer.append('0');
            }
            buffer.append(Integer.toHexString(code));
        }

        return buffer.toString();
    }

    
}
