MoneyWiseXAnalysisTaxBasisAccountBucket.java

/*
 * MoneyWise: Finance Application
 * Copyright 2012-2026. Tony Washer
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License.  You may obtain a copy
 * of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets;

import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataList;
import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseAssetType;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicResource;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransAsset;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTaxBasis;
import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
import io.github.tonywasher.joceanus.oceanus.date.OceanusDateRange;
import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * The TaxBasis Account Bucket class.
 */
public final class MoneyWiseXAnalysisTaxBasisAccountBucket
        extends MoneyWiseXAnalysisTaxBasisBaseBucket {
    /**
     * Local Report fields.
     */
    private static final MetisFieldSet<MoneyWiseXAnalysisTaxBasisAccountBucket> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseXAnalysisTaxBasisAccountBucket.class);

    /*
     * Declare Fields.
     */
    static {
        FIELD_DEFS.declareLocalField(MoneyWiseBasicResource.TRANSACTION_ACCOUNT, MoneyWiseXAnalysisTaxBasisAccountBucket::getAccount);
    }

    /**
     * AssetId.
     */
    private final Long theAssetId;

    /**
     * Account.
     */
    private final MoneyWiseTransAsset theAccount;

    /**
     * Constructor.
     *
     * @param pAnalysis the analysis
     * @param pTaxBasis the taxBasis
     * @param pAccount  the account
     */
    MoneyWiseXAnalysisTaxBasisAccountBucket(final MoneyWiseXAnalysisHolder pAnalysis,
                                            final MoneyWiseTaxBasis pTaxBasis,
                                            final MoneyWiseTransAsset pAccount) {
        /* Store the parameters */
        super(pAnalysis, pTaxBasis);
        theAssetId = deriveAssetId(pAccount);
        theAccount = pAccount;
    }

    /**
     * Constructor.
     *
     * @param pAnalysis the analysis
     * @param pBase     the underlying bucket
     * @param pDate     the date for the bucket
     */
    private MoneyWiseXAnalysisTaxBasisAccountBucket(final MoneyWiseXAnalysisHolder pAnalysis,
                                                    final MoneyWiseXAnalysisTaxBasisAccountBucket pBase,
                                                    final OceanusDate pDate) {
        /* Copy details from base */
        super(pAnalysis, pBase, pDate);
        theAssetId = pBase.getBucketId();
        theAccount = pBase.getAccount();
    }

    /**
     * Constructor.
     *
     * @param pAnalysis the analysis
     * @param pBase     the underlying bucket
     * @param pRange    the range for the bucket
     */
    private MoneyWiseXAnalysisTaxBasisAccountBucket(final MoneyWiseXAnalysisHolder pAnalysis,
                                                    final MoneyWiseXAnalysisTaxBasisAccountBucket pBase,
                                                    final OceanusDateRange pRange) {
        /* Copy details from base */
        super(pAnalysis, pBase, pRange);
        theAssetId = pBase.getBucketId();
        theAccount = pBase.getAccount();
    }

    /**
     * derive asset key for an asset.
     *
     * @param pAsset the asset
     * @return the asset key
     */
    private static Long deriveAssetId(final MoneyWiseTransAsset pAsset) {
        /* Calculate the key */
        return MoneyWiseAssetType.createAlternateExternalId(MoneyWiseAssetType.TAXBASISACCOUNT, pAsset.getExternalId());
    }

    @Override
    public MetisFieldSet<MoneyWiseXAnalysisTaxBasisAccountBucket> getDataFieldSet() {
        return FIELD_DEFS;
    }

    @Override
    public Integer getIndexedId() {
        return theAccount.getExternalId().intValue();
    }

    @Override
    public Long getBucketId() {
        return theAssetId;
    }

    /**
     * Obtain simple name.
     *
     * @return the simple name
     */
    public String getSimpleName() {
        return theAccount.getName();
    }

    @Override
    public String getName() {
        return getTaxBasis().getName()
                + ':'
                + getSimpleName();
    }

    /**
     * Obtain account.
     *
     * @return the account
     */
    public MoneyWiseTransAsset getAccount() {
        return theAccount;
    }

    /**
     * TaxBasisAccountBucketList class.
     */
    public static class MoneyWiseXAnalysisTaxBasisAccountBucketList
            implements MetisFieldItem, MetisDataList<MoneyWiseXAnalysisTaxBasisAccountBucket> {
        /**
         * Local Report fields.
         */
        private static final MetisFieldSet<MoneyWiseXAnalysisTaxBasisAccountBucketList> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseXAnalysisTaxBasisAccountBucketList.class);

        /*
         * Declare Fields.
         */
        static {
            FIELD_DEFS.declareLocalField(MoneyWiseXAnalysisBucketResource.ANALYSIS_NAME, MoneyWiseXAnalysisTaxBasisAccountBucketList::getAnalysis);
        }

        /**
         * The analysis.
         */
        private final MoneyWiseXAnalysisHolder theAnalysis;

        /**
         * The list.
         */
        private final List<MoneyWiseXAnalysisTaxBasisAccountBucket> theList;

        /**
         * TaxBasis.
         */
        private final MoneyWiseTaxBasis theTaxBasis;

        /**
         * Bucket map.
         */
        private final Map<Long, MoneyWiseXAnalysisTaxBasisAccountBucket> theMap;

        /**
         * Construct a top-level List.
         *
         * @param pAnalysis the analysis
         * @param pTaxBasis the taxBasis
         */
        protected MoneyWiseXAnalysisTaxBasisAccountBucketList(final MoneyWiseXAnalysisHolder pAnalysis,
                                                              final MoneyWiseTaxBasis pTaxBasis) {
            theAnalysis = pAnalysis;
            theTaxBasis = pTaxBasis;
            theMap = new HashMap<>();
            theList = new ArrayList<>();
        }

        /**
         * Construct a dated List.
         *
         * @param pAnalysis the analysis
         * @param pTaxBasis the taxBasis
         * @param pBase     the base list
         * @param pDate     the Date
         */
        protected MoneyWiseXAnalysisTaxBasisAccountBucketList(final MoneyWiseXAnalysisHolder pAnalysis,
                                                              final MoneyWiseTaxBasis pTaxBasis,
                                                              final MoneyWiseXAnalysisTaxBasisAccountBucketList pBase,
                                                              final OceanusDate pDate) {
            /* Initialise class */
            this(pAnalysis, pTaxBasis);

            /* Loop through the buckets */
            final Iterator<MoneyWiseXAnalysisTaxBasisAccountBucket> myIterator = pBase.iterator();
            while (myIterator.hasNext()) {
                final MoneyWiseXAnalysisTaxBasisAccountBucket myCurr = myIterator.next();

                /* Access the bucket for this date */
                final MoneyWiseXAnalysisTaxBasisAccountBucket myBucket = new MoneyWiseXAnalysisTaxBasisAccountBucket(pAnalysis, myCurr, pDate);

                /* If the bucket is non-idle */
                if (!myBucket.isIdle()) {
                    /* Calculate the delta and add to the list */
                    theList.add(myBucket);
                    theMap.put(myBucket.getBucketId(), myBucket);
                }
            }
        }

        /**
         * Construct a ranged List.
         *
         * @param pAnalysis the analysis
         * @param pTaxBasis the taxBasis
         * @param pBase     the base list
         * @param pRange    the Date Range
         */
        protected MoneyWiseXAnalysisTaxBasisAccountBucketList(final MoneyWiseXAnalysisHolder pAnalysis,
                                                              final MoneyWiseTaxBasis pTaxBasis,
                                                              final MoneyWiseXAnalysisTaxBasisAccountBucketList pBase,
                                                              final OceanusDateRange pRange) {
            /* Initialise class */
            this(pAnalysis, pTaxBasis);

            /* Loop through the buckets */
            final Iterator<MoneyWiseXAnalysisTaxBasisAccountBucket> myIterator = pBase.iterator();
            while (myIterator.hasNext()) {
                final MoneyWiseXAnalysisTaxBasisAccountBucket myCurr = myIterator.next();

                /* Access the bucket for this range */
                final MoneyWiseXAnalysisTaxBasisAccountBucket myBucket = new MoneyWiseXAnalysisTaxBasisAccountBucket(pAnalysis, myCurr, pRange);

                /* If the bucket is non-idle */
                if (!myBucket.isIdle()) {
                    /* Adjust to the base */
                    myBucket.adjustToBase();

                    /* Add to list and to map */
                    theList.add(myBucket);
                    theMap.put(myBucket.getBucketId(), myBucket);
                }
            }
        }

        @Override
        public MetisFieldSet<MoneyWiseXAnalysisTaxBasisAccountBucketList> getDataFieldSet() {
            return FIELD_DEFS;
        }

        @Override
        public List<MoneyWiseXAnalysisTaxBasisAccountBucket> getUnderlyingList() {
            return theList;
        }

        @Override
        public String formatObject(final OceanusDataFormatter pFormatter) {
            return getDataFieldSet().getName();
        }

        /**
         * Obtain the analysis.
         *
         * @return the analysis
         */
        protected MoneyWiseXAnalysisHolder getAnalysis() {
            return theAnalysis;
        }

        /**
         * Adjust value.
         *
         * @param pAccount the relevant account
         * @param pValue   the value
         * @param pAdjust  adjustment control
         * @return the adjusted taxBasisAccountBucket (or null)
         */
        MoneyWiseXAnalysisTaxBasisBaseBucket adjustValue(final MoneyWiseTransAsset pAccount,
                                                         final OceanusMoney pValue,
                                                         final MoneyWiseXTaxBasisAdjust pAdjust) {
            /* Access the relevant account bucket */
            final MoneyWiseXAnalysisTaxBasisAccountBucket myBucket = getBucket(pAccount);

            /* register deltas */
            return myBucket.adjustValue(pAccount, pValue, pAdjust);
        }

        /**
         * Obtain the TaxBasisAccountBucket for a given account.
         *
         * @param pAccount the account
         * @return the bucket
         */
        private MoneyWiseXAnalysisTaxBasisAccountBucket getBucket(final MoneyWiseTransAsset pAccount) {
            /* Locate the bucket in the list */
            final Long myKey = deriveAssetId(pAccount);
            return theMap.computeIfAbsent(myKey, m -> {
                /* Create the new bucket */
                final MoneyWiseXAnalysisTaxBasisAccountBucket myNew = new MoneyWiseXAnalysisTaxBasisAccountBucket(theAnalysis, theTaxBasis, pAccount);

                /* Add to the list */
                theList.add(myNew);
                return myNew;
            });
        }

        /**
         * SortBuckets.
         */
        protected void sortBuckets() {
            theList.sort(Comparator.comparing(MoneyWiseXAnalysisTaxBasisAccountBucket::getBucketId));
        }

        /**
         * Find the TaxBasisAccountBucket for a given account.
         *
         * @param pAccount the account
         * @return the bucket (or null)
         */
        protected MoneyWiseXAnalysisTaxBasisAccountBucket findBucket(final MoneyWiseTransAsset pAccount) {
            /* Locate the bucket in the list */
            final Long myKey = deriveAssetId(pAccount);
            return theMap.get(myKey);
        }
    }
}