package org.gnucash.android.model;

import org.gnucash.android.util.TimestampHelper;

import java.math.BigDecimal;
import java.math.MathContext;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.NumberFormat;

/**
 * Model for commodity prices
 */
public class Price extends BaseModel {

    private String mCommodityUID;
    private String mCurrencyUID;
    private Timestamp mDate;
    private String mSource;
    private String mType;
    private long mValueNum;
    private long mValueDenom;

    /**
     * String indicating that the price was provided by the user
     */
    public static final String SOURCE_USER = "user:xfer-dialog";

    public Price(){
        mDate = TimestampHelper.getTimestampFromNow();
    }

    /**
     * Create new instance with the GUIDs of the commodities
     * @param commodityUID GUID of the origin commodity
     * @param currencyUID GUID of the target commodity
     */
    public Price(String commodityUID, String currencyUID){
        this.mCommodityUID = commodityUID;
        this.mCurrencyUID = currencyUID;
        mDate = TimestampHelper.getTimestampFromNow();
    }

    /**
     * Create new instance with the GUIDs of the commodities and the specified exchange rate.
     * @param commodity1UID GUID of the origin commodity
     * @param commodity2UID GUID of the target commodity
     * @param exchangeRate exchange rate between the commodities
     */
    public Price(String commodity1UID, String commodity2UID, BigDecimal exchangeRate) {
        this(commodity1UID, commodity2UID);
        // Store 0.1234 as 1234/10000
        setValueNum(exchangeRate.unscaledValue().longValue());
        setValueDenom(BigDecimal.ONE.scaleByPowerOfTen(exchangeRate.scale()).longValue());
    }

    public String getCommodityUID() {
        return mCommodityUID;
    }

    public void setCommodityUID(String mCommodityUID) {
        this.mCommodityUID = mCommodityUID;
    }

    public String getCurrencyUID() {
        return mCurrencyUID;
    }

    public void setCurrencyUID(String currencyUID) {
        this.mCurrencyUID = currencyUID;
    }

    public Timestamp getDate() {
        return mDate;
    }

    public void setDate(Timestamp date) {
        this.mDate = date;
    }

    public String getSource() {
        return mSource;
    }

    public void setSource(String source) {
        this.mSource = source;
    }

    public String getType() {
        return mType;
    }

    public void setType(String type) {
        this.mType = type;
    }

    public long getValueNum() {
        reduce();
        return mValueNum;
    }

    public void setValueNum(long valueNum) {
        this.mValueNum = valueNum;
    }

    public long getValueDenom() {
        reduce();
        return mValueDenom;
    }

    public void setValueDenom(long valueDenom) {
        this.mValueDenom = valueDenom;
    }

    private void reduce() {
        if (mValueDenom < 0) {
            mValueDenom = -mValueDenom;
            mValueNum = -mValueNum;
        }
        if (mValueDenom != 0 && mValueNum != 0) {
            long num1 = mValueNum;
            if (num1 < 0) {
                num1 = -num1;
            }
            long num2 = mValueDenom;
            long commonDivisor = 1;
            for(;;) {
                long r = num1 % num2;
                if (r == 0) {
                    commonDivisor = num2;
                    break;
                }
                num1 = r;
                r = num2 % num1;
                if (r == 0) {
                    commonDivisor = num1;
                    break;
                }
                num2 = r;
            }
            mValueNum /= commonDivisor;
            mValueDenom /= commonDivisor;
        }
    }

    /**
     * Returns the exchange rate as a string formatted with the default locale.
     *
     * <p>It will have up to 6 decimal places.
     *
     * <p>Example: "0.123456"
     */
    @Override
    public String toString() {
        BigDecimal numerator = new BigDecimal(mValueNum);
        BigDecimal denominator = new BigDecimal(mValueDenom);
        DecimalFormat formatter = (DecimalFormat) NumberFormat.getNumberInstance();
        formatter.setMaximumFractionDigits(6);
        return formatter.format(numerator.divide(denominator, MathContext.DECIMAL32));
    }
}
