// Copyright 2010-2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "client/client.h"

#ifdef OS_WIN
#include <windows.h>
#else
#include <sys/types.h>
#include <unistd.h>
#endif  // OS_WIN

#include <iostream>  // NOLINT

#include "base/file_stream.h"
#include "base/flags.h"
#include "base/logging.h"
#include "base/port.h"
#include "base/scoped_ptr.h"
#include "base/util.h"
#include "renderer/renderer_client.h"
#include "renderer/renderer_command.pb.h"
#include "session/random_keyevents_generator.h"

// TODO(taku)
// 1. multi-thread testing
// 2. change/config the senario

DEFINE_int32(max_keyevents, 100000,
             "test at most |max_keyevents| key sequences");
DEFINE_string(server_path, "", "specify server path");
DEFINE_int32(key_duration, 10, "key duration (msec)");
DEFINE_bool(display_preedit, true, "display predit to tty");
DEFINE_bool(test_renderer, false, "test renderer");
DEFINE_bool(test_testsendkey, true, "test TestSendKey");

DECLARE_bool(logtostderr);

namespace mozc {
namespace {

void DisplayPreedit(const commands::Output &output) {
  // TODO(taku): display segment attributes
  if (output.has_preedit()) {
    string value;
    for (size_t i = 0; i < output.preedit().segment_size(); ++i) {
      value += output.preedit().segment(i).value();
    }
#ifdef OS_WIN
    string tmp;
    Util::UTF8ToSJIS(value, &tmp);
    cout << tmp << '\r';
#else
    cout << value << '\r';
#endif  // OS_WIN
  } else if (output.has_result()) {
#ifdef OS_WIN
    string tmp;
    Util::UTF8ToSJIS(output.result().value(), &tmp);
    cout << tmp << endl;
#else
    cout << output.result().value() << endl;
#endif  // OS_WIN
  }
}
}  // namespace
}  // namespace mozc

int main(int argc, char **argv) {
  InitGoogle(argv[0], &argc, &argv, false);

  FLAGS_logtostderr = true;

  mozc::client::Client client;
  if (!FLAGS_server_path.empty()) {
    client.set_server_program(FLAGS_server_path);
  }

  CHECK(client.IsValidRunLevel()) << "IsValidRunLevel failed";
  CHECK(client.EnsureSession()) << "EnsureSession failed";
  CHECK(client.NoOperation()) << "Server is not respoinding";

  scoped_ptr<mozc::renderer::RendererClient> renderer_client;
  mozc::commands::RendererCommand renderer_command;

  if (FLAGS_test_renderer) {
#if defined(OS_WIN) || defined(OS_MACOSX)
#ifdef OS_WIN
    renderer_command.mutable_application_info()->set_process_id
        (::GetCurrentProcessId());
    renderer_command.mutable_application_info()->set_thread_id
        (::GetCurrentThreadId());
#endif  // OS_WIN
    renderer_command.mutable_preedit_rectangle()->set_left(10);
    renderer_command.mutable_preedit_rectangle()->set_top(10);
    renderer_command.mutable_preedit_rectangle()->set_right(200);
    renderer_command.mutable_preedit_rectangle()->set_bottom(30);
#else
    LOG(FATAL) << "test_renderer is only supported on Windows and Mac";
#endif  // OS_WIN || OS_MACOSX
    renderer_client.reset(new mozc::renderer::RendererClient);
    CHECK(renderer_client->Activate());
  }

  vector<mozc::commands::KeyEvent> keys;
  mozc::commands::Output output;
  int32 keyevents_size = 0;

  // TODO(taku):
  // Stop the test if server is crashed.
  // Currently, we cannot detect the server crash out of
  // client library, as client automatically re-lahches the server.

  while (true) {
    mozc::session::RandomKeyEventsGenerator::GenerateSequence(&keys);
    CHECK(client.NoOperation()) << "Server is not responding";
    for (size_t i = 0; i < keys.size(); ++i) {
      mozc::Util::Sleep(FLAGS_key_duration);
      keyevents_size++;
      if (keyevents_size % 100 == 0) {
        cout << keyevents_size << " key events finished" << endl;
      }
      if (FLAGS_max_keyevents < keyevents_size) {
        cout << "key events reached to " << FLAGS_max_keyevents << endl;
        return 0;
      }
      if (FLAGS_test_testsendkey) {
        VLOG(2) << "Sending to Server: " << keys[i].DebugString();
        client.TestSendKey(keys[i], &output);
        VLOG(2) << "Output of TestSendKey: " << output.DebugString();
        mozc::Util::Sleep(10);
      }

      VLOG(2) << "Sending to Server: " << keys[i].DebugString();
      client.SendKey(keys[i], &output);
      VLOG(2) << "Output of SendKey: " << output.DebugString();

      if (FLAGS_display_preedit) {
        mozc::DisplayPreedit(output);
      }

      if (renderer_client.get() != NULL) {
        renderer_command.set_type(mozc::commands::RendererCommand::UPDATE);
        renderer_command.set_visible(output.has_candidates());
        renderer_command.mutable_output()->CopyFrom(output);
        VLOG(2) << "Sending to Renderer: " << renderer_command.DebugString();
        renderer_client->ExecCommand(renderer_command);
      }
    }
  }

  return 0;
}
