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.party.server.command;
018
019import com.echothree.control.user.party.common.edit.PartyEditFactory;
020import com.echothree.control.user.party.common.edit.ProfileEdit;
021import com.echothree.control.user.party.common.form.EditProfileForm;
022import com.echothree.control.user.party.common.result.EditProfileResult;
023import com.echothree.control.user.party.common.result.PartyResultFactory;
024import com.echothree.control.user.party.common.spec.PartySpec;
025import com.echothree.model.control.core.common.MimeTypeUsageTypes;
026import com.echothree.model.control.core.server.logic.MimeTypeLogic;
027import com.echothree.model.control.icon.common.IconConstants;
028import com.echothree.model.control.icon.server.control.IconControl;
029import com.echothree.model.control.party.common.PartyTypes;
030import com.echothree.model.control.party.server.control.PartyControl;
031import com.echothree.model.data.core.server.entity.MimeType;
032import com.echothree.model.data.icon.server.entity.Icon;
033import com.echothree.model.data.party.server.entity.BirthdayFormat;
034import com.echothree.model.data.party.server.entity.Gender;
035import com.echothree.model.data.party.server.entity.Party;
036import com.echothree.model.data.party.server.entity.Profile;
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.validation.FieldDefinition;
041import com.echothree.util.common.validation.FieldType;
042import com.echothree.util.server.control.BaseAbstractEditCommand;
043import com.echothree.util.server.persistence.Session;
044import com.echothree.util.server.string.DateUtils;
045import java.util.List;
046import javax.enterprise.context.Dependent;
047
048@Dependent
049public class EditProfileCommand
050        extends BaseAbstractEditCommand<PartySpec, ProfileEdit, EditProfileResult, Profile, Party> {
051    
052    private final static List<FieldDefinition> SPEC_FIELD_DEFINITIONS;
053    private final static List<FieldDefinition> customerEditFieldDefinitions;
054    private final static List<FieldDefinition> otherEditFieldDefinitions;
055    
056    static {
057        SPEC_FIELD_DEFINITIONS = List.of(
058                new FieldDefinition("PartyName", FieldType.ENTITY_NAME, false, null, null)
059                );
060        
061        customerEditFieldDefinitions = List.of(
062                new FieldDefinition("Nickname", FieldType.STRING, true, 1L, 40L),
063                new FieldDefinition("IconName", FieldType.ENTITY_NAME, false, null, null),
064                new FieldDefinition("Pronunciation", FieldType.STRING, false, 1L, 200L),
065                new FieldDefinition("GenderName", FieldType.ENTITY_NAME, false, null, null),
066                new FieldDefinition("Pronouns", FieldType.STRING, false, 1L, 50L),
067                new FieldDefinition("Birthday", FieldType.DATE, false, null, null),
068                new FieldDefinition("BirthdayFormatName", FieldType.ENTITY_NAME, true, null, null),
069                new FieldDefinition("Occupation", FieldType.STRING, false, 1L, 200L),
070                new FieldDefinition("Hobbies", FieldType.STRING, false, 1L, 200L),
071                new FieldDefinition("Location", FieldType.STRING, false, 1L, 60L),
072                new FieldDefinition("BioMimeTypeName", FieldType.MIME_TYPE, false, null, null),
073                new FieldDefinition("Bio", FieldType.STRING, false, 1L, 512L),
074                new FieldDefinition("SignatureMimeTypeName", FieldType.MIME_TYPE, false, null, null),
075                new FieldDefinition("Signature", FieldType.STRING, false, 1L, 512L)
076                );
077        
078        otherEditFieldDefinitions = List.of(
079                new FieldDefinition("Nickname", FieldType.STRING, false, 1L, 40L),
080                new FieldDefinition("IconName", FieldType.ENTITY_NAME, false, null, null),
081                new FieldDefinition("Pronunciation", FieldType.STRING, false, 1L, 200L),
082                new FieldDefinition("GenderName", FieldType.ENTITY_NAME, false, null, null),
083                new FieldDefinition("Pronouns", FieldType.STRING, false, 1L, 50L),
084                new FieldDefinition("Birthday", FieldType.DATE, false, null, null),
085                new FieldDefinition("BirthdayFormatName", FieldType.ENTITY_NAME, true, null, null),
086                new FieldDefinition("Occupation", FieldType.STRING, false, 1L, 200L),
087                new FieldDefinition("Hobbies", FieldType.STRING, false, 1L, 200L),
088                new FieldDefinition("Location", FieldType.STRING, false, 1L, 60L),
089                new FieldDefinition("BioMimeTypeName", FieldType.MIME_TYPE, false, null, null),
090                new FieldDefinition("Bio", FieldType.STRING, false, 1L, 512L),
091                new FieldDefinition("SignatureMimeTypeName", FieldType.MIME_TYPE, false, null, null),
092                new FieldDefinition("Signature", FieldType.STRING, false, 1L, 512L)
093                );
094    }
095    
096    /** Creates a new instance of EditProfileCommand */
097    public EditProfileCommand() {
098        super(null, SPEC_FIELD_DEFINITIONS, null);
099    }
100    
101    @Override
102    protected List<FieldDefinition> getEditFieldDefinitions() {
103        var partyTypeName = getPartyTypeName();
104        
105        return partyTypeName == null || partyTypeName.equals(PartyTypes.CUSTOMER.name()) ? customerEditFieldDefinitions : otherEditFieldDefinitions;
106    }
107    
108    @Override
109    public EditProfileResult getResult() {
110        return PartyResultFactory.getEditProfileResult();
111    }
112
113    @Override
114    public ProfileEdit getEdit() {
115        return PartyEditFactory.getProfileEdit();
116    }
117
118    @Override
119    public Profile getEntity(EditProfileResult result) {
120        var partyControl = Session.getModelController(PartyControl.class);
121        Profile profile = null;
122        var partyTypeName = getPartyTypeName();
123        var partyName = partyTypeName.equals(PartyTypes.CUSTOMER.name()) ? null : spec.getPartyName();
124        var party = partyName == null ? null : partyControl.getPartyByName(partyName);
125
126        if(partyName == null || party != null) {
127            if(party == null) {
128                party = getParty();
129            }
130
131            if(party == null) {
132                addExecutionError(ExecutionErrors.PartyRequired.name());
133            } else {
134                if(editMode.equals(EditMode.LOCK) || editMode.equals(EditMode.ABANDON)) {
135                    profile = partyControl.getProfile(party);
136                } else { // EditMode.UPDATE
137                    profile = partyControl.getProfileForUpdate(party);
138                }
139
140                if(profile == null) {
141                    addExecutionError(ExecutionErrors.UnknownProfile.name(), partyName);
142                }
143            }
144        } else {
145            addExecutionError(ExecutionErrors.UnknownPartyName.name(), partyName);
146        }
147
148        return profile;
149    }
150
151    @Override
152    public Party getLockEntity(Profile profile) {
153        return profile.getParty();
154    }
155
156    @Override
157    public void fillInResult(EditProfileResult result, Profile profile) {
158        var partyControl = Session.getModelController(PartyControl.class);
159
160        result.setParty(partyControl.getPartyTransfer(getUserVisit(), profile.getParty()));
161    }
162
163    Icon icon;
164    Gender gender;
165    MimeType bioMimeType;
166    MimeType signatureMimeType;
167
168    @Override
169    public void doLock(ProfileEdit edit, Profile profile) {
170        icon = profile.getIcon();
171        gender = profile.getGender();
172
173        bioMimeType = profile.getBioMimeType();
174        signatureMimeType = profile.getSignatureMimeType();
175
176        edit.setNickname(profile.getNickname());
177        edit.setIconName(icon == null? null: icon.getLastDetail().getIconName());
178        edit.setPronunciation(profile.getPronunciation());
179        edit.setGenderName(gender == null? null: gender.getLastDetail().getGenderName());
180        edit.setPronouns(profile.getPronouns());
181        edit.setBirthday(DateUtils.getInstance().formatDate(getUserVisit(), profile.getBirthday()));
182        edit.setBirthdayFormatName(profile.getBirthdayFormat().getLastDetail().getBirthdayFormatName());
183        edit.setOccupation(profile.getOccupation());
184        edit.setHobbies(profile.getHobbies());
185        edit.setLocation(profile.getLocation());
186        edit.setBioMimeTypeName(bioMimeType == null ? null : bioMimeType.getLastDetail().getMimeTypeName());
187        edit.setBio(profile.getBio());
188        edit.setSignatureMimeTypeName(signatureMimeType == null ? null : signatureMimeType.getLastDetail().getMimeTypeName());
189        edit.setSignature(profile.getSignature());
190    }
191
192    BirthdayFormat birthdayFormat;
193
194    @Override
195    protected void canUpdate(Profile profile) {
196        var partyControl = Session.getModelController(PartyControl.class);
197        var mimeTypeLogic = MimeTypeLogic.getInstance();
198        var bioMimeTypeName = edit.getBioMimeTypeName();
199        var bio = edit.getBio();
200        var signatureMimeTypeName = edit.getSignatureMimeTypeName();
201        var signature = edit.getSignature();
202
203        bioMimeType = mimeTypeLogic.checkMimeType(this, bioMimeTypeName, bio, MimeTypeUsageTypes.TEXT.name(),
204                ExecutionErrors.MissingRequiredBioMimeTypeName.name(), ExecutionErrors.MissingRequiredBio.name(),
205                ExecutionErrors.UnknownBioMimeTypeName.name(), ExecutionErrors.UnknownBioMimeTypeUsage.name());
206
207        signatureMimeType = mimeTypeLogic.checkMimeType(this, signatureMimeTypeName, signature, MimeTypeUsageTypes.TEXT.name(),
208                ExecutionErrors.MissingRequiredSignatureMimeTypeName.name(), ExecutionErrors.MissingRequiredSignature.name(),
209                ExecutionErrors.UnknownSignatureMimeTypeName.name(), ExecutionErrors.UnknownSignatureMimeTypeUsage.name());
210
211        var nickname = edit.getNickname();
212        var duplicateProfile = nickname == null ? null : partyControl.getProfileByNickname(nickname);
213
214        if(duplicateProfile == null || duplicateProfile.getPrimaryKey().equals(profile.getPrimaryKey())) {
215            var iconControl = Session.getModelController(IconControl.class);
216            var iconName = edit.getIconName();
217
218            icon = iconName == null? null: iconControl.getIconByName(iconName);
219
220            if(iconName == null || icon != null) {
221                if(icon != null) {
222                    var iconUsageType = iconControl.getIconUsageTypeByName(IconConstants.IconUsageType_PROFILE);
223                    var iconUsage = iconControl.getIconUsage(iconUsageType, icon);
224
225                    if(iconUsage == null) {
226                        addExecutionError(ExecutionErrors.UnknownIconUsage.name());
227                    }
228                }
229
230                if(!hasExecutionErrors()) {
231                    var genderName = edit.getGenderName();
232
233                    gender = genderName == null? null: partyControl.getGenderByName(genderName);
234
235                    if(genderName == null || gender != null) {
236                        var birthdayFormatName = edit.getBirthdayFormatName();
237
238                        birthdayFormat = birthdayFormatName == null ? null : partyControl.getBirthdayFormatByName(birthdayFormatName);
239
240                        if(birthdayFormat == null) {
241                            addExecutionError(ExecutionErrors.UnknownBirthdayFormatName.name(), birthdayFormatName);
242                        }
243                    } else {
244                        addExecutionError(ExecutionErrors.UnknownGenderName.name(), genderName);
245                    }
246                }
247            } else {
248                addExecutionError(ExecutionErrors.UnknownIconName.name(), iconName);
249            }
250        } else {
251            addExecutionError(ExecutionErrors.DuplicateNickname.name(), nickname);
252        }
253    }
254
255    @Override
256    public void doUpdate(Profile profile) {
257        var partyControl = Session.getModelController(PartyControl.class);
258        var profileValue = partyControl.getProfileValue(profile);
259        var nickname = edit.getNickname();
260        var pronunciation = edit.getPronunciation();
261        var pronouns = edit.getPronouns();
262        var birthday = edit.getBirthday();
263
264        profileValue.setNickname(nickname);
265        profileValue.setIconPK(icon == null ? null : icon.getPrimaryKey());
266        profileValue.setPronunciation(pronunciation);
267        profileValue.setGenderPK(gender == null ? null : gender.getPrimaryKey());
268        profileValue.setPronouns(pronouns);
269        profileValue.setBirthday(birthday == null ? null : Integer.valueOf(birthday));
270        profileValue.setBirthdayFormatPK(birthdayFormat.getPrimaryKey());
271        profileValue.setOccupation(edit.getOccupation());
272        profileValue.setHobbies(edit.getHobbies());
273        profileValue.setLocation(edit.getLocation());
274        profileValue.setBioMimeTypePK(bioMimeType == null ? null : bioMimeType.getPrimaryKey());
275        profileValue.setBio(edit.getBio());
276        profileValue.setSignatureMimeTypePK(signatureMimeType == null ? null : signatureMimeType.getPrimaryKey());
277        profileValue.setSignature(edit.getSignature());
278
279        partyControl.updateProfileFromValue(profileValue, getPartyPK());
280    }
281    
282}