package it.cnr.istc.stlab.mira.altmetrics.plum;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Option.Builder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
import org.openrdf.model.Model;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.impl.LinkedHashModel;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.model.vocabulary.RDFS;
import org.openrdf.rio.RDFHandlerException;
import org.openrdf.rio.RDFParseException;
import org.openrdf.rio.RDFParser;
import org.openrdf.rio.RDFWriter;
import org.openrdf.rio.helpers.StatementCollector;
import org.openrdf.rio.turtle.TurtleParserFactory;
import org.openrdf.rio.turtle.TurtleWriterFactory;

import com.bigdata.rdf.internal.XSD;

import it.cnr.istc.stlab.mira.commons.QualificationProcessOntology;

public class DisciplinaryAreaPlumScraper {

	
	public static final String DISCIPLINARY_AREA_OPTION = "d";
	public static final String DISCIPLINARY_AREA_OPTIONS_LONG = "discipline";
	
	public static final String APPEND_OPTION = "a";
	public static final String APPEND_OPTIONS_LONG = "append";
	
	public static final String QUALIFICATION_LEVEL_OPTION = "l";
	public static final String QUALIFICATION_LEVEL_OPTIONS_LONG = "level";
	
	public static final String OUTPUT_OPTION = "o";
	public static final String OUTPUT_OPTIONS_LONG = "output";
	
	public static void main(String[] args) {
		
		Options options = new Options();
		
		Builder optionBuilder = Option.builder(OUTPUT_OPTION);
        Option outputOption = optionBuilder.argName("folder")
                .desc("The name of the folder where to store the resulting RDF..")
                .hasArg()
                .required(true)
                .longOpt(OUTPUT_OPTIONS_LONG)
                .build();
        
        optionBuilder = Option.builder(DISCIPLINARY_AREA_OPTION);
        Option disciplinaryAreaOption = optionBuilder.argName("string")
                .desc("The code of the disciplinary area.")
                .hasArg()
                .required(true)
                .longOpt(DISCIPLINARY_AREA_OPTIONS_LONG)
                .build();
        
        optionBuilder = Option.builder(QUALIFICATION_LEVEL_OPTION);
        Option qualificationLevelOption = optionBuilder.argName("string")
                .desc("The level of qualification. Valid levels are 1 and 2")
                .hasArg()
                .required(true)
                .longOpt(QUALIFICATION_LEVEL_OPTIONS_LONG)
                .build();
        
        optionBuilder = Option.builder(APPEND_OPTION);
        Option appendOption = optionBuilder.argName("append")
                .desc("If append mode is declared then already available outputs are not overwritten.")
                .required(false)
                .longOpt(APPEND_OPTION)
                .build();
        
        options.addOption(outputOption);
        options.addOption(disciplinaryAreaOption);
        options.addOption(qualificationLevelOption);
        options.addOption(appendOption);
		
		CommandLine commandLine = null;
        
        CommandLineParser cmdLineParser = new DefaultParser();
        try {
            commandLine = cmdLineParser.parse(options, args);
        } catch (ParseException e) {
            HelpFormatter formatter = new HelpFormatter();
            formatter.printHelp( "citationCounter", options );
        }
        
		if(commandLine != null){
        	String[] arguments = commandLine.getArgs();
        	if(arguments.length != 1){
        		System.out.println("No correct arguments provided as input.");
        		System.exit(0);
        	}
        	
        	String sessionFolderPath = commandLine.getArgs()[0];
        	File sessionFolder = new File(sessionFolderPath);
        	if(!sessionFolder.exists() || !sessionFolder.isDirectory()){
        		System.out.println("The folder representing the session does not exist.");
        		System.exit(0);
        	}
        	
        	String qualificationLevel = null;
        	if(commandLine.hasOption(QUALIFICATION_LEVEL_OPTION)){
				String value = commandLine.getOptionValue(QUALIFICATION_LEVEL_OPTION);
				if(value != null){
					try{
						Integer lev = Integer.valueOf(value.trim());
						
						if(lev == 1) qualificationLevel = "fascia-1";
						else if(lev == 2) qualificationLevel = "fascia-2";
					} catch(NumberFormatException e){
						e.printStackTrace();
					}
					
				
				}
			}
        	
        	boolean append = commandLine.hasOption(APPEND_OPTION);
        	
        	String disciplinaryAreaCode = null;
        	if(commandLine.hasOption(DISCIPLINARY_AREA_OPTION)){
				String value = commandLine.getOptionValue(DISCIPLINARY_AREA_OPTION);
				if(value != null) disciplinaryAreaCode = value.trim();
			}
        	
        	File rdfOutFolder = null;
        	File jsonOutFolder = null;
        	if(commandLine.hasOption(OUTPUT_OPTION)){
				String value = commandLine.getOptionValue(OUTPUT_OPTION);
				if(value != null) {
					File outFolder = new File(value.trim());
					outFolder.mkdirs();
					
					rdfOutFolder = new File(outFolder, "rdf");
					jsonOutFolder = new File(outFolder, "json");
				}
			}
        	
        	System.out.println("Level: " + qualificationLevel + " - Area: " + disciplinaryAreaCode);
        	File rdfQlOutFolder = new File(rdfOutFolder, qualificationLevel);
        	File rdfDaOutFolder = new File(rdfQlOutFolder, disciplinaryAreaCode);
        	File jsonQlOutFolder = new File(jsonOutFolder, qualificationLevel);
        	File jsonDaOutFolder = new File(jsonQlOutFolder, disciplinaryAreaCode);
        	
        	rdfDaOutFolder.mkdirs();
        	jsonDaOutFolder.mkdirs();
        	
        	if(qualificationLevel != null && disciplinaryAreaCode != null){
        		
        		File qualificationLevelFolder = new File(sessionFolderPath, qualificationLevel);
        		if(qualificationLevelFolder.exists() && qualificationLevelFolder.isDirectory()){
        			File disciplinaryAreaFolder = new File(qualificationLevelFolder, disciplinaryAreaCode);
        			if(disciplinaryAreaFolder.exists() && disciplinaryAreaFolder.isDirectory()){
        				File[] rdfFiles = disciplinaryAreaFolder.listFiles(f->f.getName().endsWith(".ttl"));
        				List<File> files = new ArrayList<File>();
        				Collections.addAll(files, rdfFiles);
        				
        				files.parallelStream().forEach(rdfFile -> {
        					System.out.println(rdfFile.getName());
        					Model outModel = new LinkedHashModel();
        					
        					
        					File outRDFFile = new File(rdfDaOutFolder, rdfFile.getName());
        					File outJSONFile = new File(jsonDaOutFolder, rdfFile.getName().replace(".ttl", ".json"));
        					
        					boolean execute = true;
        					if(append){
        						if(outRDFFile.exists() && outJSONFile.exists())
        							execute = false;
        					}
        					
        					if(execute){
	        					RDFParser parser = new TurtleParserFactory().getParser();
	        					Model model = new LinkedHashModel();
	        					StatementCollector collector = new StatementCollector(model);
	        					parser.setRDFHandler(collector);
	        					try {
									parser.parse(new FileInputStream(rdfFile), QualificationProcessOntology.NS);
									
									outModel.addAll(model);
									JSONObject plumJsonObject = new JSONObject();
									model.filter(null, QualificationProcessOntology.doi, null).forEach(stmt -> {
										
										URI publication = (URI)stmt.getSubject();
										
										String doi = stmt.getObject().stringValue();
										if(doi != null){
											doi = doi.replace("http://dx.doi.org/", "");
											
											JSONArray plumJsonArray = PlumScraper.scrape(doi);
											Model altmetricsModel = PlumScraper.json2rdf(publication, plumJsonArray);
											
											outModel.addAll(altmetricsModel);
											try {
												plumJsonObject.put(publication.getLocalName(), plumJsonArray);
											} catch (Exception e) {
												// TODO Auto-generated catch block
												e.printStackTrace();
											}
										}
									});;
									
									OutputStream out = new FileOutputStream(outRDFFile);
									RDFWriter writer = new TurtleWriterFactory().getWriter(out);
									writer.handleNamespace("ref-list", "http://w3id.org/anvur/nq/data/reference-list/");
									writer.handleNamespace("biblio-item", "http://w3id.org/anvur/nq/data/bibliographic-item/");
									writer.handleNamespace("biblio-item-type", "http://w3id.org/anvur/nq/data/bibliographic-item-type/");
									writer.handleNamespace("application", "http://w3id.org/anvur/nq/data/application/");
									writer.handleNamespace("person", "http://w3id.org/anvur/nq/data/person/");
									writer.handleNamespace("resume", "http://w3id.org/anvur/nq/data/resume/");
									writer.handleNamespace("qualification-type", "http://w3id.org/anvur/nq/data/qualification-type/");
									writer.handleNamespace("qualification", "http://w3id.org/anvur/nq/data/qualification/");
									writer.handleNamespace("qualification-list", "http://w3id.org/anvur/nq/data/qualification-list/");
									writer.handleNamespace("publication", "http://w3id.org/anvur/nq/data/publication/");
									writer.handleNamespace("ont", "http://w3id.org/anvur/nq/ontology/");
									writer.handleNamespace("rdf", RDF.NAMESPACE);
									writer.handleNamespace("rdfs", RDFS.NAMESPACE);
									writer.handleNamespace("xsd", XSD.NAMESPACE);
									
									writer.startRDF();
									for(Statement stmt : outModel)
										writer.handleStatement(stmt);
									writer.endRDF();
									
									out.close();
									
									
									BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(outJSONFile));
									try {
										bufferedWriter.write(plumJsonObject.toString(4));
									} catch (Exception e) {
										// TODO Auto-generated catch block
										e.printStackTrace();
									}
									bufferedWriter.close();
									
								} catch (RDFParseException | RDFHandlerException | IOException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
        					}
        				});
        			}
        		}
        	}
		}	
		
    
		
		
	}
}
