/*!
  \file
  \brief mot ファイルの送信プログラム

  \author Satofumi KAMIMURA

  $Id: sloader.cpp 1157 2009-07-18 11:18:40Z satofumi $
*/

#include "SformatHandler.h"
#include "SformatSender.h"
#include "SerialDevice.h"
#include "StandardIo.h"
#include "DetectOS.h"
#include <iostream>
#include <cstring>
#include <cstdlib>

using namespace qrk;
using namespace std;


namespace
{
#if defined(WINDOWS_OS)
  const char* DefaultPort = "COM3";
#else
  const char* DefaultPort = "/dev/usb/ttyUSB0";
#endif


  class ArgsInformation
  {
    string device_;
    string file_;


    void printHelp(const char* program_name)
    {
      cout << "usage: " << endl
           << "\t" << program_name << " [options] <mot file>" << endl;

      // !!! options

      exit(0);
    }


  public:
    ArgsInformation(int argc, char *argv[]) : device_(DefaultPort)
    {
      // -h, --help
      // -v, --version
      for (int i = 1; i < argc; ++i) {
        const char* token = argv[i];
        if (! strncmp("--port=", token, 6)) {
          device_ = &token[7];

        } else {
          file_ = token;
        }
      }

      // 引数に何も指定がない場合、ヘルプを表示して終了する
      const char* program_name = argv[0];
      if (file_.empty()) {
        printHelp(program_name);
      }
    }


    const char* device(void) const
    {
      return device_.c_str();
    }


    const char* file(void) const
    {
      return file_.c_str();
    }
  };


  class SformatSenderConsole : public SformatSender
  {
  public:
    SformatSenderConsole(Connection* connection, long baudrate)
      : SformatSender(connection, baudrate)
    {
    }


    void progress(double percent)
    {
      static_cast<void>(percent);
      cout << ".";
    }
  };


  int runTerminal(Connection* connection)
  {
    StandardIo sio;
    enum { BufferSize = 1024 };
    char buffer[BufferSize];

    while (1) {
      int n = connection->receive(buffer, BufferSize, 0);
      if (n > 0) {
        for (int i = 0; i < n; ++i) {
          char ch = buffer[i];

          if (isprint(ch) || (ch == '\r') || (ch == '\n') || (ch == '\t')) {
            printf("%c", ch);
          } else {
            // 改行以外のバイナリ文字は、16進表示
            printf("[%02x]", (unsigned char)ch);
          }
          fflush(stdout);
        }
      }
      n = sio.receive(buffer, BufferSize, 10);
      if (n > 0) {
        connection->send(buffer, n);
      }
    }

    return 0;
  }
}


int main(int argc, char *argv[])
{
  ArgsInformation args(argc, argv);

  // mot ファイルをチェック
  SformatHandler mot_file(args.file());
  if (mot_file.invalid()) {
    cout << mot_file.what() << endl;
    exit(1);
  }

  // デバイスへの接続
  SerialDevice serial;
  enum { Baudrate = 115200 };
  if (! serial.connect(args.device(), Baudrate)) {
    cout << "Coudn't connect: " << args.device() << endl;
    exit(1);
  }

  // mot ファイルの転送と実行
  enum { TransferBaudrate = 115200 };
  SformatSenderConsole sformat(&serial, TransferBaudrate);
  if ((! sformat.send(args.file())) || (! sformat.jump(args.file()))) {
    cout << sformat.what() << endl;
    exit(1);
  }

  // ターミナル動作
  return runTerminal(&serial);
}
