package de.ugoe.cs.cpdp.loader;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.json.JSONObject;

import de.ugoe.cs.cpdp.IParameterizable;
import weka.core.Attribute;
import weka.core.DenseInstance;
import weka.core.Instances;

/**
 * Loader for CSV data generated by mynbou. 
 * @author sherbold
 */
public class MynbouDataLoader implements SingleVersionLoader, IBugMatrixLoader, IParameterizable {

	/**
	 * the bug matrix
	 */
	private Instances bugMatrix = null;
	
	/**
	 * Date of the release
	 */
	private LocalDateTime releaseDate = null;
	
	/**
     * names of the attributes to be kept (determined by {@link #setParameter(String)})
     */
    private ArrayList<String> attributeNames = new ArrayList<>();

    /**
     * Sets that attributes that will be kept. The string contains the blank-separated regular expressions of the
     * attributes to be kept. <br>
     * <br>
     * Note, that the regular expressions currently must not contain whitespaces.
     * 
     * @param parameters
     *            string with the blank-separated attribute names
     */
    @Override
    public void setParameter(String parameters) {
        if (parameters != null) {
            String[] attributeNamesArray = parameters.split(" ");
            for (String attributeName : attributeNamesArray) {
                this.attributeNames.add(attributeName);
            }
        }
    }
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see de.ugoe.cs.cpdp.loader.AbstractFolderLoader.SingleVersionLoader#load(
	 * java.io.File)
	 */
	@Override
	public Instances load(File file, boolean binaryClass) {

		final String[] lines;
		try {
			List<String> stringList = Files.readAllLines(file.toPath());
			lines = stringList.toArray(new String[] {});
		} catch (IOException e) {
			throw new RuntimeException(e);
		}

		// configure Instances
		final ArrayList<Attribute> atts = new ArrayList<>();

		String[] lineSplit = lines[0].split(";");
		List<Integer> usedAttributes = new ArrayList<>();
		int index = 1;
		while (!"imports".equals(lineSplit[index])) {
			String curAttribute = lineSplit[index];
			boolean hasMatch = false;
        	for( String regex : attributeNames ) {
        		if( curAttribute.matches(regex) ) {
        			hasMatch = true;
        		}
        	}
        	if( hasMatch || attributeNames.isEmpty() ) {
        		atts.add(new Attribute(curAttribute));
        		usedAttributes.add(index);
        	}
			index++;
		}
		final int importIndex = index;
		Attribute classAtt;
		if (binaryClass) {
			// add nominal class attribute
			final ArrayList<String> classAttVals = new ArrayList<>();
			classAttVals.add("0");
			classAttVals.add("1");
			classAtt = new Attribute("bug", classAttVals);
		} else {
			// add numeric class attribute
			classAtt = new Attribute("bugs");
		}
		atts.add(classAtt);

		final Instances data = new Instances(file.getName(), atts, 0);
		data.setClass(classAtt);

		// fetch data
		for (int i = 1; i < lines.length; i++) {
			lineSplit = lines[i].split(";");
			double[] values = new double[usedAttributes.size()+1];
			for (int j = 0; j < values.length - 1; j++) {
				values[j] = Double.parseDouble(lineSplit[usedAttributes.get(j)].trim());
			}
			if (binaryClass) {
				// nominal class value
				values[values.length - 1] = lineSplit[importIndex + 1].trim().equals("0") ? 0 : 1;
			} else {
				// numeric class value
				values[values.length - 1] = Double.parseDouble(lineSplit[importIndex + 1].trim());
			}
			data.add(new DenseInstance(1.0, values));
		}

		// create issue matrix
		final ArrayList<Attribute> issueMatrixAtts = new ArrayList<>();
		index = importIndex + 2;
		lineSplit = lines[0].split(";");
		while (index < lineSplit.length) {
			issueMatrixAtts.add(new Attribute(lineSplit[index]));
			index++;
		}
		bugMatrix = new Instances(file.getName(), issueMatrixAtts, 0);
		for (int i = 1; i < lines.length; i++) {
			lineSplit = lines[i].split(";");
			double[] values = new double[issueMatrixAtts.size()];
			for (int j = 0; j < values.length - 1; j++) {
				values[j] = Double.parseDouble(lineSplit[j + importIndex + 2].trim());
			}
			bugMatrix.add(new DenseInstance(1.0, values));
		}

		// read metadata
		File jsonFile = new File(file.getAbsolutePath().replace("_aggregated.csv", ".json"));
		String jsonData = null;
        try {
            jsonData = FileUtils.readFileToString(jsonFile);
        }
        catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        JSONObject metadata = new JSONObject(jsonData);
        String dateString = metadata.getString("release_date");
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        this.releaseDate = LocalDateTime.parse(dateString, formatter); 

        return data;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see de.ugoe.cs.cpdp.loader.AbstractFolderLoader.SingleVersionLoader#
	 * filenameFilter(java.lang.String)
	 */
	@Override
	public boolean filenameFilter(String filename) {
		return filename.endsWith(".csv");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see de.ugoe.cs.cpdp.loader.IBugMatrixLoader#getBugMatrix()
	 */
	@Override
	public Instances getBugMatrix() {
		return bugMatrix;
	}
	
	/**
	 * Returns the date of the loaded release
	 * @return date of the release; null if not yet loaded
	 */
	public LocalDateTime getReleaseDate() {
		return this.releaseDate;
	}

}

@@ -4334,36 +4334,32 @@
  %3C values.length
- - 1
 ; j++) %7B%0D%0A%09%09%09%09va

Fix bug in mynbou loader. Ignored last bug column