content: package im.actor.runtime.mvvm;
  
  import java.util.HashSet;
  
  import im.actor.runtime.annotations.MainThread;
  
  public class LockableValue<T> extends Value<T> {
  
      private ValueChangedListener<T> listener = new ValueChangedListener<T>() {
          @Override
          public void onChanged(T val, Value<T> valueModel) {
              LockableValue.this.originalValue = val;
  
              if (!isLockEnabled) {
                  notifyInMainThread(LockableValue.this.originalValue);
              }
          }
      };
      private Value<T> baseValue;
  
      private T originalValue;
      private T modifiedValue;
  
      private boolean isLockEnabled = false;
      private int NEXT_LOCK_ID = 0;
      private HashSet<Integer> activeLocks = new HashSet<Integer>();
  
      public LockableValue(String name, Value<T> baseValue) {
          super(name);
          this.baseValue = baseValue;
          this.originalValue = baseValue.get();
  
          baseValue.subscribe(listener);
      }
  
      @MainThread
      public int createLock() {
          // Check lock enable
          if (activeLocks.size() == 0) {
              modifiedValue = originalValue;
              isLockEnabled = true;
          }
  
          // Creating lock id
          int lockId = NEXT_LOCK_ID++;
          activeLocks.add(lockId);
          return lockId;
      }
  
      /**
       * Can be executed only between create/release lock calls
       */
      @MainThread
      public void change(T obj) {
          if (!isLockEnabled) {
              throw new RuntimeException("changing of values only cen be performed in locked state");
          }
  
          modifiedValue = obj;
          notifyInMainThread(modifiedValue);
      }
  
      @MainThread
      public void releaseLock(int id) {
          // Releasing lock
          activeLocks.remove(id);
  
          // Check lock disable
          if (activeLocks.size() == 0) {
              modifiedValue = null;
              isLockEnabled = false;
              notifyInMainThread(originalValue);
          }
      }
  
      @Override
      public T get() {
          if (isLockEnabled) {
              return modifiedValue;
          } else {
              return originalValue;
          }
      }
  
      protected T getModifiedValue() {
          return modifiedValue;
      }
  
      public void destroy() {
          baseValue.unsubscribe(listener);
      }
  }
  