package eu.dnetlib.data.claims.migration;

import eu.dnetlib.data.claims.migration.entity.*;
import eu.dnetlib.data.claimsDemo.ClaimUtils;
import org.apache.log4j.Logger;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.PrintWriter;

/**
 * Created by argirok on 21/1/2016.
 */
public class ClaimValidation {
    private PrintWriter out;
    String pathToSaveReport = null;

    private static Logger logger = Logger.getLogger(ClaimValidation.class);

    /*
    Claim:
    Mandatory Fields : id, sourceType,targetType, User e-mail, Date, Target, Source

    */
    public  boolean validateClaim(Claim claim){
        logger.info("Validating...");
        boolean isValid=true;
        try {
            out = new PrintWriter(new BufferedWriter(new FileWriter(pathToSaveReport+"/validationFile.txt", true)));

        } catch (Exception e) {
            out = null;
            logger.error("Couldn't write to file " + "validationFile.txt", e);
        }

              if(claim==null){
                isValid=false;
                if(out!=null) {
                    out.println("Claim invalid (null)...");
                }
                logger.warn("Claim invalid (null)...");
//            }else if(claim.getId()==null||claim.getId().isEmpty()){
//                isValid=false;
//                 out.println("Claim invalid  (id)..." );
             }else if(claim.getTargetType()==null||claim.getTargetType().isEmpty()){
                isValid=false;
                if(out!=null) {
                    out.println("Claim invalid (target type): " + claim.getId());
                }
                logger.warn("Claim invalid (target type): "+claim.getId());

            }else if(claim.getSourceType()==null||claim.getSourceType().isEmpty()){
                isValid=false;
                if(out!=null) {
                    out.println("Claim invalid (source type): " + claim.getId());
                }
                logger.warn("Claim invalid (source type): "+claim.getId());

            }else if(claim.getDate()==null){
                isValid=false;
                if(out!=null) {
                    out.println("Claim invalid (date): " + claim.getId());
                }
                logger.warn("Claim invalid (date): "+claim.getId());

            }else if(claim.getUserMail()==null||claim.getUserMail().isEmpty()){
                isValid=false;
                 if(out!=null) {
                     out.println("Claim invalid (mail): " + claim.getId());
                 }
                logger.warn("Claim invalid (mail): "+claim.getId());

            }else if(claim.getSource()==null || claim.getTarget()==null){
                isValid=false;
                 if(out!=null) {
                     out.println("Result invalid : " + claim.getId());
                 }
                logger.warn("Result invalid : "+claim.getId());

            }else if(claim.getSource()==null || claim.getTarget()==null){
                isValid=false;
                 if(out!=null) {
                     out.println("Result invalid : " + claim.getId());
                 }
                logger.warn("Result invalid : "+claim.getId());

            }else if(claim.getSource().getOpenaireId()!=null && claim.getTarget().getOpenaireId()!=null && claim.getSource().getOpenaireId().equals(claim.getTarget().getOpenaireId())){
                isValid=false;
                 if(out!=null) {
                     out.println("Claim invalid (source == target): " + claim.getId());
                 }
                logger.warn("Claim invalid (source == target): "+claim.getId());

            }else{
                boolean sourceIsValid=validateByType(claim.getSource(),claim.getSourceType(),claim.getId());
                boolean targetIsValid=validateByType(claim.getTarget(),claim.getTargetType(),claim.getId());
                isValid= isValid&&sourceIsValid&&targetIsValid;
                 if(!isValid){
                     if(out!=null) {
                         out.println("Claim invalid (source /target): " + claim.getId() + "\n");
                     }
                     logger.warn("Claim invalid (source /target): "+claim.getId()+"\n");
                 }
            }
            if(out!=null) {
                out.close();
            }

        return isValid;
    }
    /*
    Project:
    Mandatory Fields : id, type, Collected from

     */
    public  boolean validateResult(Result result, String claimId){
        boolean isValid=true;
            if(result==null){
                isValid=false;
                out.println("Result invalid (null): - claimId:"+claimId);
//            }else if(result.getOpenaireId()==null||result.getOpenaireId().isEmpty()){
//                isValid=false;
//                out.println("Result invalid (Id): - claimId:"+claimId);
            }else if(result.getResultType()==null||result.getResultType().isEmpty()){
                isValid=false;
                out.println("Result invalid (Type): "+result.getOpenaireId()+"- claimId:"+claimId);
            }/*
            //http://services.openaire.eu:8380/search/search?action=search&sTransformer=results_openaire&query=%28%28%28deletedbyinference+%3D+false%29+AND+%28oaftype+exact+result%29%29+and+%28%28resulttypeid+exact+publication%29+or+%28resulttypeid+exact+dataset%29%29%29+and+%28%28objIdentifier+
            //exact+od______1389%3A%3A6ba133c8460d5a67dfb18f34cc5303fb%29+or+%28resultdupid+exact+od______1389%3A%3A6ba133c8460d5a67dfb18f34cc5303fb%29%29&size=10&locale=en_GB
            //There are resuts with no title
            //so I am
            else if(result.getTitle()==null||result.getTitle().isEmpty()){
                isValid=false;
                out.println("Result invalid (title): "+result.getOpenaireId()+"- claimId:"+claimId);
            }*/else if(result.getCollectedFrom()==null||result.getCollectedFrom().isEmpty()){
                isValid=false;
                out.println("Result invalid (collectedFrom) : "+result.getOpenaireId()+"- claimId:"+claimId);
            }else if (result.getCollectedFrom().equals(ClaimUtils.COLLECTED_FROM_OPENAIRE) && result.getOpenaireId()==null) {
                isValid = false;
                out.println("Result invalid (Openaire - no id): - claimId:" + claimId);
            }else if ((result.getCollectedFrom().equals(ClaimUtils.COLLECTED_FROM_DATACITE)|| result.getCollectedFrom().equals(ClaimUtils.COLLECTED_FROM_CROSSREF) ) && result.getDoi()==null) {
                isValid = false;
                out.println("Result invalid (Crossref/Datacite - no doi): - claimId:" + claimId);
            }else if (result.getCollectedFrom().equals(ClaimUtils.COLLECTED_FROM_ORCID) && result.getOrcidworkid()==null) {
                isValid = false;
                out.println("Result invalid (Orcid - no work id): - claimId:" + claimId);
            }

        return isValid;
    }
    /*
    Project:
    Mandatory Fields : id, name

     */
    public  boolean validateProject(Project project, String claimId){
        boolean isValid=true;
             if(project==null){
                isValid=false;
                out.println("Project invalid (null): - claimId:"+claimId);
            }else if(project.getOpenaireId()==null||project.getOpenaireId().isEmpty()){
                isValid=false;
                out.println("Project invalid (id): - claimId:"+claimId);
            }else if((project.getName()==null||project.getName().isEmpty())&&(project.getAcronym()==null||project.getAcronym().isEmpty())){
                isValid=false;
                out.println("Project invalid (name/acronym): "+project.getOpenaireId()+"- claimId:"+claimId);
            }else if(project.getFunderId()==null||project.getFunderId().isEmpty()){
                isValid=false;
                out.println("Project invalid (funder id): "+project.getOpenaireId()+"- claimId:"+claimId);
            }
            else if(project.getFunderName()==null||project.getFunderName().isEmpty()){
                isValid=false;
                out.println("Project invalid (funder name): "+project.getOpenaireId()+"- claimId:"+claimId);
            }

        return isValid;
    }
    /*
    Context:
    Mandatory Fields : id, title

     */
    public  boolean validateContext(Context context, String claimId){
        boolean isValid=true;
            if(context==null){
                isValid=false;
                out.println("Context invalid (null): - claimId:"+claimId);
            }else if(context.getOpenaireId()==null||context.getOpenaireId().isEmpty()){
                isValid=false;
                out.println("Context invalid (id): - claimId:"+claimId);
            }/*
            //This is commented since There isn't a way to fill this field right now.
            else if(context.getTitle()==null||context.getTitle().isEmpty()){
                isValid=false;
                out.println("Context invalid : "+context.getOpenaireId()+"- claimId:"+claimId);
            }*/
        return isValid;
    }
    private boolean validateByType(OpenaireEntity entity,String type , String claimId ){
        //TODO add more types (e.g. patends) when they are available
        if(type.equals(ClaimUtils.PUBLICATION)||type.equals(ClaimUtils.DATASET)){
            return validateResult((Result)entity,claimId);
        } else if(type.equals(ClaimUtils.CONTEXT)){
            return validateContext((Context)entity,claimId);
        }else if(type.equals(ClaimUtils.PROJECT)){
            return validateProject((Project)entity,claimId);
        }else{
            if(entity.getOpenaireId()!=null){
                out.println("Entity invalid type ("+type+"):"+entity.getOpenaireId()+" - claimId:"+claimId);
            }else {
                out.println("Entity invalid type (" + type + "): - claimId:" + claimId);
            }
        }
        return false;
    }

    public static boolean validateCollectedFrom(String collectedFrom) throws ClaimValidationException {
        //TODO add more collected from when they are available
        if (collectedFrom==null || collectedFrom.isEmpty()) {
            logger.error("CollectedFrom field of source and/or target is null or empty");
            throw new ClaimValidationException("CollectedFrom field of source and/or target cannot be empty.");

        } else if (!collectedFrom.equals(ClaimUtils.OPENAIRE) &&
                !collectedFrom.equals(ClaimUtils.DATACITE) &&
                !collectedFrom.equals(ClaimUtils.CROSSREF) &&
                !collectedFrom.equals(ClaimUtils.ORCID)) {
            logger.error("CollectedFrom field of source and/or target is invalid. Value is:"+collectedFrom);
            throw new ClaimValidationException("CollectedFrom field of source and/or target is invalid. The allowed " +
                    "types are: " + ClaimUtils.OPENAIRE + ", " + ClaimUtils.DATACITE
                    + ", " + ClaimUtils.CROSSREF + ", " + ClaimUtils.ORCID +".");


        }

        return true;
    }

    public static boolean validateType(String type)  throws ClaimValidationException {
        if (type == null || type.isEmpty()) {
            throw new ClaimValidationException("The type of source and/or target cannot be empty.");

        } else if (!type.equals(ClaimUtils.PUBLICATION) && !type.equals(ClaimUtils.DATASET) &&
                !type.equals(ClaimUtils.CONTEXT) && !type.equals(ClaimUtils.PROJECT)) {
            throw new ClaimValidationException("The given type is invalid. The allowed types are: " +
                    ClaimUtils.PUBLICATION + ", " + ClaimUtils.DATASET + ", " + ClaimUtils.CONTEXT + ", " +
                    ClaimUtils.PROJECT);
        }

        return true;
    }

//    /*
//   Checks if the doi is valid. If it is not  then replaces the existing  DOI with the valid one.
//    */
//    public static void checkForDOI(Result r) throws Exception {
//        if(r.getDOI()==null){
//            return ;
//        }
//         String validDOI=isValidDoi(r.getDOI());
//        if(!validDOI.equals(r.getDOI())){
//            if(r.getMetadataRecord()!=null) {
//                r.setMetadataRecord(r.getMetadataRecord().replace(r.getDOI(), validDOI));
//            }
//            if(r.getExternalUrl()!=null){
//                r.setExternalUrl(r.getExternalUrl().replace(r.getDOI(), validDOI));
//            }
//            r.setDoi(validDOI);
//        }
//    }
//    public static String isValidDoi(String doi) throws Exception {
//        if(doi==null){
//            return null;
//        }
//        try{
//            PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("invalid_dois.txt", true)));
//            boolean valid=SearchUtils.isDoiValid(doi);
//            if(!valid&&(doi.length() - (doi.replace("_", "")).length() > 1)){
//                String transformDoi = doi.replace("_", "-");
//                valid=SearchUtils.isDoiValid(transformDoi);
//                if(valid){
//                    Date date= new java.util.Date();
//                    out.println(new Timestamp(date.getTime())+" - Invalid doi: "+doi+" replaced with : "+transformDoi);
//                    doi=transformDoi;
//                }
//            }else if(!valid&&(doi.length() - (doi.replace("_", "")).length() == 1)) {
//                String transformDoi = doi.replace("_", "-");
//                valid=SearchUtils.isDoiValid(transformDoi);
//                if(valid){
//                    Date date= new java.util.Date();
//                    out.println(new Timestamp(date.getTime())+" - Invalid doi: "+doi+" replaced with : "+transformDoi);
//                    doi = transformDoi;
//                }
//            }else if(!valid) {
//                String transformDoi =doi.replaceAll("\\p{C}", "");
//                valid=SearchUtils.isDoiValid(transformDoi);
//                if(valid){
//                    Date date= new java.util.Date();
//                    out.println(new Timestamp(date.getTime())+" - Invalid doi: "+doi+" replaced with (zero-width-char): "+transformDoi);
//                    doi = transformDoi;
//                }
//            }
//            out.close();
//        }catch (IOException e) {
//            e.printStackTrace();
//            System.err.println("Couldn't write to file " + "invalid_dois.txt");
//        }
//        return doi;
//    }


    public String getPathToSaveReport() {
        return pathToSaveReport;
    }

    public void setPathToSaveReport(String pathToSaveReport) {
        this.pathToSaveReport = pathToSaveReport;
    }
}
