/*!
  \file
  \brief S-format ファイルの転送用プログラム

  \author Satofumi KAMIMURA

  $Id: sloader.cpp 1745 2010-03-13 07:41:13Z satofumi $
*/

#include "SerialDevice.h"
#include "StandardIo.h"
#include "delay.h"
#include <fstream>
#include <iostream>
#include <cstring>
#include <cstdlib>

using namespace qrk;
using namespace std;


namespace
{
  //const char DefaultDevice[] = "/dev/ttyUSB0";
  const char DefaultDevice[] = "/dev/ttyACM0";
  const long DefaultBaudrate = 38400; // [bps]


  void printHelp(const char* program_name)
  {
    printf("usage:\n"
           "\t%s [options] <mot-file>\n"
           "\n"
           "options:\n"
           "-h,--help                              Print this message.\n"
           "-p=<PORT>, --port=<PORT>               Specify serial device.\n"
           "-b=<BAUDRATE>, --baudrate=<BAUDRATE>   Specify write baudrate.\n"
           "\n", program_name);
  }


  int motFileLines(const char* mot_file)
  {
    ifstream fin(mot_file);
    if (! fin.is_open()) {
      return -1;
    }

    int n = 0;
    string line;
    while (getline(fin, line)) {
      ++n;
    }

    return n;
  }


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

    while (true) {
      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;
  }
}


static int sendMotFile(Connection* connection,
                       const char* mot_file, const char* device, long baudrate,
                       int lines)
{
  // ファイルを開き、ターゲットに転送する
  ifstream fin(mot_file);
  if (! fin.is_open()) {
    perror(mot_file);
    return 1;
  }

  if (! connection->connect(device, baudrate)) {
    cout << "connect: " << connection->what() << endl;
    return 1;
  }

  enum {
    LineTimeout = 0,
    LastTimeout = 10,
  };
  int n = 0;
  string line;
  while (getline(fin, line)) {
    int percent = 100 * n / lines;
    fprintf(stderr, "%d %%\r", percent);

    connection->send(line.c_str(), line.size());
    connection->send("\n", 1);
    delay(LineTimeout);

#if 0
    // !!! 受信文字のデバッグ表示
    enum { BufferSize = 256 };
    char buffer[BufferSize + 1];
    int receive_n = connection->receive(buffer, BufferSize, 100);
    if (receive_n > 0) {
      buffer[receive_n] = '\0';
      fprintf(stderr, "%d: %s\n", receive_n, buffer);
      fprintf(stderr, "\n");
    }
#endif

    ++n;
  }
  connection->send("\n", 1);
  fprintf(stderr, "100 %%\r\n");

  delay(LastTimeout);

  return 0;
}


int main(int argc, char *argv[])
{
  const char* device = DefaultDevice;
  long baudrate = DefaultBaudrate;
  const char* mot_file = NULL;

  for (int i = 1; i < argc; ++i) {
    const char* token = argv[i];
    if ((! strcmp("-h", token)) || (! strcmp("--help", token))) {
      // ヘルプ表示
      printHelp(argv[0]);
      exit(0);

    } else if (! strncmp("-b=", token, 3)) {
      baudrate = atoi(&token[3]);
    } else if (! strncmp("--baudrate=", token, 11)) {
      baudrate = atoi(&token[11]);

    } else if (! strncmp("-p=", token, 3)) {
      device = &token[3];
    } else if (! strncmp("--port=", token, 7)) {
      device = &token[7];

    } else {
      mot_file = argv[i];
    }
  }

  int lines = motFileLines(mot_file);
  if (lines < 0) {
    perror(mot_file);
    return 1;
  }

  SerialDevice serial;
  int ret = sendMotFile(&serial, mot_file, device, baudrate, lines);
  if (ret != 0) {
    return ret;
  }
  return runTerminal(&serial);
}
