001/*
002 * Kuali Coeus, a comprehensive research administration system for higher education.
003 * 
004 * Copyright 2005-2015 Kuali, Inc.
005 * 
006 * This program is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU Affero General Public License as
008 * published by the Free Software Foundation, either version 3 of the
009 * License, or (at your option) any later version.
010 * 
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU Affero General Public License for more details.
015 * 
016 * You should have received a copy of the GNU Affero General Public License
017 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
018 */
019package org.kuali.coeus.s2sgen.impl.print;
020
021import gov.grants.apply.system.metaGrantApplication.GrantApplicationDocument;
022import gov.grants.apply.system.metaGrantApplication.GrantApplicationDocument.GrantApplication.Forms;
023import org.apache.commons.lang3.StringUtils;
024import org.apache.xmlbeans.XmlCursor;
025import org.apache.xmlbeans.XmlException;
026import org.apache.xmlbeans.XmlObject;
027import org.apache.xpath.XPathAPI;
028import org.kuali.coeus.propdev.api.core.DevelopmentProposalContract;
029import org.kuali.coeus.propdev.api.person.attachment.ProposalPersonBiographyContract;
030import org.kuali.coeus.propdev.api.s2s.*;
031import org.kuali.coeus.s2sgen.api.core.AuditError;
032import org.kuali.coeus.s2sgen.api.core.S2SException;
033import org.kuali.coeus.s2sgen.api.generate.FormMappingInfo;
034import org.kuali.coeus.s2sgen.api.generate.FormMappingService;
035import org.kuali.coeus.s2sgen.api.print.FormPrintService;
036import org.kuali.coeus.s2sgen.api.print.FormPrintResult;
037import org.kuali.coeus.s2sgen.impl.generate.S2SFormGenerator;
038import org.kuali.coeus.s2sgen.impl.util.ClassLoaderUtils;
039import org.kuali.coeus.s2sgen.impl.util.XPathExecutor;
040import org.kuali.coeus.s2sgen.impl.datetime.S2SDateTimeService;
041import org.kuali.coeus.s2sgen.impl.generate.S2SFormGeneratorRetrievalService;
042import org.kuali.coeus.s2sgen.impl.validate.S2SValidatorService;
043import org.kuali.coeus.propdev.api.core.ProposalDevelopmentDocumentContract;
044import org.kuali.coeus.sys.api.model.KcFile;
045import org.kuali.coeus.s2sgen.api.core.ConfigurationConstants;
046import org.kuali.coeus.propdev.api.attachment.NarrativeContract;
047import org.kuali.coeus.propdev.api.attachment.NarrativeService;
048import org.kuali.coeus.s2sgen.api.generate.AttachmentData;
049import org.slf4j.Logger;
050import org.slf4j.LoggerFactory;
051import org.springframework.beans.factory.annotation.Autowired;
052import org.springframework.beans.factory.annotation.Qualifier;
053import org.springframework.core.io.DefaultResourceLoader;
054import org.springframework.core.io.Resource;
055import org.springframework.stereotype.Component;
056import org.w3c.dom.Element;
057
058import javax.xml.transform.Source;
059import javax.xml.transform.stream.StreamSource;
060import java.io.*;
061import java.util.*;
062import java.util.zip.ZipEntry;
063import java.util.zip.ZipOutputStream;
064
065/**
066 * This class is implementation of PrintService. It provides the functionality
067 * to generate PDF for all forms along with their attachments
068 */
069@Component("formPrintService")
070public class FormPrintServiceImpl implements FormPrintService {
071        private static final Logger LOG = LoggerFactory.getLogger(FormPrintServiceImpl.class);
072    private static final String PDF_FILE_EXTENSION = ".pdf";
073
074    @Autowired
075    @Qualifier("s2sApplicationService")
076        private S2sApplicationService s2sApplicationService;
077
078    @Autowired
079    @Qualifier("s2SFormGeneratorRetrievalService")
080    private S2SFormGeneratorRetrievalService s2SFormGeneratorService;
081
082    @Autowired
083    @Qualifier("s2SValidatorService")
084    private S2SValidatorService s2SValidatorService;
085
086    @Autowired
087    @Qualifier("s2SConfigurationService")
088    private S2SConfigurationService s2SConfigurationService;
089
090    @Autowired
091    @Qualifier("s2SDateTimeService")
092    private S2SDateTimeService s2SDateTimeService;
093
094    @Autowired
095    @Qualifier("narrativeService")
096    private NarrativeService narrativeService;
097
098    @Autowired
099    @Qualifier("s2SPrintingService")
100    private S2SPrintingService s2SPrintingService;
101
102    @Autowired
103    @Qualifier("formMappingService")
104    private FormMappingService formMappingService;
105
106    @Autowired
107    @Qualifier("userAttachedFormService")
108    private UserAttachedFormService userAttachedFormService;
109
110        /**
111         * 
112         * This method is used for the printing of forms in PDF format. It generates
113         * PDF forms and puts it into {@link KcFile}
114         * 
115         * @param pdDoc (ProposalDevelopmentDocumentContract)
116         * @return {@link KcFile} which contains all information
117         *         related to the generated PDF
118         * @throws
119         * @throws S2SException
120         * 
121         */
122    @Override
123        public FormPrintResult printForm(Object pdDoc) throws S2SException {
124
125        if (pdDoc == null) {
126            throw new IllegalArgumentException("pdDoc is null");
127        }
128
129        ProposalDevelopmentDocumentContract pdDocContract = (ProposalDevelopmentDocumentContract) pdDoc;
130
131        PrintableResult pResult;
132                S2sAppSubmissionContract s2sAppSubmission = getLatestS2SAppSubmission(pdDocContract);
133                if (s2sAppSubmission != null
134                                && s2sAppSubmission.getGgTrackingId() != null) {
135            pResult = getSubmittedPDFStream(pdDocContract);
136                } else {
137            pResult = getPDFStream(pdDocContract);
138                }
139            if(pdDocContract.getDevelopmentProposal().getGrantsGovSelectFlag()){
140            FormPrintResult result = new FormPrintResult();
141            result.setErrors(pResult.errors);
142            return result;
143            }
144        S2SFile attachmentDataSource = s2SPrintingService
145                .print(pResult.printables);
146                attachmentDataSource.setName(getFileNameForFormPrinting(pdDocContract));
147
148        FormPrintResult result = new FormPrintResult();
149        result.setFile(attachmentDataSource);
150        result.setErrors(pResult.errors);
151        return result;
152        }
153
154        protected void saveGrantsGovXml(ProposalDevelopmentDocumentContract pdDoc, boolean formEntryFlag,XmlObject formObject,List<AttachmentData> attachmentList,List<? extends S2sAppAttachmentsContract> attachmentLists) throws Exception{
155            String loggingDirectory = s2SConfigurationService.getValueAsString(ConfigurationConstants.PRINT_XML_DIRECTORY);
156        String opportunityId = pdDoc.getDevelopmentProposal().getS2sOpportunity().getOpportunityId();
157        String proposalnumber = pdDoc.getDevelopmentProposal().getProposalNumber();
158        String exportDate = StringUtils.replaceChars((pdDoc.getDevelopmentProposal().getUpdateTimestamp().toString()), ":", "_");
159        exportDate = StringUtils.replaceChars(exportDate, " ", ".");
160
161        File grantsGovXmlDirectoryFile = new File(loggingDirectory + opportunityId + "." + proposalnumber + "." + exportDate);
162        if (!grantsGovXmlDirectoryFile.exists() || formEntryFlag) {
163            grantsGovXmlDirectoryFile.mkdir();
164        }
165
166        for (AttachmentData attachmentData : attachmentList) {
167            File attachmentFile = new File(grantsGovXmlDirectoryFile,"Attachments");
168            attachmentFile.mkdir();
169            File attachedFile = new File(attachmentFile,attachmentData.getFileName());
170            try (FileOutputStream output = new FileOutputStream(attachedFile)) {
171                output.write(attachmentData.getContent());
172            }
173        }
174        for (S2sAppAttachmentsContract attAppAttachments : attachmentLists) {
175            File attachmentFile = new File(grantsGovXmlDirectoryFile,"Attachments");   
176            attachmentFile.mkdir();
177            KcFile ads = getAttributeContent(pdDoc,attAppAttachments.getContentId());
178            File attachedFile = new File(attachmentFile,ads.getName());
179            try (FileOutputStream output = new FileOutputStream(attachedFile)) {
180                output.write(getAttContent(pdDoc, attAppAttachments.getContentId()));
181            }
182        }
183        File xmlFile= new File(grantsGovXmlDirectoryFile,opportunityId + "." + proposalnumber + "." + exportDate+".xml");
184        try (BufferedWriter out = new BufferedWriter(new FileWriter(xmlFile))) {
185            out.write(formObject.xmlText());
186        }
187
188        try (FileOutputStream fileOutputStream = new FileOutputStream(grantsGovXmlDirectoryFile+".zip"); ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream)) {
189            addFolderToZip("", grantsGovXmlDirectoryFile.getPath(), zipOutputStream);
190            zipOutputStream.flush();
191        }
192
193        }
194        
195    protected void addFolderToZip(String path, String sourceFolder, ZipOutputStream zipOutputStream) throws Exception {
196        File proposalNumberfolder = new File(sourceFolder);
197        for (String fileName : proposalNumberfolder.list()) {
198            if (path.equals("")) {
199                addFileToZip(proposalNumberfolder.getName(), sourceFolder + "/" + fileName, zipOutputStream);
200            } else {
201                addFileToZip(path + "/" + proposalNumberfolder.getName(), sourceFolder + "/" + fileName, zipOutputStream);
202            }
203        }
204    }
205
206    protected void addFileToZip(String path, String sourceFile, ZipOutputStream zipOutputStream) throws Exception {
207        File attachmentFile = new File(sourceFile);
208        if (attachmentFile.isDirectory()) {
209            addFolderToZip(path, sourceFile, zipOutputStream);
210        } else {
211            byte[] buffer = new byte[1024];
212            int length;
213            try (FileInputStream fileInputStream = new FileInputStream(attachmentFile)) {
214                zipOutputStream.putNextEntry(new ZipEntry(path + "/" + attachmentFile.getName()));
215                while ((length = fileInputStream.read(buffer)) > 0) {
216                    zipOutputStream.write(buffer, 0, length);
217                }
218            }
219        }
220    }
221        protected String getFileNameForFormPrinting(ProposalDevelopmentDocumentContract pdDoc) {
222                StringBuilder fileName = new StringBuilder();
223                fileName.append(pdDoc.getDocumentNumber());
224                fileName.append(pdDoc.getDevelopmentProposal()
225                                .getProgramAnnouncementNumber());
226                fileName.append(PDF_FILE_EXTENSION);
227                return fileName.toString();
228        }
229
230        /**
231         * 
232         * This method is to write the submitted application data to a pdfStream
233         * 
234         * @param pdDoc
235         *            Proposal Development Document.
236         * @return ByteArrayOutputStream[] of the submitted application data.
237         * @throws S2SException
238         */
239        protected PrintableResult getSubmittedPDFStream(
240                        ProposalDevelopmentDocumentContract pdDoc) throws S2SException {
241                GrantApplicationDocument submittedDocument;
242                String frmXpath = null;        
243        String frmAttXpath = null;
244                try {
245                    S2sAppSubmissionContract s2sAppSubmission = getLatestS2SAppSubmission(pdDoc);
246                    String submittedApplicationXml = findSubmittedXml(s2sAppSubmission);
247                    String submittedApplication = s2SDateTimeService.removeTimezoneFactor(submittedApplicationXml);
248                        submittedDocument = GrantApplicationDocument.Factory.parse(submittedApplication);
249                } catch (XmlException e) {
250                        LOG.error(e.getMessage(), e);
251                        throw new S2SException(e);
252                }
253                FormMappingInfo info = null;
254                DevelopmentProposalContract developmentProposal = pdDoc.getDevelopmentProposal();
255        List<String> sortedNameSpaces = getSortedNameSpaces(developmentProposal.getProposalNumber(),developmentProposal.getS2sOppForms());
256                boolean formEntryFlag = true;
257                List<S2SPrintable> formPrintables = new ArrayList<>();
258                for (String namespace : sortedNameSpaces) {
259                        XmlObject formFragment = null;
260                        info = formMappingService.getFormInfo(namespace);
261                        if(info==null) continue;
262                        formFragment = getFormObject(submittedDocument, info);
263                        frmXpath = "//*[namespace-uri(.) = '"+namespace+"']";               
264            frmAttXpath = "//*[namespace-uri(.) = '"+namespace+"']//*[local-name(.) = 'FileLocation' and namespace-uri(.) = 'http://apply.grants.gov/system/Attachments-V1.0']";           
265
266            byte[] formXmlBytes = formFragment.xmlText().getBytes();
267            GenericPrintable formPrintable = new GenericPrintable();
268
269            ArrayList<Source> templates = new ArrayList<Source>();
270            DefaultResourceLoader resourceLoader = new DefaultResourceLoader(ClassLoaderUtils.getDefaultClassLoader());
271            Resource resource = resourceLoader.getResource(info.getStyleSheet());
272
273            Source xsltSource = null;
274            try {
275                xsltSource = new StreamSource(resource.getInputStream());
276            } catch (IOException e) {
277                throw new S2SException(e);
278            }
279            templates.add(xsltSource);
280            formPrintable.setXSLTemplates(templates);
281
282            // Linkedhashmap is used to preserve the order of entry.
283            Map<String, byte[]> formXmlDataMap = new LinkedHashMap<String, byte[]>();
284            formXmlDataMap.put(info.getFormName(), formXmlBytes);
285            formPrintable.setStreamMap(formXmlDataMap);
286            S2sApplicationContract s2sApplciation = s2sApplicationService.findS2sApplicationByProposalNumber(pdDoc.getDevelopmentProposal().getProposalNumber());
287            List<? extends S2sAppAttachmentsContract> attachmentList = s2sApplciation.getS2sAppAttachmentList();
288
289            Map<String, byte[]> formAttachments = new LinkedHashMap<String, byte[]>();
290                                
291            try{
292              XPathExecutor executer = new XPathExecutor(formFragment.toString());
293              org.w3c.dom.Node d = executer.getNode(frmXpath);
294              org.w3c.dom.NodeList attList = XPathAPI.selectNodeList(d, frmAttXpath);
295              int attLen = attList.getLength();
296
297              for(int i=0;i<attLen;i++){
298                  org.w3c.dom.Node attNode = attList.item(i);
299                  String contentId = ((Element)attNode).getAttributeNS("http://apply.grants.gov/system/Attachments-V1.0","href");
300
301                  if (attachmentList != null && !attachmentList.isEmpty()) {
302                    for (S2sAppAttachmentsContract attAppAttachments : attachmentList) {
303                      if(attAppAttachments.getContentId().equals(contentId)){
304                        try (ByteArrayOutputStream attStream = new ByteArrayOutputStream()) {
305                            attStream.write(getAttContent(pdDoc,
306                                    attAppAttachments.getContentId()));
307                        } catch (IOException e) {
308                            LOG.error(e.getMessage(), e);
309                            throw new S2SException(e);
310                        }
311                        StringBuilder attachment = new StringBuilder();
312                        attachment.append("   ATT : ");
313                        attachment.append(attAppAttachments.getContentId());
314                        formAttachments.put(attachment.toString(),
315                                getAttContent(pdDoc, attAppAttachments
316                                        .getContentId()));
317                     }
318                    }
319                  }
320              }
321            } catch (Exception e) {
322                LOG.error(e.getMessage(), e);
323            }
324            try {
325              if(developmentProposal.getGrantsGovSelectFlag()){
326                List<AttachmentData> attachmentLists = new ArrayList<AttachmentData>();
327                saveGrantsGovXml(pdDoc,formEntryFlag,formFragment,attachmentLists,attachmentList);
328                formEntryFlag = false;
329              }
330            } catch (Exception e) {
331                  LOG.error(e.getMessage(), e);
332            }
333            formPrintable.setAttachments(formAttachments);
334            formPrintables.add(formPrintable);
335                }
336        PrintableResult result = new PrintableResult();
337        result.printables = formPrintables;
338                return result;
339        }
340
341        protected String findSubmittedXml(S2sAppSubmissionContract appSubmission) {
342            S2sApplicationContract s2sApplication = s2sApplicationService.findS2sApplicationByProposalNumber(appSubmission.getProposalNumber());
343            return s2sApplication.getApplication();
344    }
345
346
347
348    /**
349         * This method is used to generate byte stream of forms
350         * 
351         * @param pdDoc
352         *            ProposalDevelopmentDocumentContract
353         * @return ByteArrayOutputStream[] PDF byte Array
354         * @throws S2SException
355         */
356        protected PrintableResult getPDFStream(ProposalDevelopmentDocumentContract pdDoc)
357                        throws S2SException {
358
359                List<AuditError> errors = new ArrayList<AuditError>();
360                DevelopmentProposalContract developmentProposal = pdDoc
361                                .getDevelopmentProposal();
362        String proposalNumber = developmentProposal.getProposalNumber();
363        List<String> sortedNameSpaces = getSortedNameSpaces(proposalNumber, developmentProposal.getS2sOppForms());
364
365                List<S2SPrintable> formPrintables = new ArrayList<>();
366                boolean formEntryFlag = true;
367            getNarrativeService().deleteSystemGeneratedNarratives(pdDoc.getDevelopmentProposal().getNarratives());
368            Forms forms = Forms.Factory.newInstance();
369                for (String namespace : sortedNameSpaces) {
370            FormMappingInfo info = formMappingService.getFormInfo(namespace,proposalNumber);
371                        if(info==null) continue;
372            S2SFormGenerator s2sFormGenerator = s2SFormGeneratorService.getS2SGenerator(proposalNumber,info.getNameSpace());
373            errors.addAll(s2sFormGenerator.getAuditErrors());
374                        XmlObject formObject = s2sFormGenerator.getFormObject(pdDoc);
375                        
376                        if (s2SValidatorService.validate(formObject, errors, info.getFormName()) && errors.isEmpty()) {
377                            String applicationXml = formObject.xmlText(s2SFormGeneratorService.getXmlOptionsPrefixes());
378                            String filteredApplicationXml = s2SDateTimeService.removeTimezoneFactor(applicationXml);
379                                byte[] formXmlBytes = filteredApplicationXml.getBytes();
380                GenericPrintable formPrintable = new GenericPrintable();
381                                // Linkedhashmap is used to preserve the order of entry.
382                                Map<String, byte[]> formXmlDataMap = new LinkedHashMap<String, byte[]>();
383                                formXmlDataMap.put(info.getFormName(), formXmlBytes);
384                                formPrintable.setStreamMap(formXmlDataMap);
385
386                                ArrayList<Source> templates = new ArrayList<Source>();
387
388                DefaultResourceLoader resourceLoader = new DefaultResourceLoader(ClassLoaderUtils.getDefaultClassLoader());
389                Resource resource = resourceLoader.getResource(info.getStyleSheet());
390
391                Source xsltSource = null;
392                try {
393                    xsltSource = new StreamSource(resource.getInputStream());
394                } catch (IOException e) {
395                    throw new S2SException(e);
396                }
397                templates.add(xsltSource);
398                                formPrintable.setXSLTemplates(templates);
399
400                                List<AttachmentData> attachmentList = s2sFormGenerator.getAttachments();
401                                try {
402                                    if(developmentProposal.getGrantsGovSelectFlag()){
403                                        List<S2sAppAttachmentsContract> attachmentLists = new ArrayList<S2sAppAttachmentsContract>();
404                                        setFormObject(forms, formObject);
405                        saveGrantsGovXml(pdDoc,formEntryFlag,forms,attachmentList,attachmentLists);
406                        formEntryFlag = false;
407                                    }
408                }
409                catch (Exception e) {
410                        LOG.error(e.getMessage(), e);
411                }
412                                Map<String, byte[]> formAttachments = new LinkedHashMap<String, byte[]>();
413                                if (attachmentList != null && !attachmentList.isEmpty()) {
414                                        for (AttachmentData attachmentData : attachmentList) {
415                                                if (!isPdfType(attachmentData.getContent()))
416                                                        continue;
417                                                StringBuilder attachment = new StringBuilder();
418                                                attachment.append("   ATT : ");
419                                                attachment.append(attachmentData.getContentId());
420                                                formAttachments.put(attachment.toString(),
421                                                                attachmentData.getContent());
422                                        }
423                                }
424                                if (formAttachments.size() > 0) {
425                                        formPrintable.setAttachments(formAttachments);
426                                }
427                                formPrintables.add(formPrintable);
428                        }
429                }
430        final PrintableResult result = new PrintableResult();
431        result.errors = errors;
432        result.printables = formPrintables;
433        return result;
434        }
435
436        /**
437         * 
438         * This method gets formObject from submitted Application
439         * 
440         * @param submittedXml
441         *            GrantApplicationDocument object of the submitted form.
442         * @param info
443         *            form mapping information of the form.
444         * @return XmlObject form object corresponding to the
445         *         GrantApplicationDocument and FormMappingInfo objects.
446         * @throws S2SException
447         */
448
449        protected XmlObject getFormObject(GrantApplicationDocument submittedXml,
450                        FormMappingInfo info) {
451                Forms forms = submittedXml.getGrantApplication().getForms();
452                return forms.newCursor().getObject();
453        }
454
455        /**
456         * 
457         * This method gets attachment contents from narrative based on content ID
458         * 
459         * @param pdDoc
460         *            Proposal Development Document.
461         * @param contentId
462         *            for the particular attachment in the Narrative.
463         * @return byte[] byte array of attachments based on the contentId object.
464         */
465
466        protected byte[] getAttContent(ProposalDevelopmentDocumentContract pdDoc,
467                        String contentId) {
468                String[] contentIds = contentId.split("-");
469                String[] contentDesc = contentIds[1].split("_");
470                if (StringUtils.equals(contentIds[0], "N")) {
471                for (NarrativeContract narrative : pdDoc.getDevelopmentProposal()
472                                .getNarratives()) {
473                                if (narrative.getModuleNumber().equals(Integer.valueOf(contentDesc[0]))) {
474                                    return narrative.getNarrativeAttachment().getData();
475                                }
476                }
477                } else if (StringUtils.equals(contentIds[0], "B")){
478                    for (ProposalPersonBiographyContract biography : pdDoc.getDevelopmentProposal().getPropPersonBios()) {
479                        if (biography.getProposalPersonNumber().equals(Integer.valueOf(contentDesc[0]))
480                                && biography.getBiographyNumber().equals(Integer.valueOf(contentDesc[1]))) {
481                            return biography.getPersonnelAttachment().getData();
482                        }
483                    }
484        }
485                return null;
486        }
487
488        protected KcFile getAttributeContent(ProposalDevelopmentDocumentContract pdDoc,
489            String contentId) {
490        String[] contentIds = contentId.split("-");
491        String[] contentDesc = contentIds[1].split("_");
492        if (StringUtils.equals(contentIds[0], "N")) {
493            for (NarrativeContract narrative : pdDoc.getDevelopmentProposal()
494                    .getNarratives()) {
495                if (narrative.getModuleNumber().equals(Integer.valueOf(contentDesc[0]))) {
496                    return narrative.getNarrativeAttachment();
497                }
498            }
499        } else if (StringUtils.equals(contentIds[0], "B")){
500            for (ProposalPersonBiographyContract biography : pdDoc.getDevelopmentProposal().getPropPersonBios()) {
501                if (biography.getProposalPersonNumber().equals(Integer.valueOf(contentDesc[0]))
502                        && biography.getBiographyNumber().equals(Integer.valueOf(contentDesc[1]))) {
503                    return biography.getPersonnelAttachment();
504                }
505            }
506        }
507        return null;
508    }
509        /**
510         * 
511         * This method gets the latest S2SAppSubmission record from the list of
512         * S2SAppSubmissions. It iterates through the list and returns the record
513         * that has highest SubmissionNo
514         * 
515         * @param pdDoc
516         *            {@link ProposalDevelopmentDocumentContract}
517         * @return {@link S2sAppSubmissionContract}
518         */
519        protected S2sAppSubmissionContract getLatestS2SAppSubmission(
520                        ProposalDevelopmentDocumentContract pdDoc) {
521                S2sAppSubmissionContract s2sSubmission = null;
522                int submissionNo = 0;
523                for (S2sAppSubmissionContract s2sAppSubmission : pdDoc.getDevelopmentProposal()
524                                .getS2sAppSubmission()) {
525                        if (s2sAppSubmission.getSubmissionNumber() != null
526                                        && s2sAppSubmission.getSubmissionNumber().intValue() > submissionNo) {
527                                s2sSubmission = s2sAppSubmission;
528                                submissionNo = s2sAppSubmission.getSubmissionNumber().intValue();
529                        }
530                }
531                return s2sSubmission;
532        }
533
534
535
536        /**
537         * 
538         * This method sorts all the forms in order as specified in
539         * S2sFormBinding.xml and returns the list of namespaces in sorted order.
540         * 
541         * @param s2sOppForms
542         *            list of S2sOppForms.
543         * @return List<String> list of sorted name spaces.
544         */
545        protected List<String> getSortedNameSpaces(String proposalNumber,List<? extends S2sOppFormsContract> s2sOppForms) {
546                List<String> orderedNamespaces = new ArrayList<String>();
547                Set<String> namespaces;
548        formMappingService.getBindings();
549                Map<Integer, Set<String>> sortedNamespaces = formMappingService.getSortedNameSpaces();
550                List<Integer> sortedIndices = new ArrayList<Integer>(sortedNamespaces
551                                .keySet());
552                int index = 0;
553                for (Integer sortedIndex : sortedIndices) {
554            for (S2sOppFormsContract oppForm : s2sOppForms) {
555                namespaces = sortedNamespaces.get(sortedIndex);
556                for (String namespace : namespaces) {
557                                        if (namespace.equals(oppForm.getOppNameSpace())) {
558                                                if (Boolean.TRUE.equals(oppForm.getSelectToPrint())) {
559                                                        orderedNamespaces.add(index++, namespace);
560                                                }
561                                        }
562                                }
563                        }
564                }
565                List<String> userAttachedFormNamespaces = findUserAttachedNamespaces(proposalNumber);
566        for (S2sOppFormsContract oppForm : s2sOppForms) {
567            if(userAttachedFormNamespaces.contains(oppForm.getOppNameSpace())){
568                orderedNamespaces.add(oppForm.getOppNameSpace());
569            }
570        }
571                return orderedNamespaces;
572        }
573
574    private List<String> findUserAttachedNamespaces(String proposalNumber) {
575        return userAttachedFormService.findFormNamespaces(proposalNumber);
576    }
577
578    /**
579         * 
580         * Setter for {@link org.kuali.coeus.s2sgen.impl.generate.S2SFormGeneratorRetrievalService}
581         * 
582         * @param s2SFormGeneratorService
583         */
584        public void setS2SFormGeneratorService(
585                        S2SFormGeneratorRetrievalService s2SFormGeneratorService) {
586                this.s2SFormGeneratorService = s2SFormGeneratorService;
587        }
588
589        /**
590         * 
591         * Setter for {@link org.kuali.coeus.s2sgen.impl.generate.S2SFormGeneratorRetrievalService}
592         * 
593         * @param s2SValidatorService
594         */
595        public void setS2SValidatorService(S2SValidatorService s2SValidatorService) {
596                this.s2SValidatorService = s2SValidatorService;
597        }
598
599        protected boolean isPdfType(byte[] data) {
600                final int ATTRIBUTE_CHUNK_SIZE = 1200;// increased for ppt
601                final String PRE_HEXA = "0x";
602
603                boolean retValue = false;
604                String str[] = { "25", "50", "44", "46" };
605                byte byteCheckArr[] = new byte[4];
606                byte byteDataArr[] = new byte[4];
607
608                for (int byteIndex = 0; byteIndex < byteCheckArr.length; byteIndex++) {
609                        byteCheckArr[byteIndex] = Integer.decode(PRE_HEXA + str[byteIndex])
610                                        .byteValue();
611                }
612
613                int startPoint, endPoint;
614
615                startPoint = 0;
616                endPoint = (ATTRIBUTE_CHUNK_SIZE > (data.length / 2)) ? data.length / 2
617                                : ATTRIBUTE_CHUNK_SIZE;
618
619                for (int forwardIndex = startPoint; forwardIndex < endPoint
620                                - str.length; forwardIndex++) {
621                        if (forwardIndex == 0) {
622                                // Fill All Data
623                                for (int fillIndex = 0; fillIndex < str.length; fillIndex++) {
624                                        byteDataArr[fillIndex] = toUnsignedByte(data[fillIndex]);
625                                }
626                        } else {
627                                // Push Data, Fill last index
628                                for (int fillIndex = 0; fillIndex < str.length - 1; fillIndex++) {
629                                        byteDataArr[fillIndex] = byteDataArr[fillIndex + 1];
630                                }
631                                byteDataArr[str.length - 1] = toUnsignedByte(data[str.length
632                                                - 1 + forwardIndex]);
633                        }
634
635                        if (new String(byteCheckArr).equals(new String(byteDataArr))) {
636                                retValue = true;
637                        }
638                }
639
640                return retValue;
641        }
642
643        /**
644         * convert int to unsigned byte
645         */
646        protected static byte toUnsignedByte(int intVal) {
647                byte byteVal;
648                if (intVal > 127) {
649                        int temp = intVal - 256;
650                        byteVal = (byte) temp;
651                } else {
652                        byteVal = (byte) intVal;
653                }
654                return byteVal;
655        }
656
657    public NarrativeService getNarrativeService() {
658        return narrativeService;
659    }
660
661    public void setNarrativeService(NarrativeService narrativeService) {
662        this.narrativeService = narrativeService;
663    }
664
665    public S2SPrintingService getS2SPrintingService() {
666                return s2SPrintingService;
667        }
668
669        public void setS2SPrintingService(S2SPrintingService s2SPrintingService) {
670                this.s2SPrintingService = s2SPrintingService;
671        }
672        protected void setFormObject(Forms forms, XmlObject formObject) {
673        // Create a cursor from the grants.gov form
674        XmlCursor formCursor = formObject.newCursor();
675        formCursor.toStartDoc();
676        formCursor.toNextToken();
677
678        // Create a cursor from the Forms object
679        XmlCursor metaGrantCursor = forms.newCursor();
680        metaGrantCursor.toNextToken();
681
682        // Add the form to the Forms object.
683        formCursor.moveXml(metaGrantCursor);
684    }
685
686    public S2SConfigurationService getS2SConfigurationService() {
687        return s2SConfigurationService;
688    }
689
690    public void setS2SConfigurationService(S2SConfigurationService s2SConfigurationService) {
691        this.s2SConfigurationService = s2SConfigurationService;
692    }
693
694    public S2sApplicationService getS2sApplicationService() {
695        return s2sApplicationService;
696    }
697
698    public void setS2sApplicationService(S2sApplicationService s2sApplicationService) {
699        this.s2sApplicationService = s2sApplicationService;
700    }
701
702    public S2SFormGeneratorRetrievalService getS2SFormGeneratorService() {
703        return s2SFormGeneratorService;
704    }
705
706    public S2SValidatorService getS2SValidatorService() {
707        return s2SValidatorService;
708    }
709
710    public FormMappingService getFormMappingService() {
711        return formMappingService;
712    }
713
714    public void setFormMappingService(FormMappingService formMappingService) {
715        this.formMappingService = formMappingService;
716    }
717
718    public UserAttachedFormService getUserAttachedFormService() {
719        return userAttachedFormService;
720    }
721
722    public void setUserAttachedFormService(UserAttachedFormService userAttachedFormService) {
723        this.userAttachedFormService = userAttachedFormService;
724    }
725
726    public S2SDateTimeService getS2SDateTimeService() {
727        return s2SDateTimeService;
728    }
729
730    public void setS2SDateTimeService(S2SDateTimeService s2SDateTimeService) {
731        this.s2SDateTimeService = s2SDateTimeService;
732    }
733
734    protected static class PrintableResult {
735        private List<S2SPrintable> printables;
736        private List<AuditError> errors;
737    }
738}