package performa.form;

import java.io.*;
import java.util.*;
import javax.servlet.http.*;
import oneit.logging.*;
import oneit.objstore.*;
import oneit.objstore.parser.BusinessObjectParser;
import oneit.objstore.rdbms.filters.EqualsFilter;
import oneit.servlets.forms.*;
import oneit.servlets.jsp.TableTag;
import oneit.servlets.portability.FileDownloader;
import oneit.servlets.process.*;
import oneit.utils.*;
import oneit.utils.filter.Filter;
import oneit.utils.table.*;
import performa.orm.*;
import performa.utils.AnalysisEngine;

/**
 *
 * @author Pradip J. Sabhadiya
 */
public class TestAnalysisFP extends ORMProcessFormProcessor
{
    private static final    List<String>    SUPPORTED_TYPES     =   new ArrayList<>(Arrays.asList("text/csv", "text/plain"));
    private static final    int             COLS_PER_CANDIDATE  =   3;
    
    @Override
    public SuccessfulResult processForm(ORMProcessState process, SubmissionDetails submission, Map params) throws BusinessException, StorageException
    {
        TestInput               testInput   = (TestInput) process.getAttribute("TestAnalysis");
        ByteArrayOutputStream   bos         = new ByteArrayOutputStream ();
        byte[]                  bytes;
        
        LogMgr.log(TestInput.LOG, LogLevel.PROCESSING1, "Inside TestAnalysisFP");
            
        loadData(testInput, process.getTransaction());

        AnalysisEngine.analyseAnswers(testInput);
        
        try
        {
            ExcelExporter.ExportAppender    excelRenderer   =   getExportAppender(getSingleValueTableModel(testInput));
            excelRenderer.export(bos);
            bytes = bos.toByteArray();
        }
        catch(IOException ioe)
        {
            LogMgr.log(TestInput.LOG, LogLevel.PROCESSING1, ioe, "Exception occurred while Creating Excel File.");
            
            throw new BusinessException(ioe.getMessage());
        }

        LogMgr.log(TestInput.LOG, LogLevel.PROCESSING1, "TestAnalysisFP completed");
        
        return (HttpServletRequest request, HttpServletResponse response) ->
        {
            FileDownloader.writeData(request, response, bytes, TableTag.EXCEL_MIME_TYPE, "Result.xls", false);
        };
    }
    
    private ExcelExporter.ExportAppender getExportAppender(SingleValueTableModel model) throws IOException
    {
        Properties props = new Properties();

        props.put("subheader.font-style", "bold");
        props.put("header.horizontal-alignment", "center");
        props.put("header.font-style", "bold");
        
        ExcelExporter.ExportAppender    exportAppender  =   new ExcelExporter(props).getAppender();
        
        exportAppender.appendTable("Analysis Sheet", 0, model);
        
        return exportAppender;
    }
    
    private SingleValueTableModel getSingleValueTableModel(TestInput testInput)
    {
        SingleValueTableModel model = new SingleValueTableModel();
        
        int rowNumber   =   0;
        int colNumber   =   1;
        
        for (Candidate candidate : testInput.getCandidatesSet())
        {
            model.addCell(rowNumber, colNumber, new SingleValueTableModel.CellModel(1, COLS_PER_CANDIDATE, candidate.getFirstName(), "header"));
            colNumber   +=  COLS_PER_CANDIDATE;
        }
        
        for(Factor factor : testInput.getRelatedFactors())
        {
            Filter<FactorScore> scoreFilter =   FactorScore.SearchByAll().andFactor(new EqualsFilter(factor));
            
            colNumber   =   0;
            rowNumber++;
            
            model.addCell(rowNumber, colNumber++, new SingleValueTableModel.CellModel(factor.getDescription(), "subheader"));
            
            for (Candidate candidate : testInput.getCandidatesSet())
            {
                List<FactorScore>   factorScores    =   (List<FactorScore>)candidate.pipelineCandidate().toTestAnalysises().toFactorScores(scoreFilter).vals();
                        
                if(factorScores != null && !factorScores.isEmpty())
                {
                    FactorScore factorScore =   factorScores.get(0);
                    
                    //model.addCell(rowNumber, colNumber++, new SingleValueTableModel.CellModel(factorScore.getScore(), "EscapeHTML", ""));
                    model.addCell(rowNumber, colNumber++, new SingleValueTableModel.CellModel(factorScore.getColorRank(), "EscapeHTML", ""));
                    model.addCell(rowNumber, colNumber++, new SingleValueTableModel.CellModel(factorScore.getColorCode(), "EscapeHTML", ""));
                    model.addCell(rowNumber, colNumber++, new SingleValueTableModel.CellModel(factorScore.getNarrative(), "EscapeHTML", ""));
                }
                else
                {
                    colNumber   +=  COLS_PER_CANDIDATE;
                }
            }
        }
        return model;
    }
    
    public void loadData(TestInput testInput, ObjectTransaction objTran) throws BusinessException
    {
        BufferedReader          bReader         = null;
        String                  line            = "";
        String                  csvSeparator    = ",";
        boolean                 first           = true;
        
        try
        {
            bReader = new BufferedReader(new InputStreamReader(testInput.getCSV().getInputStream()));
            
            while ((line = bReader.readLine()) != null)
            {
                String[]    values  =   line.trim().split(csvSeparator);

                if(values != null && values.length > 0)
                {
                    if(first)
                    {
                        for (int i = 1; i < values.length ; i++)
                        {
                            Candidate   candidate   = Candidate.createCandidate(objTran);

                            candidate.setFirstName(values[i]);
                            testInput.addToCandidates(candidate);
                        }
                        first   =   false;
                    }
                    else
                    {
                        Question    question    =   Question.getQuestionByID(objTran, Long.valueOf(values[0]));

                        if(question == null)
                        {
                            throw new BusinessException("Question doesnot exist with ID:" + values[0]);
                        }
                        
                        for (int i = 1; i < values.length ; i++)
                        {
                            Answer  answer  =   Answer.createAnswer(objTran);

                            answer.setAnswerNo(Integer.parseInt(values[i]));
                            answer.setQuestion(question);
                            testInput.getCandidatesAt(i -1).addToAnswers(answer);
                        }
                    }
                }
            }
        }
        catch (IOException | NumberFormatException | StorageException ex)
        {
            LogMgr.log(TestInput.LOG, LogLevel.PROCESSING2, ex, "TestAnalysisFP error occured in loadData");
            throw new BusinessException("Error occurred when processing CSV file: " + ex.getMessage());
        }
        finally
        {
            try
            {
                if (bReader != null)
                {
                    bReader.close();
                }
            }
            catch (IOException ex)
            {
                LogMgr.log(TestInput.LOG, LogLevel.PROCESSING2, "TestAnalysisFP loadData finally: IOException :" + ex);
                throw new BusinessException("Error occurred when processing CSV file");
            }
        }
    }

    @Override
    public void validate(ORMProcessState process, SubmissionDetails submission, MultiException exceptions, Map params) throws StorageException
    {
        super.validate(process, submission, exceptions, params);
        
        TestInput   testInput   = (TestInput) process.getAttribute("TestAnalysis");

        Debug.assertion(testInput != null, "Test Input is null while Processing CSV File.");
        
        if(testInput.getCSV() != null)
        {
            BusinessObjectParser.assertFieldCondition(SUPPORTED_TYPES.contains(testInput.getCSV().getContentType()), testInput, TestInput.FIELD_CSV, "invalid", exceptions, true, submission.getRequest());
        }
    }
}
