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.control.user.document.server.command;
018
019import com.echothree.control.user.document.common.edit.DocumentEditFactory;
020import com.echothree.control.user.document.common.edit.PartyDocumentEdit;
021import com.echothree.control.user.document.common.form.EditPartyDocumentForm;
022import com.echothree.control.user.document.common.result.DocumentResultFactory;
023import com.echothree.control.user.document.common.result.EditPartyDocumentResult;
024import com.echothree.control.user.document.common.spec.DocumentSpec;
025import com.echothree.model.control.core.common.EntityAttributeTypes;
026import com.echothree.model.control.core.server.control.MimeTypeControl;
027import com.echothree.model.control.document.server.control.DocumentControl;
028import com.echothree.model.control.document.server.logic.DocumentLogic;
029import com.echothree.model.control.party.common.PartyTypes;
030import com.echothree.model.control.security.common.SecurityRoleGroups;
031import com.echothree.model.control.security.common.SecurityRoles;
032import com.echothree.model.data.core.server.entity.MimeType;
033import com.echothree.model.data.document.server.entity.Document;
034import com.echothree.model.data.document.server.entity.DocumentBlob;
035import com.echothree.model.data.document.server.entity.DocumentClob;
036import com.echothree.model.data.document.server.entity.PartyDocument;
037import com.echothree.model.data.user.common.pk.UserVisitPK;
038import com.echothree.util.common.command.EditMode;
039import com.echothree.util.common.message.ExecutionErrors;
040import com.echothree.util.common.persistence.type.ByteArray;
041import com.echothree.util.common.validation.FieldDefinition;
042import com.echothree.util.common.validation.FieldType;
043import com.echothree.util.server.control.BaseAbstractEditCommand;
044import com.echothree.util.server.control.CommandSecurityDefinition;
045import com.echothree.util.server.control.PartyTypeDefinition;
046import com.echothree.util.server.control.SecurityRoleDefinition;
047import java.util.List;
048import javax.enterprise.context.Dependent;
049import javax.inject.Inject;
050
051@Dependent
052public class EditPartyDocumentCommand
053        extends BaseAbstractEditCommand<DocumentSpec, PartyDocumentEdit, EditPartyDocumentResult, PartyDocument, Document> {
054    
055    private final static CommandSecurityDefinition COMMAND_SECURITY_DEFINITION;
056    private final static List<FieldDefinition> SPEC_FIELD_DEFINITIONS;
057    private final static List<FieldDefinition> EDIT_FIELD_DEFINITIONS;
058    
059    static {
060        COMMAND_SECURITY_DEFINITION = new CommandSecurityDefinition(List.of(
061                new PartyTypeDefinition(PartyTypes.UTILITY.name(), null),
062                new PartyTypeDefinition(PartyTypes.EMPLOYEE.name(), List.of(
063                        new SecurityRoleDefinition(SecurityRoleGroups.PartyDocument.name(), SecurityRoles.Edit.name())
064                ))
065        ));
066        
067        SPEC_FIELD_DEFINITIONS = List.of(
068                new FieldDefinition("DocumentName", FieldType.ENTITY_NAME, true, null, null)
069        );
070        
071        EDIT_FIELD_DEFINITIONS = List.of(
072                new FieldDefinition("MimeTypeName", FieldType.MIME_TYPE, true, null, null),
073                new FieldDefinition("IsDefault", FieldType.BOOLEAN, true, null, null),
074                new FieldDefinition("SortOrder", FieldType.SIGNED_INTEGER, true, null, null),
075                new FieldDefinition("Description", FieldType.STRING, false, 1L, 132L),
076                new FieldDefinition("Clob", FieldType.STRING, false, 1L, null)
077        );
078    }
079
080    @Inject
081    DocumentControl documentControl;
082
083    @Inject
084    MimeTypeControl mimeTypeControl;
085
086    @Inject
087    DocumentLogic documentLogic;
088
089    
090    /** Creates a new instance of EditPartyDocumentCommand */
091    public EditPartyDocumentCommand() {
092        super(COMMAND_SECURITY_DEFINITION, SPEC_FIELD_DEFINITIONS, EDIT_FIELD_DEFINITIONS);
093    }
094
095    @Override
096    public EditPartyDocumentResult getResult() {
097        return DocumentResultFactory.getEditPartyDocumentResult();
098    }
099
100    @Override
101    public PartyDocumentEdit getEdit() {
102        return DocumentEditFactory.getPartyDocumentEdit();
103    }
104
105    @Override
106    public PartyDocument getEntity(EditPartyDocumentResult result) {
107        PartyDocument partyDocument = null;
108        var documentName = spec.getDocumentName();
109        var document = documentControl.getDocumentByName(documentName);
110
111        if(document != null) {
112            if(editMode.equals(EditMode.LOCK) || editMode.equals(EditMode.ABANDON)) {
113                partyDocument = documentControl.getPartyDocument(document);
114            } else { // EditMode.UPDATE
115                partyDocument = documentControl.getPartyDocumentForUpdate(document);
116            }
117
118            if(partyDocument != null) {
119                result.setPartyDocument(documentControl.getPartyDocumentTransfer(getUserVisit(), partyDocument));
120            } else {
121                addExecutionError(ExecutionErrors.UnknownPartyDocument.name(), documentName);
122            }
123        } else {
124            addExecutionError(ExecutionErrors.UnknownDocumentName.name(), documentName);
125        }
126
127        return partyDocument;
128    }
129
130    @Override
131    public Document getLockEntity(PartyDocument partyDocument) {
132        return partyDocument.getDocument();
133    }
134
135    @Override
136    public void fillInResult(EditPartyDocumentResult result, PartyDocument partyDocument) {
137        result.setPartyDocument(documentControl.getPartyDocumentTransfer(getUserVisit(), partyDocument));
138    }
139
140    MimeType mimeType;
141
142    @Override
143    public void doLock(PartyDocumentEdit edit, PartyDocument partyDocument) {
144        var document = partyDocument.getDocument();
145        var documentDescription = documentControl.getDocumentDescription(document, getPreferredLanguage());
146
147        mimeType = document.getLastDetail().getMimeType();
148
149        edit.setMimeTypeName(mimeType.getLastDetail().getMimeTypeName());
150        edit.setIsDefault(partyDocument.getIsDefault().toString());
151        edit.setSortOrder(partyDocument.getSortOrder().toString());
152
153        if(mimeType.getLastDetail().getEntityAttributeType().getEntityAttributeTypeName().equals(EntityAttributeTypes.CLOB.name())) {
154            var documentClob = documentControl.getDocumentClob(document);
155
156            edit.setClob(documentClob.getClob());
157        }
158
159        if(documentDescription != null) {
160            edit.setDescription(documentDescription.getDescription());
161        }
162    }
163
164    @Override
165    public void canUpdate(PartyDocument partyDocument) {
166        var mimeTypeName = edit.getMimeTypeName();
167
168        mimeType = mimeTypeControl.getMimeTypeByName(mimeTypeName);
169
170        if(mimeType != null) {
171            var mimeTypeUsageType = partyDocument.getDocument().getLastDetail().getDocumentType().getLastDetail().getMimeTypeUsageType();
172            var mimeTypeUsage = mimeTypeUsageType == null ? null : mimeTypeControl.getMimeTypeUsage(mimeType, mimeTypeUsageType);
173
174            if(mimeTypeUsageType == null || mimeTypeUsage != null) {
175                var entityAttributeTypeName = mimeType.getLastDetail().getEntityAttributeType().getEntityAttributeTypeName();
176
177                if(entityAttributeTypeName.equals(EntityAttributeTypes.BLOB.name())) {
178                    var blob = edit.getBlob();
179
180                    if(blob == null) {
181                        addExecutionError(ExecutionErrors.MissingBlob.name());
182                    }
183                } else if(entityAttributeTypeName.equals(EntityAttributeTypes.CLOB.name())) {
184                    var clob = edit.getClob();
185
186                    if(clob == null) {
187                        addExecutionError(ExecutionErrors.MissingClob.name());
188                    }
189                } else {
190                    addExecutionError(ExecutionErrors.UnknownEntityAttributeTypeName.name(), entityAttributeTypeName);
191                }
192            } else {
193                addExecutionError(ExecutionErrors.UnknownMimeTypeUsage.name());
194            }
195        } else {
196            addExecutionError(ExecutionErrors.UnknownMimeTypeName.name(), mimeTypeName);
197        }
198    }
199
200    @Override
201    public void doUpdate(PartyDocument partyDocument) {
202        var partyDocumentValue = documentControl.getPartyDocumentValueForUpdate(partyDocument);
203        var document = partyDocument.getDocument();
204        var documentDetailValue = documentControl.getDocumentDetailValueForUpdate(document);
205        var blob = edit.getBlob();
206        var clob = edit.getClob();
207        var pages = documentLogic.getPages(mimeType, blob, clob);
208        var partyPK = getPartyPK();
209
210        partyDocumentValue.setIsDefault(Boolean.valueOf(edit.getIsDefault()));
211        partyDocumentValue.setSortOrder(Integer.valueOf(edit.getSortOrder()));
212
213        documentControl.updatePartyDocumentFromValue(partyDocumentValue, partyPK);
214
215        documentDetailValue.setMimeTypePK(mimeType.getPrimaryKey());
216        documentDetailValue.setPages(pages);
217
218        documentControl.updateDocumentFromValue(documentDetailValue, partyPK);
219        
220        doLobUpdate(document, blob, clob);
221        doDescriptionUpdate(document);
222    }
223
224    private void doLobUpdate(Document document, ByteArray blob, String clob) {
225        DocumentBlob documentBlob = null;
226        DocumentClob documentClob = null;
227        var oldEntityAttributeTypeName = document.getLastDetail().getMimeType().getLastDetail().getEntityAttributeType().getEntityAttributeTypeName();
228        var entityAttributeTypeName = mimeType.getLastDetail().getEntityAttributeType().getEntityAttributeTypeName();
229        var partyPK = getPartyPK();
230
231        if(oldEntityAttributeTypeName.equals(EntityAttributeTypes.BLOB.name())) {
232            documentBlob = documentControl.getDocumentBlobForUpdate(document);
233        } else if(oldEntityAttributeTypeName.equals(EntityAttributeTypes.CLOB.name())) {
234            documentClob = documentControl.getDocumentClobForUpdate(document);
235        }
236        
237        if(entityAttributeTypeName.equals(EntityAttributeTypes.BLOB.name())) {
238            if(documentClob != null) {
239                documentControl.deleteDocumentClob(documentClob, partyPK);
240                documentControl.createDocumentBlob(document, blob, partyPK);
241            } else {
242                var documentBlobValue = documentControl.getDocumentBlobValue(documentBlob);
243                documentBlobValue.setBlob(blob);
244                documentControl.updateDocumentBlobFromValue(documentBlobValue, partyPK);
245            }
246        } else if(entityAttributeTypeName.equals(EntityAttributeTypes.CLOB.name())) {
247            if(documentBlob != null) {
248                documentControl.deleteDocumentBlob(documentBlob, partyPK);
249                documentControl.createDocumentClob(document, clob, partyPK);
250            } else {
251                var documentClobValue = documentControl.getDocumentClobValue(documentClob);
252                documentClobValue.setClob(clob);
253                documentControl.updateDocumentClobFromValue(documentClobValue, partyPK);
254            }
255        }
256    }
257
258    private void doDescriptionUpdate(Document document) {
259        var documentDescription = documentControl.getDocumentDescriptionForUpdate(document, getPreferredLanguage());
260        var description = edit.getDescription();
261        var partyPK = getPartyPK();
262
263        if(documentDescription == null && description != null) {
264            documentControl.createDocumentDescription(document, getPreferredLanguage(), description, partyPK);
265        } else {
266            if(documentDescription != null && description == null) {
267                documentControl.deleteDocumentDescription(documentDescription, partyPK);
268            } else {
269                if(documentDescription != null && description != null) {
270                    var documentDescriptionValue = documentControl.getDocumentDescriptionValue(documentDescription);
271                    documentDescriptionValue.setDescription(description);
272                    documentControl.updateDocumentDescriptionFromValue(documentDescriptionValue, partyPK);
273                }
274            }
275        }
276    }
277
278}