// Copyright (C) 2010 The Android Open Source Project
//
// Licensed 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 com.google.gerrit.sshd.commands;

import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE;

import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.common.ChangeListener;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.events.ChangeEvent;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.git.WorkQueue.CancelableRunnable;
import com.google.gerrit.sshd.BaseCommand;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.StreamCommandExecutor;
import com.google.gson.Gson;
import com.google.inject.Inject;

import org.apache.sshd.server.Environment;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;

@RequiresCapability(GlobalCapability.STREAM_EVENTS)
@CommandMetaData(name = "stream-events", description = "Monitor events occurring in real time",
  runsAt = MASTER_OR_SLAVE)
final class StreamEvents extends BaseCommand {
  /** Maximum number of events that may be queued up for each connection. */
  private static final int MAX_EVENTS = 128;

  /** Number of events to write before yielding off the thread. */
  private static final int BATCH_SIZE = 32;

  @Inject
  private IdentifiedUser currentUser;

  @Inject
  private ChangeHooks hooks;

  @Inject
  @StreamCommandExecutor
  private WorkQueue.Executor pool;

  /** Queue of events to stream to the connected user. */
  private final LinkedBlockingQueue<ChangeEvent> queue =
      new LinkedBlockingQueue<>(MAX_EVENTS);

  private final Gson gson = new Gson();

  /** Special event to notify clients they missed other events. */
  private final Object droppedOutputEvent = new Object() {
    @SuppressWarnings("unused")
    final String type = "dropped-output";
  };

  private final ChangeListener listener = new ChangeListener() {
    @Override
    public void onChangeEvent(final ChangeEvent event) {
      offer(event);
    }
  };

  private final CancelableRunnable writer = new CancelableRunnable() {
    @Override
    public void run() {
      writeEvents();
    }

    @Override
    public void cancel() {
      onExit(0);
    }
  };

  /** True if {@link #droppedOutputEvent} needs to be sent. */
  private volatile boolean dropped;

  /** Lock to protect {@link #queue}, {@link #task}, {@link #done}. */
  private final Object taskLock = new Object();

  /** True if no more messages should be sent to the output. */
  private boolean done;

  /**
   * Currently scheduled task to spin out {@link #queue}.
   * <p>
   * This field is usually {@code null}, unless there is at least one object
   * present inside of {@link #queue} ready for delivery. Tasks are only started
   * when there are events to be sent.
   */
  private Future<?> task;

  private PrintWriter stdout;

  @Override
  public void start(final Environment env) throws IOException {
    try {
      parseCommandLine();
    } catch (UnloggedFailure e) {
      String msg = e.getMessage();
      if (!msg.endsWith("\n")) {
        msg += "\n";
      }
      err.write(msg.getBytes("UTF-8"));
      err.flush();
      onExit(1);
      return;
    }

    stdout = toPrintWriter(out);
    hooks.addChangeListener(listener, currentUser);
  }

  @Override
  protected void onExit(final int rc) {
    hooks.removeChangeListener(listener);

    synchronized (taskLock) {
      done = true;
    }

    super.onExit(rc);
  }

  @Override
  public void destroy() {
    hooks.removeChangeListener(listener);

    final boolean exit;
    synchronized (taskLock) {
      if (task != null) {
        task.cancel(true);
        exit = false; // onExit will be invoked by the task cancellation.
      } else {
        exit = !done;
      }
      done = true;
    }
    if (exit) {
      onExit(0);
    }
  }

  private void offer(final ChangeEvent event) {
    synchronized (taskLock) {
      if (!queue.offer(event)) {
        dropped = true;
      }

      if (task == null && !done) {
        task = pool.submit(writer);
      }
    }
  }

  private ChangeEvent poll() {
    synchronized (taskLock) {
      ChangeEvent event = queue.poll();
      if (event == null) {
        task = null;
      }
      return event;
    }
  }

  private void writeEvents() {
    int processed = 0;

    while (processed < BATCH_SIZE) {
      if (Thread.interrupted() || stdout.checkError()) {
        // The other side either requested a shutdown by calling our
        // destroy() above, or it closed the stream and is no longer
        // accepting output. Either way terminate this instance.
        //
        hooks.removeChangeListener(listener);
        flush();
        onExit(0);
        return;
      }

      if (dropped) {
        write(droppedOutputEvent);
        dropped = false;
      }

      final ChangeEvent event = poll();
      if (event == null) {
        break;
      }

      write(event);
      processed++;
    }

    flush();

    if (BATCH_SIZE <= processed) {
      // We processed the limit, but more might remain in the queue.
      // Schedule the write task again so we will come back here and
      // can process more events.
      //
      synchronized (taskLock) {
        task = pool.submit(writer);
      }
    }
  }

  private void write(final Object message) {
    final String msg = gson.toJson(message) + "\n";
    synchronized (stdout) {
      stdout.print(msg);
    }
  }

  private void flush() {
    synchronized (stdout) {
      stdout.flush();
    }
  }
}
