package org.realityforge.arez.examples;

import java.util.Objects;
import javax.annotation.Nonnull;
import org.realityforge.arez.ArezContext;
import org.realityforge.arez.annotations.Computed;
import org.realityforge.arez.annotations.Observable;

public final class CalculatedModelExample
{
  public static abstract class PersonModel
  {
    @Observable
    public abstract String getFirstName();

    @Observable
    public abstract void setFirstName( @Nonnull String firstName );

    @Observable
    public abstract String getLastName();

    @Observable
    public abstract void setLastName( @Nonnull String lastName );

    @Computed
    @Nonnull
    public String getFullName()
    {
      return getFirstName() + " " + getLastName();
    }
  }

  public static class PersonModelImpl
    extends PersonModel
  {
    private final org.realityforge.arez.Observable $_firstName;
    private final org.realityforge.arez.Observable $_lastName;
    private final org.realityforge.arez.ComputedValue<String> $_fullName;

    private String _firstName;
    private String _lastName;

    PersonModelImpl( @Nonnull final ArezContext context )
    {
      $_firstName = context.createObservable( "Person.firstName" );
      $_lastName = context.createObservable( "Person.lastName" );
      $_fullName = context.createComputedValue( "Person.fullName", super::getFullName, Objects::equals );
    }

    @Override
    public String getFirstName()
    {
      $_firstName.reportObserved();
      return _firstName;
    }

    @Override
    public void setFirstName( @Nonnull final String firstName )
    {
      if ( !Objects.equals( firstName, _firstName ) )
      {
        $_firstName.reportChanged();
        _firstName = firstName;
      }
    }

    @Override
    public String getLastName()
    {
      $_lastName.reportObserved();
      return _lastName;
    }

    @Override
    public void setLastName( @Nonnull final String lastName )
    {
      if ( !Objects.equals( lastName, _lastName ) )
      {
        $_firstName.reportChanged();
        _lastName = lastName;
      }
    }

    @Nonnull
    @Override
    public String getFullName()
    {
      return $_fullName.get();
    }
  }

  public static void main( final String[] args )
    throws Exception
  {
    final ArezContext context = new ArezContext();

    context.addObserverErrorHandler( ( observer, error, throwable ) -> {
      System.out.println( "Observer error: " + error + "\nobserver: " + observer );
      if ( null != throwable )
      {
        throwable.printStackTrace( System.out );
      }
    } );

    final PersonModel person = new PersonModelImpl( context );

    context.procedure( "Initial setup",
                       true,
                       () -> {
                         person.setFirstName( "Bill" );
                         person.setLastName( "Smith" );
                       } );

    context.autorun( "NamePrinter",
                     false,
                     () -> System.out.println( "First Name: " + person.getFirstName() ),
                     true );
    context.autorun( "Printer",
                     false,
                     () -> System.out.println( "Full Name: " + person.getFullName() ),
                     true );

    context.procedure( "Name update", true, () -> person.setFirstName( "Fred" ) );
  }
}

@@ -227,26 +227,25 @@
 tations.
-Observable
+Container
 ;%0A%0Apubli
@@ -283,16 +283,66 @@
 ample%0A%7B%0A
+  @Container( name = %22Person%22, singleton = true )%0A
   public
@@ -380,32 +380,16 @@
 del%0A  %7B%0A
-    @Observable%0A
     publ
@@ -424,32 +424,16 @@
 ame();%0A%0A
-    @Observable%0A
     publ
@@ -493,32 +493,16 @@
 ame );%0A%0A
-    @Observable%0A
     publ
@@ -540,24 +540,8 @@
 );%0A%0A
-    @Observable%0A
     

Update Annotation usage to more accurately reflect the way we expect it to work