package it.integry.integrywmsnative.core.di;

import androidx.annotation.NonNull;
import androidx.databinding.Bindable;
import androidx.databinding.Observable;
import androidx.databinding.PropertyChangeRegistry;

import java.math.BigDecimal;

import it.integry.integrywmsnative.core.expansion.RunnableArgs;

public class BindableBigDecimal  implements Observable {

    BigDecimal mValue;

    private transient PropertyChangeRegistry mCallbacks;

    public BindableBigDecimal() {
    }

    public BindableBigDecimal(BigDecimal startValue) {
        this.mValue = startValue;
    }


    @Override
    public void addOnPropertyChangedCallback(@NonNull OnPropertyChangedCallback callback) {
        synchronized (this) {
            if (mCallbacks == null) {
                mCallbacks = new PropertyChangeRegistry();
            }
        }
        mCallbacks.add(callback);
    }

    public void addOnPropertyChangedCallback(@NonNull Runnable callback) {
        synchronized (this) {
            if (mCallbacks == null) {
                mCallbacks = new PropertyChangeRegistry();
            }
        }
        mCallbacks.add(new OnPropertyChangedCallback() {
            @Override
            public void onPropertyChanged(Observable sender, int propertyId) {
                callback.run();
            }
        });
    }

    @Override
    public void removeOnPropertyChangedCallback(@NonNull OnPropertyChangedCallback callback) {
        synchronized (this) {
            if (mCallbacks == null) {
                return;
            }
        }
        mCallbacks.remove(callback);
    }

    public void resetOnPropertyChangedCallback() {
        synchronized (this) {
            if (mCallbacks == null) {
                return;
            }
        }
        mCallbacks.clear();
        mCallbacks = null;
    }

    /**
     * Notifies listeners that all properties of this instance have changed.
     */
    public void notifyChange() {
        synchronized (this) {
            if (mCallbacks == null) {
                return;
            }
        }
        mCallbacks.notifyCallbacks(this, 0, null);
    }

    /**
     * Notifies listeners that a specific property has changed. The getter for the property
     * that changes should be marked with {@link Bindable} to generate a field in
     * <code>BR</code> to be used as <code>fieldId</code>.
     *
     * @param fieldId The generated BR id for the Bindable field.
     */
    public void notifyPropertyChanged(int fieldId) {
        synchronized (this) {
            if (mCallbacks == null) {
                return;
            }
        }
        mCallbacks.notifyCallbacks(this, fieldId, null);
    }

    public BigDecimal get() {
        return mValue;
    }

    public void set(BigDecimal value) {
        this.set(value, false);
    }

    public void set(BigDecimal value, boolean forceRefresh) {
        if ((mValue == null)  || !mValue.equals(value) || forceRefresh) {
            this.mValue = value;
            notifyChange();
        }
    }

    public static void registerListener(BindableBigDecimal bindableBigDecimal, RunnableArgs<BigDecimal> onValueChanged) {
        bindableBigDecimal.addOnPropertyChangedCallback(new OnPropertyChangedCallback() {
            @Override
            public void onPropertyChanged(Observable sender, int propertyId) {
                if(onValueChanged != null) onValueChanged.run(bindableBigDecimal.get());
            }
        });
    }

    public static void resetListeners(BindableBigDecimal bindableBigDecimal){
        BigDecimal oldValue = bindableBigDecimal.get();
        bindableBigDecimal = new BindableBigDecimal();
        bindableBigDecimal.set(oldValue);
    }
}
