package org.realityforge.arez.examples;

import java.util.Timer;
import java.util.TimerTask;
import javax.annotation.Generated;
import javax.annotation.Nonnull;
import org.jetbrains.annotations.TestOnly;
import org.realityforge.arez.ArezContext;
import org.realityforge.arez.Observer;
import org.realityforge.arez.annotations.Action;
import org.realityforge.arez.annotations.Container;
import org.realityforge.arez.annotations.Observable;

public final class TimerExample
{
  @Container( name = "Time", singleton = true )
  public static abstract class TimeModel
  {
    private long _time;

    TimeModel( final long time )
    {
      _time = time;
    }

    @Observable
    public long getTime()
    {
      return _time;
    }

    public void setTime( final long time )
    {
      _time = time;
    }

    @Action
    public void updateTime()
    {
      setTime( System.currentTimeMillis() );
    }
  }

  @Generated( "org.realityforge.arez.processor.ArezProcessor" )
  public static final class Arez_TimeModel
    extends TimeModel
  {
    private final ArezContext $arez$_context;
    private final org.realityforge.arez.Observable $arez$_time;

    public Arez_TimeModel( @Nonnull final ArezContext context, final long time )
    {
      super( time );
      $arez$_context = context;
      $arez$_time = context.createObservable( "Time.time" );
    }

    @Override
    public long getTime()
    {
      $arez$_time.reportObserved();
      return super.getTime();
    }

    @Override
    public void setTime( final long time )
    {
      if ( super.getTime() != time )
      {
        $arez$_time.reportChanged();
        super.setTime( time );
      }
    }

    @Override
    public void updateTime()
    {
      $arez$_context.safeProcedure( "Time.updateTime", true, () -> super.updateTime() );
    }

    @TestOnly
    @Nonnull
    public org.realityforge.arez.Observable getTimeObservable()
    {
      return $arez$_time;
    }
  }

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

    final TimeModel timeModel = new Arez_TimeModel( context, 0 );

    timeModel.updateTime();

    final Observer timePrinter =
      context.autorun( "TimePrinter",
                       false,
                       () -> System.out.println( "Current time: " + timeModel.getTime() ),
                       true );

    final Timer timer = new Timer();
    timer.schedule( new TimerTask()
    {
      @Override
      public void run()
      {
        timeModel.updateTime();
      }
    }, 0, 100 );

    timer.schedule( new TimerTask()
    {
      @Override
      public void run()
      {
        System.out.println( ( (Arez_TimeModel) timeModel ).getTimeObservable() );
        System.out.println( timePrinter + "::Active=" + timePrinter.isActive() );
      }
    }, 0, 1000 );
    Thread.sleep( 10 * 1000 );
    System.exit( 0 );
  }
}

@@ -467,16 +467,166 @@
 ample%0A%7B%0A
+  public interface TimeModelExtension%0A  %7B%0A    TimeModel self();%0A%0A    @Action%0A    default void resetTime()%0A    %7B%0A      self().setTime( 0 );%0A    %7D%0A  %7D%0A%0A
   @Conta
@@ -685,21 +685,37 @@
 tic 
-abstract clas
+class TimeModel%0A    implement
 s Ti
@@ -713,32 +713,41 @@
 ements TimeModel
+Extension
 %0A  %7B%0A    private
@@ -822,24 +822,98 @@
 ime;%0A    %7D%0A%0A
+    @Override%0A    public TimeModel self()%0A    %7B%0A      return this;%0A    %7D%0A%0A
     @Observa
@@ -2057,24 +2057,167 @@
 ) );%0A    %7D%0A%0A
+    @Override%0A    public void resetTime()%0A    %7B%0A      $arez$_context.safeProcedure( %22Time.updateTime%22, true, () -%3E super.resetTime() );%0A    %7D%0A%0A
     @TestOnl
@@ -3223,32 +3223,32 @@
 ve() );%0A      %7D%0A
-
     %7D, 0, 1000 )
@@ -3244,24 +3244,171 @@
 , 0, 1000 );
+%0A%0A    timer.schedule( new TimerTask()%0A    %7B%0A      @Override%0A      public void run()%0A      %7B%0A        timeModel.resetTime();%0A      %7D%0A    %7D, 0, 500 );
 %0A    Thread.

Verify that default methods can be wrapped as @Action methods