package performa.orm;

import com.google.maps.model.Distance;
import java.util.Calendar;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import oneit.logging.LoggingArea;
import oneit.objstore.MessageSource;
import oneit.objstore.ObjectTransaction;
import oneit.objstore.rdbms.filters.EqualsFilter;
import oneit.objstore.rdbms.filters.IsNotNullFilter;
import oneit.objstore.utils.ObjstoreUtils;
import oneit.security.SecUser;
import oneit.servlets.objstore.MessageSourceDecorator;
import oneit.servlets.process.ORMProcessState;
import oneit.utils.BusinessException;
import oneit.utils.CollectionUtils;
import oneit.utils.DateDiff;
import oneit.utils.ObjectTransform;
import oneit.utils.RandomStringGen;
import oneit.utils.StringUtils;
import oneit.utils.filter.*;
import performa.utils.DistanceUtils;
import performa.utils.ExpressAnswerFilter;


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

    @Override
    protected void postInitNewObj() throws BusinessException 
    {
        RandomStringGen random  =   new RandomStringGen();

        setVerificationKey(random.generateAlphaNum(6));
        
        super.postInitNewObj();
    }
    
    
    public String getFirstName()
    {
        return getUser() != null ? getUser().getFirstName() : null;
    }

    
    @Override
    public String getToString() 
    {
        return getUser() != null ? getUser().getName() : null;
    }   

    
    public static String checkCandidate(HttpServletRequest request, ORMProcessState process)
    {
        ObjectTransaction   transaction         =   process.getTransaction();
        String              candidateID         =   (String) request.getParameter("id");
        String              verificationCode    =   (String) request.getParameter("pin");
        MessageSource       messageSource       =   MessageSourceDecorator.getMessageSource(request);
        Candidate           candidate           =   null;
        String              errorMsg            =   "";
        
        if(StringUtils.subBlanks(candidateID) != null && StringUtils.subBlanks(verificationCode) != null)
        {
            candidate = Candidate.getCandidateByID(transaction, Long.parseLong(candidateID));
            
            process.setAttribute("Candidate", candidate);
        }
        else if(process.getAttribute("Candidate") != null)
        {
            candidate = (Candidate) process.getAttribute("Candidate");
        }
        else
        {
            errorMsg = messageSource.getFieldErrorMsg(Candidate.REFERENCE_Candidate, "", "UnauthorizedUser", null);
        }

        if(candidate == null)
        {
            errorMsg = messageSource.getFieldErrorMsg(Candidate.REFERENCE_Candidate, "", "UnauthorizedUser", null);
        }
        else if(!CollectionUtils.equals(verificationCode, candidate.getVerificationKey()))
        {
            errorMsg = messageSource.getFieldErrorMsg(Candidate.REFERENCE_Candidate, "", "WrongVerificationCode", null);
        }
        else if(DateDiff.getDateDiff(Calendar.HOUR, candidate.getVerificationMailSendDate(), new Date()) > 24)
        {
            errorMsg = messageSource.getFieldErrorMsg(Candidate.REFERENCE_Candidate, "", "LinkExpired", null);
        }
        
        return errorMsg;
    }
    
    
    public TestAnalysis getTestAnalysisFor(Level level)
    {
        Filter<TestAnalysis>    testAnalysisFilter  =   TestAnalysis.SearchByAll().andLevel(new EqualsFilter(level));
           
        return pipelineCandidate().toTestAnalysises(testAnalysisFilter).val();
    }
    

    public boolean cultureCompleted(Job job)
    {
        if(!job.showCultureCriteriaSection())
        {
            return false;
        }
        
        Set<CultureCriteriaAnswer>  selectedAnswers     =   pipelineCandidate().toCultureCriteriaAnswers(CultureCriteriaAnswer.SearchByAll().andSelectedQuestion(new IsNotNullFilter<>())).uniqueVals();
        Set<CultureElement>         answeredElements    =   CultureCriteriaAnswer.pipesCultureCriteriaAnswer(selectedAnswers).toCultureElement().uniqueVals();
        Set<CultureElement>         applicableElements  =   CultureCriteria.pipesCultureCriteria(job.getApplicableCultureSet()).toCultureElement().uniqueVals();
        
        return answeredElements.containsAll(applicableElements);
    }
    
    public double cultureCompletedPercentage(Job job)
    {
        return job.showCultureCriteriaSection() ? (getApplicableCultureAnswerCount(job) * 100) / job.getApplicableCultureCount(): 0d;
    }

    public int getApplicableCultureAnswerCount(Job job) 
    {
        int applicableAnswerCount   =   0;
        
        for(CultureCriteria cultureCriteria : job.getApplicableCultureSet())
        {
            for(CultureCriteriaAnswer answer : getCultureCriteriaAnswersSet())
            {
                if(CollectionUtils.equals(answer.getCultureElement(), cultureCriteria.getCultureElement()))
                {
                    applicableAnswerCount+= 1;
                    break;
                }
            }
        }
        
        return applicableAnswerCount;
    }
    
    public double roleFitCompletedPercentage(Job job)
    {
        return (getCompletedAnswers(job).size() * 100) / job.getAllQuestions().size() ;
    }
    
    public Collection<Answer> getCompletedAnswers(Job job)
    {
        return CollectionFilter.filter(getProfileAssessmentAnswersSet(), new ExpressAnswerFilter(job.isExpressJob()));
    }
    
    public boolean assessmentCompleted(Job job) //role
    {
        int allAnswersCount =   job.getAllQuestions().size();
        
        if(allAnswersCount > 0)
        {
            Collection  selectedAnswers =   getCompletedAnswers(job);
            
            return (selectedAnswers.size() >= allAnswersCount);
        }
        return false;
    }
    
    
    public List<CultureCriteriaAnswer> getSortedCultureCriteriaAnswers()
    {
        return  ObjstoreUtils.sort(getCultureCriteriaAnswersSet(), 
                                new ObjectTransform[] {CultureCriteriaAnswer.pipesCultureCriteriaAnswer().toObjectID()},  
                                new Comparator[]{CollectionUtils.DEFAULT_COMPARATOR});
    }
    
    
    public static Candidate getCandidateForForgotPassword(ObjectTransaction transaction, String userIDStr, String code)
    {
        userIDStr   =   StringUtils.subBlanks(userIDStr);
        code        =   StringUtils.subBlanks(code);
        
        if(userIDStr != null && code!=null)
        {
            Candidate   candidate   =   Candidate.getCandidateByID(transaction, Long.parseLong(userIDStr));
                        
            if(candidate != null && CollectionUtils.equals(candidate.getForgotPasswordKey(), code))
            {
                return candidate;
            }
        }
        
        return null;
    }
    
    public boolean showPrivacyPolicyAgreed()
    {
        return isTrue(getPrivacyPolicyAgreed());
    }
    
    public boolean showConditionsAgreed()
    {
        return isTrue(getConditionsAgreed());
    }
    
    public boolean isFarFromJob()
    {
        Distance calculateDistance = DistanceUtils.calculateDistance(FIELD_Phone, FIELD_Phone);
        return false;
    }
    
    public boolean isUnverifiedEmailIngestUser()
    {
        return !isTrue(getIsAccountVerified()) && isTrue(getIsEmailIngest());
    }
    
    public Boolean isEmailFound()
    {
        if(getUser() != null && getUser().getEmail() != null)
        {
            SecUser user    = SecUser.searchNAME(getTransaction(), getUser().getEmail().toLowerCase());

            if(user != null && user.getExtension(Candidate.REFERENCE_Candidate) != null && user.getExtension(Candidate.REFERENCE_Candidate).getIsAccountVerified())
            {
                return Boolean.TRUE;
            }
        }
        
        return Boolean.FALSE;
    }
}