package performa.orm;

import java.util.*;
import oneit.logging.LoggingArea;
import oneit.objstore.StorageException;
import oneit.objstore.rdbms.filters.EqualsFilter;
import oneit.objstore.rdbms.filters.IsNotNullFilter;
import oneit.utils.filter.CollectionFilter;
import oneit.utils.filter.Filter;
import oneit.utils.parsers.FieldException;
import performa.orm.types.AppProcessOption;
import performa.orm.types.ApplicationStatus;
import performa.orm.types.CriteriaType;


public class JobApplication extends BaseJobApplication
{
    private static final long   serialVersionUID    = 0L;
    public  static LoggingArea  LOG                 = LoggingArea.createLoggingArea("JobApplication");
    
    // This constructor should not be called
    public JobApplication ()
    {
        // Do not add any code to this, always put it in initialiseNewObject
    }

    
    public static JobApplication createNewApplication(Candidate candidate, Job job) throws StorageException, FieldException
    {
        JobApplication  jobApplication  =   createJobApplication(job.getTransaction());
        
        jobApplication.setCandidate(candidate);
        jobApplication.setJob(job);
        
        return jobApplication;
    }
    
    
    private void initACAnswers()
    {
        if(isIncludeAssessmentCriteria())
        {
            for(AssessmentCriteria assessmentCriteria : getJob().getAssessmentCriteriasSet())
            {
                AssessmentCriteriaAnswer    answer  =   AssessmentCriteriaAnswer.createAssessmentCriteriaAnswer(getTransaction());

                addToAssessmentCriteriaAnswers(answer);
                assessmentCriteria.addToAnswers(answer);
            }
        }
    }
    
    
    public boolean createAssessmentCriteriaObjects() throws FieldException
    {
        boolean safeRedirect = false;

        if(isIncludeAssessmentCriteria())
        {
            for(AssessmentCriteria assessmentCriteria : getJob().getAssessmentCriteriasSet())
            {
                boolean available   = false;
                
                for(AssessmentCriteriaAnswer answer : getAssessmentCriteriaAnswersSet())
                {
                    if(assessmentCriteria.equals(answer.getAssessmentCriteria()))
                    {
                        available = true;
                        break;
                    }
                }
                
                if(!available)
                {
                    AssessmentCriteriaAnswer    answer  =   AssessmentCriteriaAnswer.createAssessmentCriteriaAnswer(getTransaction());

                    addToAssessmentCriteriaAnswers(answer);
                    assessmentCriteria.addToAnswers(answer);
                    safeRedirect = true;
                }
            }
        }
        
        return safeRedirect;    
    }
    
    
    public boolean createCultureCriteriaObjects() throws FieldException
    {
        boolean safeRedirect = false;
        
        for(CultureCriteria cultureCriteria : getJob().getCultureCriteriasSet())
        {
            boolean available   = false;

            for(CultureCriteriaAnswer answer : getCultureCriteriaAnswersSet())
            {
                if(cultureCriteria.equals(answer.getCultureCriteria()))
                {
                    available = true;
                    break;
                }
            }

            if(!available)
            {
                CultureCriteriaAnswer   answer  =   CultureCriteriaAnswer.createCultureCriteriaAnswer(getTransaction());

                addToCultureCriteriaAnswers(answer);
                cultureCriteria.addToAnswers(answer);
                safeRedirect = true;
            }
        }
        
        return safeRedirect;    
    }

    
    public boolean initAssessmentAnswers(List<Question> questions) throws StorageException, FieldException
    {
        boolean         redirect        =   false;
        List<Question>  allQuestions    =   new ArrayList<>();
        
        for(Question question : questions)
        {
            allQuestions.add(question);
            
            if(question.getRightQuestion() != null)
            {
                allQuestions.add(question.getRightQuestion());
            }
        }
        
        for(Question question : allQuestions)            
        {
            boolean available   = false;

            for(Answer answer : getProfileAssessmentAnswersSet())
            {
                if(question.equals(answer.getQuestion()))
                {
                    available = true;
                    break;
                }
            }

            if(!available)
            {
                Answer  answer  =   Answer.createAnswer(getTransaction());
            
                addToProfileAssessmentAnswers(answer);
                answer.setQuestion(question);                
                redirect    =   true;
            }
        } 
        
        return redirect;
    }
  
    public Answer getAnswerForQuestion(Question question) throws FieldException
    {
        Filter  filter  =   Answer.SearchByAll().andQuestion(new EqualsFilter<>(question));
        
        return CollectionFilter.getFirstMatch(getProfileAssessmentAnswersSet(), filter);
    }
    
    
    public Collection<AssessmentCriteriaAnswer> getACAnswersByType(CriteriaType criteriaType)
    {
        Filter  filter  =   AssessmentCriteriaAnswer.SearchByCriteriaType().byCriteriaType(criteriaType);

        return  CollectionFilter.filter(getAssessmentCriteriaAnswersSet(), filter);
    }

    
    public boolean selectionCompleted()
    {
        int allAnswersCount =   getAssessmentCriteriaAnswersCount();
        
        if(allAnswersCount == getJob().getAssessmentCriteriasCount())
        {
            Filter      filter          =   AssessmentCriteriaAnswer.SearchByAll().andAnswer(new IsNotNullFilter<>());
            Collection  selectedAnswers =   pipelineJobApplication().toAssessmentCriteriaAnswers(filter).vals();

            return (selectedAnswers.size() == allAnswersCount);
        }
        
        return false;
    }
       
    
    public boolean cultureCompleted()
    {
        int allAnswersCount =   getCultureCriteriaAnswersCount();
        
        if(allAnswersCount == getJob().getCultureCriteriasCount())
        {
            Filter      filter          =   CultureCriteriaAnswer.SearchByAll().andSelectedQuestion(new IsNotNullFilter<>());
            Collection  selectedAnswers =   pipelineJobApplication().toCultureCriteriaAnswers(filter).vals();

            return (selectedAnswers.size() == allAnswersCount);
        }
        
        return false;
    }
    
    
    public boolean assessmentCompleted()
    {
        int allAnswersCount =   getJob().getAllProfileAssessmentQuestions().size();
        
        if(allAnswersCount > 0)
        {
            Filter      filter          =   Answer.SearchByAll().andAnswerNo(new IsNotNullFilter<>());
            Collection  selectedAnswers =   pipelineJobApplication().toProfileAssessmentAnswers(filter).vals();

            return (selectedAnswers.size() == allAnswersCount);
        }
        return false;
    }
    
    
    public boolean isIncludeAssessmentCriteria()
    {
        return getJob() != null && isTrue(getJob().getIncludeAssessmentCriteria());
    }
    
//    TODO: Fix these hard coded values
    @Override
    public Integer getOverallSuitability()
    {
        return 1;
    }
    
    
    public int getJobMatchPercentage()
    {
        return 85;
    }
    
    
    public int getCulturePercentage()
    {
        return 90;
    }
    
    
    public int getCriteriaPercentage ()
    {
        return 95;
    }
    
    
    public List<AppProcessOption> getValidProcessOptions()
    {
        List<AppProcessOption>  options = new ArrayList<>();
        
        if(getApplicationStatus() == ApplicationStatus.SUBMITTED)
        {
            options.add(AppProcessOption.TO_SHORTLIST);
        }
        else if(getApplicationStatus() == ApplicationStatus.SHORTLISTED)
        {
            options.add(AppProcessOption.REMOVE_FROM_SHORTLIST);
        }
        
        return options;
    }
    
    
    public String getApplicantStatusStr()
    {
        return getApplicationStatus().getDescription();
    }
    
    
    public List<ApplicationStatus> getAvailableStatuses()
    {
        List<ApplicationStatus>  statuses = new ArrayList<>();
        
        statuses.add(ApplicationStatus.SUBMITTED);
        statuses.add(ApplicationStatus.SHORTLISTED);
        statuses.add(ApplicationStatus.UNSUITABLE);
        
        return statuses;
    }
}