/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.beam.runners.direct;

import org.apache.beam.runners.core.BaseExecutionContext;
import org.apache.beam.runners.core.BaseStepContext;
import org.apache.beam.runners.core.ExecutionContext;
import org.apache.beam.runners.core.TimerInternals;
import org.apache.beam.runners.direct.DirectExecutionContext.DirectStepContext;
import org.apache.beam.runners.direct.WatermarkManager.TimerUpdate;
import org.apache.beam.runners.direct.WatermarkManager.TransformWatermarks;

/**
 * Execution Context for the {@link DirectRunner}.
 *
 * <p>This implementation is not thread safe. A new {@link DirectExecutionContext} must be created
 * for each thread that requires it.
 */
class DirectExecutionContext
    extends BaseExecutionContext<DirectStepContext> {
  private final Clock clock;
  private final StructuralKey<?> key;
  private final CopyOnAccessInMemoryStateInternals existingState;
  private final TransformWatermarks watermarks;

  public DirectExecutionContext(
      Clock clock,
      StructuralKey<?> key,
      CopyOnAccessInMemoryStateInternals existingState,
      TransformWatermarks watermarks) {
    this.clock = clock;
    this.key = key;
    this.existingState = existingState;
    this.watermarks = watermarks;
  }

  @Override
  protected DirectStepContext createStepContext(String stepName, String transformName) {
    return new DirectStepContext(this, stepName, transformName);
  }

  /**
   * Step Context for the {@link DirectRunner}.
   */
  public class DirectStepContext
      extends BaseStepContext {
    private CopyOnAccessInMemoryStateInternals<?> stateInternals;
    private DirectTimerInternals timerInternals;

    public DirectStepContext(
        ExecutionContext executionContext, String stepName, String transformName) {
      super(stepName, transformName);
    }

    @Override
    public CopyOnAccessInMemoryStateInternals<?> stateInternals() {
      if (stateInternals == null) {
        stateInternals = CopyOnAccessInMemoryStateInternals.withUnderlying(key, existingState);
      }
      return stateInternals;
    }

    @Override
    public DirectTimerInternals timerInternals() {
      if (timerInternals == null) {
        timerInternals =
            DirectTimerInternals.create(clock, watermarks, TimerUpdate.builder(key));
      }
      return timerInternals;
    }

    /**
     * Commits the state of this step, and returns the committed state. If the step has not
     * accessed any state, return null.
     */
    public CopyOnAccessInMemoryStateInternals commitState() {
      if (stateInternals != null) {
        return stateInternals.commit();
      }
      return null;
    }

    /**
     * Gets the timer update of the {@link TimerInternals} of this {@link DirectStepContext},
     * which is empty if the {@link TimerInternals} were never accessed.
     */
    public TimerUpdate getTimerUpdate() {
      if (timerInternals == null) {
        return TimerUpdate.empty();
      }
      return timerInternals.getTimerUpdate();
    }
  }
}

@@ -840,16 +840,44 @@
 irect;%0A%0A
+import java.io.IOException;%0A
 import o
@@ -930,61 +930,8 @@
 xt;%0A
-import org.apache.beam.runners.core.BaseStepContext;%0A
 impo
@@ -972,32 +972,81 @@
 ecutionContext;%0A
+import org.apache.beam.runners.core.StepContext;%0A
 import org.apach
@@ -1304,16 +1304,211 @@
 ermarks;
+%0Aimport org.apache.beam.sdk.coders.Coder;%0Aimport org.apache.beam.sdk.transforms.windowing.BoundedWindow;%0Aimport org.apache.beam.sdk.util.WindowedValue;%0Aimport org.apache.beam.sdk.values.TupleTag;
 %0A%0A/**%0A *
@@ -2530,27 +2530,20 @@
 text
-%0A      extend
+ implement
 s 
-Base
 Step
@@ -2666,16 +2666,91 @@
 ternals;
+%0A    private final String stepName;%0A    private final String transformName;
 %0A%0A    pu
@@ -2867,38 +2867,74 @@
     
-super(stepName, transformName)
+this.stepName = stepName;%0A      this.transformName = transformName
 ;%0A  
@@ -3738,32 +3738,32 @@
 mmit();%0A      %7D%0A
-
       return nul
@@ -3764,32 +3764,529 @@
 rn null;%0A    %7D%0A%0A
+    @Override%0A    public String getStepName() %7B%0A      return stepName;%0A    %7D%0A%0A    @Override%0A    public String getTransformName() %7B%0A      return transformName;%0A    %7D%0A%0A    @Override%0A    public %3CT, W extends BoundedWindow%3E void writePCollectionViewData(%0A        TupleTag%3C?%3E tag,%0A        Iterable%3CWindowedValue%3CT%3E%3E data, Coder%3CIterable%3CWindowedValue%3CT%3E%3E%3E dataCoder,%0A        W window, Coder%3CW%3E windowCoder) throws IOException %7B%0A      throw new UnsupportedOperationException(%22Not implemented.%22);%0A    %7D%0A%0A
     /**%0A     * G

Implement StepContext directly in the DirectRunner