package jetbrains.mps.lang.editor.diagram.runtime.jetpad.property;

/*Generated by MPS */

import jetbrains.jetpad.model.property.BaseReadableProperty;
import jetbrains.jetpad.model.event.Listeners;
import jetbrains.jetpad.model.event.EventHandler;
import jetbrains.jetpad.model.property.PropertyChangeEvent;
import jetbrains.jetpad.model.property.ReadableProperty;
import jetbrains.jetpad.base.Registration;
import jetbrains.jetpad.model.event.ListenerCaller;

public class DependentProperty<ValueT> extends BaseReadableProperty<ValueT> {
  private Listeners<EventHandler<? super PropertyChangeEvent<ValueT>>> myHandlers;
  private ReadableProperty<ValueT> myMainProperty;
  private ReadableProperty<?>[] myDependecies;
  private Registration[] myRegistrations;
  private ValueT myOldValue;

  public DependentProperty(ReadableProperty<ValueT> mainProperty, ReadableProperty<?>... dependencies) {
    myMainProperty = mainProperty;
    myDependecies = new ReadableProperty<?>[dependencies.length + 1];
    myDependecies[0] = mainProperty;
    System.arraycopy(dependencies, 0, myDependecies, 1, dependencies.length);

  }
  public ValueT get() {
    return myMainProperty.get();
  }
  public Registration addHandler(EventHandler<? super PropertyChangeEvent<ValueT>> handler) {
    if (myHandlers == null) {
      myHandlers = new Listeners<EventHandler<? super PropertyChangeEvent<ValueT>>>();
    }
    if (myHandlers.isEmpty()) {
      doAddListeners();
    }
    final Registration reg = myHandlers.add(handler);
    return new Registration() {
      public void remove() {
        reg.remove();
        if (myHandlers.isEmpty()) {
          doRemoveListeners();
        }
      }
    };
  }
  private void doAddListeners() {
    EventHandler<PropertyChangeEvent<?>> handler = new EventHandler<PropertyChangeEvent<?>>() {
      public void onEvent(PropertyChangeEvent<?> event) {
        somethingChange();
      }
    };
    myRegistrations = new Registration[myDependecies.length];
    myOldValue = get();
    for (int i = 0; i < myDependecies.length; i++) {
      myRegistrations[i] = myDependecies[i].addHandler(handler);
    }
  }
  private void doRemoveListeners() {
    for (Registration reg : myRegistrations) {
      reg.remove();
    }
    myRegistrations = null;
  }
  private void somethingChange() {
    ValueT newValue = get();
    ValueT oldValue = myOldValue;
    myOldValue = newValue;
    if (myHandlers != null) {
      final PropertyChangeEvent<ValueT> event = new PropertyChangeEvent<ValueT>(oldValue, newValue);
      myHandlers.fire(new ListenerCaller<EventHandler<? super PropertyChangeEvent<ValueT>>>() {
        public void call(EventHandler<? super PropertyChangeEvent<ValueT>> handler) {
          handler.onEvent(event);
        }
      });
    }
  }
}
