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.servlets.forms.*;
import oneit.servlets.jsp.TableTag;
import oneit.servlets.portability.FileDownloader;
import oneit.servlets.process.*;
import oneit.utils.*;
import oneit.utils.parsers.FieldException;
import oneit.utils.table.*;
import performa.orm.Answer;
import performa.orm.Candidate;
import performa.orm.Question;
import performa.orm.TestInput;
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"));
    
    @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;
        
        try
        {
            SingleValueTableModel model = loadData(testInput, process.getTransaction());
            
            ExcelExporter.ExportAppender    excelRenderer   = getExportAppender(model);
            excelRenderer.export(bos);
            bytes = bos.toByteArray();
        }
        catch(IOException ioe)
        {
            LogMgr.log(LoggingArea.ALL, LogLevel.PROCESSING1, ioe, "Exception occurred while Creating Excel File.");
            
            throw new BusinessException(ioe.getMessage());
        }

        return (HttpServletRequest request, HttpServletResponse response) ->
        {
            FileDownloader.writeData(request, response, bytes, TableTag.EXCEL_MIME_TYPE, "Result.xls", false);
        };
    }
    
    private static ExcelExporter.ExportAppender getExportAppender(SingleValueTableModel model) throws IOException
    {
        Properties props = new Properties();
        props.load(TestAnalysisFP.class.getClassLoader().getResourceAsStream("excel-styles.properties"));

        props.put("subheader.font-style", "bold");
        props.put("header.horizontal-alignment", "center");
        props.put("header.font-style", "bold");
        props.put("header.cell-background", "black");
        
        ExcelExporter.ExportAppender    exportAppender      = new ExcelExporter(props).getAppender();
        
        exportAppender.appendTable("New Sheet", 0, model);
        
        return exportAppender;
    }
    
    private static SingleValueTableModel getExcelContent(BinaryContent file)
    {
        SingleValueTableModel model = new SingleValueTableModel(); // TO-DO Converting To Excel
        model.addCell(0, 0, new SingleValueTableModel.CellModel(file.getName(), ""));
        
        return model;
    }
    
    
    public SingleValueTableModel loadData(TestInput testInput, ObjectTransaction objTran)
    {
        SingleValueTableModel   model           = null;
        BufferedReader          bReader         = null;
        String                  line            = "";
        String                  csvSeparator    = ",";
        boolean                 first           = true;
        List<Candidate>         candidates      = new ArrayList<>();
        List<Answer>            answers         = new ArrayList<>();
        
        try
        {
            bReader = new BufferedReader(new InputStreamReader(testInput.getCSV().getInputStream()));
            
            while ((line = bReader.readLine()) != null)
            {
                String[] values = line.trim().split(csvSeparator);

                if(first)
                {
                    for (int i = 1; i < values.length ; i++)
                    {
                        Candidate   candidate   = Candidate.createCandidate(objTran);
                        
                        candidate.setFirstName(values[i]);
                        candidate.setTestInput(testInput);
                        candidates.add(candidate);
                    }
                    
                    first   = false;
                }
                else
                {                    
                    Question  question   =  Question.getQuestionByID(objTran, Long.valueOf(values[0]));
                    
                    for (int i = 1; i < values.length ; i++)
                    {
                        Answer  answer  = Answer.createAnswer(objTran);
                        
                        answer.setAnswerNo(Integer.parseInt(values[i]));
                        answer.setCandidate(candidates.get(i -1));
                        answer.setQuestion(question);
                        
                        answers.add(answer);
                    }
                }
            }

            model = AnalysisEngine.analyseAnswers(answers.toArray(new Answer[0]), testInput.getLevel());
            
        }
        catch (FileNotFoundException ex)
        {
            LogMgr.log(LoggingArea.ALL, LogLevel.PROCESSING2, "UploadCSVFP loadData : FileNotFoundException :" + ex);
            throw new NestedException(ex);
        }
        catch (IOException ex)
        {
            LogMgr.log(LoggingArea.ALL, LogLevel.PROCESSING2, "UploadCSVFP loadData : IOException :" + ex);
            throw new NestedException(ex);
        } 
        catch (FieldException ex) 
        {
            LogMgr.log(LoggingArea.ALL, LogLevel.PROCESSING2, "UploadCSVFP loadData : FieldException :" + ex);
            throw new NestedException(ex);
        }
        finally
        {
            try
            {
                if (bReader != null)
                {
                    bReader.close();
                }
            }
            catch (IOException ex)
            {
                LogMgr.log(LoggingArea.ALL, LogLevel.PROCESSING2, "UploadCSVFP loadData : IOException :" + ex);
                throw new NestedException(ex);
            }
        }
        
        return model;
    }
    

    @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());
        }
    }
}
