/*
 * Copyright 2008 Google Inc.
 * 
 * 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.gwt.junit;

import com.google.gwt.dev.util.collect.HashSet;
import com.google.gwt.junit.client.TimeoutException;
import com.google.gwt.junit.client.impl.JUnitResult;
import com.google.gwt.junit.client.impl.JUnitHost.TestBlock;
import com.google.gwt.junit.client.impl.JUnitHost.TestInfo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * A message queue to pass data between {@link JUnitShell} and
 * {@link com.google.gwt.junit.server.JUnitHostImpl} in a thread-safe manner.
 * 
 * <p>
 * The public methods are called by the servlet to find out what test to execute
 * next, and to report the results of the last test to run.
 * </p>
 * 
 * <p>
 * The protected methods are called by the shell to fetch test results and drive
 * the next test the client should run.
 * </p>
 */
public class JUnitMessageQueue {

  /**
   * Holds the state of an individual client.
   */
  public static class ClientStatus {
    public final String clientId;
    public boolean isNew = true;
    public int blockIndex = 0;

    public ClientStatus(String clientId) {
      this.clientId = clientId;
    }
  }

  /**
   * Records results for each client; must lock before accessing.
   */
  private final Map<String, ClientStatus> clientStatuses = new HashMap<String, ClientStatus>();

  /**
   * A set of the GWT user agents (eg. ie6, gecko) that have connected. 
   */
  private final Set<String> userAgents = new HashSet<String>();

  /**
   * The lock used to synchronize access to clientStatuses.
   */
  private final Object clientStatusesLock = new Object();

  /**
   * The number of TestCase clients executing in parallel.
   */
  private final int numClients;

  /**
   * Maps the TestInfo to the results from each clientId. If JUnitResult is
   * null, it means that the client requested the test but did not report the
   * results yet.
   */
  private final Map<TestInfo, Map<String, JUnitResult>> testResults = new HashMap<TestInfo, Map<String, JUnitResult>>();

  /**
   * The list of test blocks to run.
   */
  private final List<TestInfo[]> testBlocks = new ArrayList<TestInfo[]>();

  /**
   * Set to true when the last test block has been added. This is used to tell
   * clients that all tests are complete.
   */
  private boolean isLastTestBlockAvailable;

  /**
   * Only instantiable within this package.
   * 
   * @param numClients The number of parallel clients being served by this
   *          queue.
   */
  JUnitMessageQueue(int numClients) {
    synchronized (clientStatusesLock) {
      this.numClients = numClients;
    }
  }

  /**
   * Called by the servlet to query for for the next block to test.
   * 
   * @param clientId the ID of the client
   * @param userAgent the user agent property of the client
   * @param blockIndex the index of the test block to get
   * @param timeout how long to wait for an answer
   * @return the next test to run, or <code>null</code> if <code>timeout</code>
   *         is exceeded or the next test does not match
   *         <code>testClassName</code>
   */
  public TestBlock getTestBlock(String clientId, String userAgent,
      int blockIndex, long timeout) throws TimeoutException {
    synchronized (clientStatusesLock) {
      userAgents.add(userAgent);
      ClientStatus clientStatus = ensureClientStatus(clientId);
      clientStatus.blockIndex = blockIndex;

      // The client has finished all of the tests.
      if (isLastTestBlockAvailable && blockIndex >= testBlocks.size()) {
        return null;
      }

      long startTime = System.currentTimeMillis();
      long stopTime = startTime + timeout;
      while (blockIndex >= testBlocks.size()) {
        long timeToWait = stopTime - System.currentTimeMillis();
        if (timeToWait < 1) {
          double elapsed = (System.currentTimeMillis() - startTime) / 1000.0;
          throw new TimeoutException("The servlet did not respond to the "
              + "next query to test within " + timeout + "ms.\n"
              + " Client id: " + clientId + "\n" + " Actual time elapsed: "
              + elapsed + " seconds.\n");
        }
        try {
          clientStatusesLock.wait(timeToWait);
        } catch (InterruptedException e) {
          /*
           * Should never happen; but if it does, just send a null back to the
           * client, which will cause it to stop running tests.
           */
          System.err.println("Unexpected thread interruption");
          e.printStackTrace();
          return null;
        }
      }

      // Record that this client has retrieved the current tests.
      TestInfo[] tests = testBlocks.get(blockIndex);
      for (TestInfo testInfo : tests) {
        ensureResults(testInfo).put(clientId, null);
      }
      return new TestBlock(tests, blockIndex);
    }
  }

  public void reportFatalLaunch(String clientId, String userAgent,
      JUnitResult result) {
    // Fatal launch error, cause this client to fail the whole block.
    ClientStatus clientStatus = ensureClientStatus(clientId);
    Map<TestInfo, JUnitResult> results = new HashMap<TestInfo, JUnitResult>();
    for (TestInfo testInfo : testBlocks.get(clientStatus.blockIndex)) {
      results.put(testInfo, result);
    }
    reportResults(clientId, userAgent, results);
  }

  /**
   * Called by the servlet to report the results of the last test to run.
   * 
   * @param clientId the ID of the client
   * @param userAgent the user agent property of the client
   * @param results the result of running the test block
   */
  public void reportResults(String clientId, String userAgent,
      Map<TestInfo, JUnitResult> results) {
    synchronized (clientStatusesLock) {
      if (results == null) {
        throw new IllegalArgumentException("results cannot be null");
      }
      userAgents.add(userAgent);
      ClientStatus clientStatus = ensureClientStatus(clientId);

      // Cache the test results.
      for (Map.Entry<TestInfo, JUnitResult> entry : results.entrySet()) {
        TestInfo testInfo = entry.getKey();
        ensureResults(testInfo).put(clientId, entry.getValue());
      }

      clientStatusesLock.notifyAll();
    }
  }

  /**
   * Called by the shell to add test blocks to test.
   * 
   * @param isLastBlock true if this is the last test block that will be added
   */
  void addTestBlocks(List<TestInfo[]> newTestBlocks, boolean isLastBlock) {
    synchronized (clientStatusesLock) {
      if (isLastTestBlockAvailable) {
        throw new IllegalArgumentException(
            "Cannot add test blocks after the last block is added");
      }
      for (TestInfo[] testBlock : newTestBlocks) {
        if (testBlock.length == 0) {
          throw new IllegalArgumentException("TestBlocks cannot be empty");
        }
      }
      testBlocks.addAll(newTestBlocks);
      if (isLastBlock) {
        isLastTestBlockAvailable = true;
      }
      clientStatusesLock.notifyAll();
    }
  }

  /**
   * Returns any new clients that have contacted the server since the last call.
   * The same client will never be returned from this method twice.
   */
  String[] getNewClients() {
    synchronized (clientStatusesLock) {
      List<String> results = new ArrayList<String>();
      for (ClientStatus clientStatus : clientStatuses.values()) {
        if (clientStatus.isNew) {
          results.add(clientStatus.clientId);
          // Record that this client is no longer new.
          clientStatus.isNew = false;
        }
      }
      clientStatusesLock.notifyAll();
      return results.toArray(new String[results.size()]);
    }
  }

  /**
   * Returns how many clients have requested the currently-running test.
   * 
   * @param testInfo the {@link TestInfo} that the clients retrieved
   */
  int getNumClientsRetrievedTest(TestInfo testInfo) {
    synchronized (clientStatusesLock) {
      int count = 0;
      Map<String, JUnitResult> results = testResults.get(testInfo);
      if (results != null) {
        count = results.size();
      }
      return count;
    }
  }

  /**
   * Returns how many clients have connected.
   */
  int getNumConnectedClients() {
    synchronized (clientStatusesLock) {
      return clientStatuses.size();
    }
  }

  /**
   * Fetches the results of a completed test.
   * 
   * @param testInfo the {@link TestInfo} to check for results
   * @return A map of results from all clients.
   */
  Map<String, JUnitResult> getResults(TestInfo testInfo) {
    synchronized (clientStatusesLock) {
      return testResults.get(testInfo);
    }
  }

  /**
   * Visible for testing.
   * 
   * @return the test blocks
   */
  List<TestInfo[]> getTestBlocks() {
    return testBlocks;
  }

  /**
   * Returns a pretty printed list of clients that have not retrieved the
   * current test. Used for error reporting.
   * 
   * @param testInfo the {@link TestInfo} we are waiting for
   * @return a string containing the list of clients that have not retrieved the
   *         current test.
   */
  String getUnretrievedClients(TestInfo testInfo) {
    synchronized (clientStatusesLock) {
      Map<String, JUnitResult> results = testResults.get(testInfo);
      StringBuilder buf = new StringBuilder();
      int lineCount = 0;
      for (ClientStatus clientStatus : clientStatuses.values()) {
        if (lineCount > 0) {
          buf.append('\n');
        }

        if (results == null || !results.containsKey(clientStatus.clientId)) {
          buf.append(" - NO RESPONSE: ");
        } else {
          buf.append(" - (ok): ");
        }
        buf.append(clientStatus.clientId);
        ++lineCount;
      }
      int difference = numClients - getNumClientsRetrievedTest(testInfo);
      if (difference > 0) {
        if (lineCount > 0) {
          buf.append('\n');
        }
        buf.append(" - "
            + difference
            + " client(s) haven't responded back to JUnitShell since the start of the test.");
      }
      return buf.toString();
    }
  }

  /**
   * Returns a list of all user agents that have connected.
   */
  String[] getUserAgents() {
    synchronized (clientStatusesLock) {
      return userAgents.toArray(new String[userAgents.size()]);
    }
  }

  /**
   * Returns a human-formatted message identifying what clients have connected
   * but have not yet reported results for this test. It is used in a timeout
   * condition, to identify what we're still waiting on.
   * 
   * @param testInfo the {@link TestInfo} that the clients are working on
   * @return human readable message
   */
  String getWorkingClients(TestInfo testInfo) {
    synchronized (clientStatusesLock) {
      // Print a list of clients that have connected but not returned results.
      int itemCount = 0;
      StringBuilder buf = new StringBuilder();
      Map<String, JUnitResult> results = testResults.get(testInfo);
      if (results != null) {
        for (Map.Entry<String, JUnitResult> entry : results.entrySet()) {
          if (entry.getValue() == null) {
            buf.append(entry.getKey());
            buf.append("\n");
            itemCount++;
          }
        }
      }

      // Print the number of other clients.
      int difference = numClients - itemCount;
      if (difference > 0) {
        if (itemCount > 0) {
          buf.append('\n');
        }
        buf.append(difference
            + " other client(s) haven't responded back to JUnitShell since the start of the test.");
      }
      return buf.toString();
    }
  }

  /**
   * Called by the shell to see if the currently-running test has completed.
   * 
   * @param testInfo the {@link TestInfo} to check for results
   * @return If the test has completed, <code>true</code>, otherwise
   *         <code>false</code>.
   */
  boolean hasResults(TestInfo testInfo) {
    synchronized (clientStatusesLock) {
      Map<String, JUnitResult> results = testResults.get(testInfo);
      if (results == null || results.size() < numClients) {
        return false;
      }
      for (JUnitResult result : results.values()) {
        if (result == null) {
          return false;
        }
      }
      return true;
    }
  }

  void waitForResults(int millis) {
    synchronized (clientStatusesLock) {
      try {
        clientStatusesLock.wait(millis);
      } catch (InterruptedException e) {
      }
    }
  }

  /**
   * Ensure that a {@link ClientStatus} for the clientId exists. 
   * 
   * @param clientId the id of the client
   * @return the {@link ClientStatus} for the client
   */
  private ClientStatus ensureClientStatus(String clientId) {
    ClientStatus clientStatus = clientStatuses.get(clientId);
    if (clientStatus == null) {
      clientStatus = new ClientStatus(clientId);
      clientStatuses.put(clientId, clientStatus);
    }
    return clientStatus;
  }
  
  /**
   * Get the map of test results from all clients for a given {@link TestInfo},
   * creating it if necessary.
   * 
   * @param testInfo the {@link TestInfo}
   * @return the map of all results
   */
  private Map<String, JUnitResult> ensureResults(TestInfo testInfo) {
    Map<String, JUnitResult> results = testResults.get(testInfo);
    if (results == null) {
      results = new HashMap<String, JUnitResult>();
      testResults.put(testInfo, results);
    }
    return results;
  }
}
