/*
 * Copyright 2017 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.
 */

/*
 * Example usage
 *  $ vts_hal_replayer /data/local/tmp/hal-trace/nfc/V1_0/nfc.vts.trace
 *  $ vts_hal_replayer --spec_dir_path /data/local/tmp/spec
 *    --hal_service_name default
 *    /data/local/tmp/hal-trace/nfc/V1_0/nfc.vts.trace
 */

#include <getopt.h>
#include <iostream>
#include <string>

#include <android-base/logging.h>

#include "VtsHidlHalReplayer.h"
#include "driver_manager/VtsHalDriverManager.h"

using namespace std;

static constexpr const char* kDefaultSpecDirPath = "/data/local/tmp/spec/";
static constexpr const char* kPassedMarker = "[  PASSED  ]";
static const int kDefaultEpochCount = 100;

static void AddHalServiceInstance(const string& instance,
                                  map<string, string>* halServiceInstances) {
  if (halServiceInstances == nullptr) {
    cerr << __func__ << ": halServiceInstances should not be null " << endl;
    return;
  }
  // hal_service_instance follows the format:
  // package@version::interface/service_name e.g.:
  // android.hardware.vibrator@1.0::IVibrator/default
  string instanceName = instance.substr(0, instance.find('/'));
  string serviceName = instance.substr(instance.find('/') + 1);
  // Fail the process if trying to pass multiple service names for the same
  // service instance.
  if (halServiceInstances->find(instanceName) != halServiceInstances->end()) {
    cerr << "Exisitng instance " << instanceName << " with name "
         << (*halServiceInstances)[instanceName] << endl;
  } else {
    (*halServiceInstances)[instanceName] = serviceName;
  }
}

void ShowUsage() {
  cout << "Usage: vts_hal_replayer [options] <trace file>\n"
          "--spec_dir_path <path>:     Set path that store the vts spec files\n"
          "--hal_service_instances <name>:  Set the hal service name\n"
          "--help:                     Show help\n";
  exit(1);
}

int main(int argc, char** argv) {
  android::base::InitLogging(argv, android::base::StderrLogger);

  const char* const short_opts = "hld:n:";
  const option long_opts[] = {
      {"help", no_argument, nullptr, 'h'},
      {"list_service", no_argument, nullptr, 'l'},
      {"spec_dir_path", optional_argument, nullptr, 'd'},
      {"hal_service_instances", optional_argument, nullptr, 'n'},
      {nullptr, 0, nullptr, 0}};

  string spec_dir_path = kDefaultSpecDirPath;
  map<string, string> hal_service_instances;
  bool list_service = false;

  while (true) {
    int opt = getopt_long(argc, argv, short_opts, long_opts, nullptr);
    if (opt == -1) {
      break;
    }

    switch (opt) {
      case 'h':
      case '?':
        ShowUsage();
        return 0;
      case 'd': {
        spec_dir_path = string(optarg);
        break;
      }
      case 'n': {
        AddHalServiceInstance(string(optarg), &hal_service_instances);
        break;
      }
      case 'l': {
        list_service = true;
        break;
      }
      default:
        cerr << "getopt_long returned unexpected value " << opt << endl;
        return 2;
    }
  }

  if (optind != argc - 1) {
    cerr << "Must specify the trace file (see --help).\n" << endl;
    return 2;
  }

  string trace_path = argv[optind];

  android::vts::VtsHalDriverManager driver_manager(spec_dir_path,
                                                   kDefaultEpochCount, "");
  android::vts::VtsHidlHalReplayer replayer(&driver_manager);

  if (list_service) {
    replayer.ListTestServices(trace_path);
  } else {
    bool success = replayer.ReplayTrace(trace_path, hal_service_instances);
    if (success) {
      cout << endl << kPassedMarker << endl;
    }
  }
  return 0;
}