001// --------------------------------------------------------------------------------
002// Copyright 2002-2025 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.util.server.string;
018
019import com.echothree.model.control.uom.server.control.UomControl;
020import com.echothree.model.control.user.server.control.UserControl;
021import com.echothree.model.data.party.server.entity.Language;
022import com.echothree.model.data.uom.server.entity.UnitOfMeasureKind;
023import com.echothree.model.data.uom.server.entity.UnitOfMeasureType;
024import com.echothree.model.data.user.server.entity.UserVisit;
025import com.echothree.util.server.persistence.Session;
026
027public class UnitOfMeasureUtils {
028    
029    private UnitOfMeasureUtils() {
030        super();
031    }
032    
033    private static class UnitOfMeasureUtilsHolder {
034        static UnitOfMeasureUtils instance = new UnitOfMeasureUtils();
035    }
036    
037    public static UnitOfMeasureUtils getInstance() {
038        return UnitOfMeasureUtilsHolder.instance;
039    }
040    
041    private void appendMeasure(UomControl uomControl, Language language, final StringBuilder builder, final UnitOfMeasureType unitOfMeasureType, final long measure) {
042        if(builder.length() > 0)
043            builder.append(", ");
044        
045        builder.append(measure).append(' ');
046        if(measure == 1) {
047            builder.append(uomControl.getBestSingularUnitOfMeasureTypeDescription(unitOfMeasureType, language));
048        } else {
049            builder.append(uomControl.getBestPluralUnitOfMeasureTypeDescription(unitOfMeasureType, language));
050        }
051    }
052    
053    private StringBuilder formatUnitOfMeasure(UomControl uomControl, Language language, StringBuilder builder, UnitOfMeasureType unitOfMeasureType, long measure) {
054        var unitOfMeasureEquivalents = uomControl.getUnitOfMeasureEquivalentsByToUnitOfMeasureType(unitOfMeasureType);
055        var appended = false;
056        
057        for(var unitOfMeasureEquivalent : unitOfMeasureEquivalents) {
058            long toQuantity = unitOfMeasureEquivalent.getToQuantity();
059            
060            if(measure > toQuantity) {
061                var equivMeasure = measure / toQuantity;
062                var remainMeasure = measure % toQuantity;
063                
064                formatUnitOfMeasure(uomControl, language, builder, unitOfMeasureEquivalent.getFromUnitOfMeasureType(), equivMeasure);
065                
066                if(remainMeasure != 0) {
067                    appendMeasure(uomControl, language, builder, unitOfMeasureType, remainMeasure);
068                }
069                
070                appended = true;
071                break;
072            }
073        }
074        
075        if(!appended && measure != 0) {
076            appendMeasure(uomControl, language, builder, unitOfMeasureType, measure);
077        }
078        
079        return builder;
080    }
081    
082    private UnitOfMeasureType getLowestUnitOfMeasureType(UomControl uomControl, UnitOfMeasureType unitOfMeasureType) {
083        var unitOfMeasureEquivalents = uomControl.getUnitOfMeasureEquivalentsByFromUnitOfMeasureType(unitOfMeasureType);
084        var iter = unitOfMeasureEquivalents.iterator();
085        
086        if(iter.hasNext()) {
087            var unitOfMeasureEquivalent = iter.next();
088            
089            unitOfMeasureType = unitOfMeasureEquivalent.getToUnitOfMeasureType();
090        }
091        
092        return unitOfMeasureType;
093    }
094    
095    // TODO: This should have a cache
096    public UnitOfMeasureType getLowestUnitOfMeasureType(UomControl uomControl, UnitOfMeasureKind unitOfMeasureKind) {
097        var unitOfMeasureTypes = uomControl.getUnitOfMeasureTypesByUnitOfMeasureKind(unitOfMeasureKind);
098        var iter = unitOfMeasureTypes.iterator();
099        UnitOfMeasureType unitOfMeasureType = null;
100        
101        if(iter.hasNext()) {
102            unitOfMeasureType = getLowestUnitOfMeasureType(uomControl, iter.next());
103        }
104        
105        return unitOfMeasureType;
106    }
107    
108    public String formatUnitOfMeasure(UserVisit userVisit, UnitOfMeasureKind unitOfMeasureKind, Long measure) {
109        String result = null;
110        
111        if(measure != null) {
112            var uomControl = Session.getModelController(UomControl.class);
113            var userControl = Session.getModelController(UserControl.class);
114            var language = userControl.getPreferredLanguageFromUserVisit(userVisit);
115            var unitOfMeasureType = getLowestUnitOfMeasureType(uomControl, unitOfMeasureKind);
116            
117            result = formatUnitOfMeasure(uomControl, language, new StringBuilder(), unitOfMeasureType, measure).toString();
118        }
119        
120        return result;
121    }
122    
123}