001// --------------------------------------------------------------------------------
002// Copyright 2002-2026 Echo Three, LLC
003//
004// Licensed under the Apache License, Version 2.0 (the "License");
005// you may not use this file except in compliance with the License.
006// You may obtain a copy of the License at
007//
008//     http://www.apache.org/licenses/LICENSE-2.0
009//
010// Unless required by applicable law or agreed to in writing, software
011// distributed under the License is distributed on an "AS IS" BASIS,
012// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013// See the License for the specific language governing permissions and
014// limitations under the License.
015// --------------------------------------------------------------------------------
016
017package com.echothree.model.control.document.server.logic;
018
019import com.echothree.control.user.document.common.spec.DocumentUniversalSpec;
020import com.echothree.model.control.core.common.ComponentVendors;
021import com.echothree.model.control.core.common.EntityAttributeTypes;
022import com.echothree.model.control.core.common.EntityTypes;
023import com.echothree.model.control.core.common.MimeTypes;
024import com.echothree.model.control.core.common.exception.InvalidParameterCountException;
025import com.echothree.model.control.core.server.logic.EntityInstanceLogic;
026import com.echothree.model.control.document.common.exception.UnknownDocumentNameException;
027import com.echothree.model.control.document.server.control.DocumentControl;
028import com.echothree.model.data.core.server.entity.MimeType;
029import com.echothree.model.data.document.server.entity.Document;
030import com.echothree.model.data.document.server.entity.DocumentType;
031import com.echothree.model.data.document.server.entity.PartyDocument;
032import com.echothree.model.data.party.common.pk.PartyPK;
033import com.echothree.model.data.party.server.entity.Language;
034import com.echothree.model.data.party.server.entity.Party;
035import com.echothree.util.common.message.ExecutionErrors;
036import com.echothree.util.common.persistence.type.ByteArray;
037import com.echothree.util.server.control.BaseLogic;
038import com.echothree.util.server.message.ExecutionErrorAccumulator;
039import com.echothree.util.server.persistence.EntityPermission;
040import com.lowagie.text.pdf.PdfReader;
041import java.io.IOException;
042import javax.enterprise.context.ApplicationScoped;
043import javax.enterprise.inject.spi.CDI;
044import javax.inject.Inject;
045
046@ApplicationScoped
047public class DocumentLogic
048        extends BaseLogic {
049
050    @Inject
051    DocumentControl documentControl;
052
053    @Inject
054    EntityInstanceLogic entityInstanceLogic;
055
056    protected DocumentLogic() {
057        super();
058    }
059
060    public static DocumentLogic getInstance() {
061        return CDI.current().select(DocumentLogic.class).get();
062    }
063
064    public Integer getPages(final MimeType mimeType, final ByteArray blob, final String clob) {
065        Integer pages = null;
066        var entityAttributeTypeName = mimeType.getLastDetail().getEntityAttributeType().getEntityAttributeTypeName();
067
068        if(entityAttributeTypeName.equals(EntityAttributeTypes.BLOB.name())) {
069            var mimeTypeName = mimeType.getLastDetail().getMimeTypeName();
070
071            if(mimeTypeName.equals(MimeTypes.APPLICATION_PDF.mimeTypeName()) && blob != null) {
072                try {
073                    var pdfReader = new PdfReader(blob.getByteArrayInputStream());
074
075                    pages = pdfReader.getNumberOfPages();
076                } catch(IOException ioe) {
077                    // Nothing, pages stays null.
078                }
079            }
080        }
081
082        return pages;
083    }
084
085    public Document createDocument(final ExecutionErrorAccumulator ema, final DocumentType documentType, final MimeType mimeType,
086            final Language preferredLanguage, final String description, final ByteArray blob, final String clob, final PartyPK createdBy) {
087        var pages = getPages(mimeType, blob, clob);
088        Document document = null;
089        var hasErrors = false;
090
091        if(pages != null) {
092            var documentTypeDetail = documentType.getLastDetail();
093            var maximumPages = documentTypeDetail.getMaximumPages();
094
095            if(maximumPages != null) {
096                if(pages > maximumPages) {
097                    hasErrors = true;
098                    addExecutionError(ema, ExecutionErrors.DocumentExceedesMaximumPages.name());
099                }
100            }
101        }
102
103        if(!hasErrors) {
104            document = documentControl.createDocument(documentType, mimeType, pages, createdBy);
105
106            if(blob != null) {
107                documentControl.createDocumentBlob(document, blob, createdBy);
108            } else if(clob != null) {
109                documentControl.createDocumentClob(document, clob, createdBy);
110            }
111
112            if(description != null) {
113                documentControl.createDocumentDescription(document, preferredLanguage, description, createdBy);
114            }
115        }
116
117        return document;
118    }
119
120    public Document getDocumentByName(final ExecutionErrorAccumulator eea, final String documentName,
121            final EntityPermission entityPermission) {
122        var document = documentControl.getDocumentByName(documentName, entityPermission);
123
124        if(document == null) {
125            handleExecutionError(UnknownDocumentNameException.class, eea, ExecutionErrors.UnknownDocumentName.name(),
126                    documentName);
127        }
128
129        return document;
130    }
131
132    public Document getDocumentByName(final ExecutionErrorAccumulator eea, final String documentName) {
133        return getDocumentByName(eea, documentName, EntityPermission.READ_ONLY);
134    }
135
136    public Document getDocumentByNameForUpdate(final ExecutionErrorAccumulator eea, final String documentName) {
137        return getDocumentByName(eea, documentName, EntityPermission.READ_WRITE);
138    }
139
140    public Document getDocumentByUniversalSpec(final ExecutionErrorAccumulator eea,
141            final DocumentUniversalSpec universalSpec, final EntityPermission entityPermission) {
142        Document document = null;
143        var documentName = universalSpec.getDocumentName();
144        var possibleEntitySpecs = entityInstanceLogic.countPossibleEntitySpecs(universalSpec);
145        var parameterCount = (documentName == null ? 0 : 1) + possibleEntitySpecs;
146
147        switch(parameterCount) {
148            case 1 -> {
149                if(possibleEntitySpecs == 1) {
150                    var entityInstance = entityInstanceLogic.getEntityInstance(eea, universalSpec,
151                            ComponentVendors.ECHO_THREE.name(), EntityTypes.Document.name());
152
153                    if(eea == null || !eea.hasExecutionErrors()) {
154                        document = documentControl.getDocumentByEntityInstance(entityInstance, entityPermission);
155                    }
156                } else {
157                    document = getDocumentByName(eea, documentName, entityPermission);
158                }
159            }
160            default ->
161                    handleExecutionError(InvalidParameterCountException.class, eea,
162                            ExecutionErrors.InvalidParameterCount.name());
163        }
164
165        return document;
166    }
167
168    public Document getDocumentByUniversalSpec(final ExecutionErrorAccumulator eea,
169            final DocumentUniversalSpec universalSpec) {
170        return getDocumentByUniversalSpec(eea, universalSpec, EntityPermission.READ_ONLY);
171    }
172
173    public Document getDocumentByUniversalSpecForUpdate(final ExecutionErrorAccumulator eea,
174            final DocumentUniversalSpec universalSpec) {
175        return getDocumentByUniversalSpec(eea, universalSpec, EntityPermission.READ_WRITE);
176    }
177
178    public PartyDocument createPartyDocument(final ExecutionErrorAccumulator ema, final Party party, final DocumentType documentType, final MimeType mimeType,
179            final Boolean isDefault, final Integer sortOrder,  final Language preferredLanguage, final String description, final ByteArray blob,
180            final String clob, final PartyPK createdBy) {
181        var document = createDocument(ema, documentType, mimeType, preferredLanguage, description, blob, clob, createdBy);
182
183        return document == null ? null : documentControl.createPartyDocument(party, document, isDefault, sortOrder, createdBy);
184    }
185
186}