// rchart.C  Version 7.45  Copyleft (c) 杉本典夫
// Time-stamp: <2026-04-13 16:52:23 tac>
//
// Ngraph用レーダーチャートデータを出力する。
//
// 使用ライブラリ:libdans.so, libfun.so
// コンパイル法 :g++ -O -s -W rchart rchart.C -I/usr/local/include
//               -L/usr/local/lib -ldans -lfun

#include <dans.H>               // dans用ヘッダファイル(fun.H含む)

using namespace dans;           // dans名前空間使用(名前空間matvec含む)

const vecstr USAGE =            // プログラム使用法表示用
{
  "rchart  Version 7.45         Copyleft(Vo\\oV) 2026 杉本典夫",
  "書式:rchart  [<オプション> …]  [<データファイル> …]",
  "機能:Ngraph用レーダーチャートデータを出力する。",
  "<オプション>",
  "  -f=<ファイル名>:指定されたファイルからオプションを読み込むんや。",
  "  -h[=<コマンド名>]:オンラインマニュアルを表示するんや。(-h:-h=man)"
};

const string Title = "=== レーダーチャートデータ ==="; // 表題

class option                    // オプション集合体
{
private:
  string v_path;                // プログラムのパス
  string v_pname;               // プログラム名
public:
  option(const char* c_pname = nullptr); // コンストラクタ
  ~option()                              // デストラクタ
  {}
  const string& path() const    // プログラムのパスを返す
  { return v_path; }
  const string& pname() const   // プログラム名を返す
  { return v_pname; }
  void setdef()                 // 省略時オプション指定を設定する
  { getoptdef(*this); }
  void set(const string& optstr, char devc = OPTdev);
  // オプション指定によってオプションを設定する
};

option::option(const char* c_pname) : v_path(), v_pname()
// コンストラクタ
{
  if (c_pname == nullptr) return; // 初期設定せず
  v_pname = getname(c_pname);     // パス名なしのプログラム名取得
  v_path = c_pname;
  strsize_t idx = v_path.find(v_pname);
  if (idx != string::npos) v_path.erase(idx); // プログラム名削除
}

void option::set(const string& optstr, char devc)
// オプション指定によってオプションを設定する
{
  string opt[2];                // オプションのopt[0]:項目,opt[1]:内容
  if (getopt(opt, optstr, devc) < 1) return; // オプション指定なし
  int err = 0;
  if (opt[0] == "f")            // オプション指定ファイル
  { err = fgetopt(*this, opt[1], true); }
  else if (opt[0] == "h")       // オンラインヘルプ表示
  { err = help(pname(), USAGE, opt[1]); }
  else                          // 間違ったオプション指定
  { err = nonopt(pname(), optstr, USAGE); }
  if (err > 0) throw help_except("ヘルプ表示");
  if (err < 0) throw option_error(string("オプション指定違反→") + optstr);
}

class rchartclass               // rchartメインクラス
{
private:
  string fname;                 // ファイル名
  idd id;                       // データ識別情報
  ldata datalst;                // データリスト
  void put_ngp(ostream& fout);  // Ngraph用データを出力する
public:
  rchartclass() : fname(), id(), datalst() // コンストラクタ
  {}
  ~rchartclass()                // デストラクタ
  {}
  int get(const char* c_fname, option& opt); // データを読み込む
  void put(option& opt);                     // 基礎統計量を出力する
};

void rchartclass::put_ngp(ostream& fout) // Ngraph用データを出力する
{
  int naxis = id.ni() - 4;
  ldata_itr dpos = datalst.begin();
  fout << "%レーダーチャート座標軸のデータ\n";
  double theta = 2.0 * M_PI / (double)naxis;
  double dmin = dpos->fdata(id.ni() - 3);
  double amax = dpos->fdata(id.ni() - 2) - dmin;
  double dint = dpos->fdata(id.ni() - 1);
  if (sgn(amax) <= 0 || sgn(dint) <= 0)
  {
    fout << "%座標軸のデータが不適切！" << endl;
    return;
  }
  for (int j = 0; j < naxis; ++j)
  {
    if (j > 0) fout << NGPdelm2 << "\n";
    double thetaj = theta * (double)j;
    double x = amax * sin(thetaj), y = amax * cos(thetaj);
    fout << "0 0\n";
    fout << x << " " << y << "\n";
  }
  fout << NGPdelm << "\n";
  fout << "%レーダーチャート座標軸目盛のデータ(指定を-dpolygonにする)\n";
  int nint = int(amax / dint + 0.999);
  double a = dint;
  for (int i = 0; i < nint; ++i)
  {
    if (a > dint) fout << NGPdelm2 << "\n";
    for (int j = 0; j < naxis; ++j)
    {
      double thetaj = theta * (double)j;
      double x = a * sin(thetaj), y = a * cos(thetaj);
      fout << x << " " << y << "\n";
    }
    a += dint;
  }
  fout << NGPdelm << "\n";
  fout << "%レーダーチャートのデータ(指定を-dpolygonにする)\n";
  for (dpos = datalst.begin(); dpos != datalst.end(); ++dpos)
  {
    if (dpos != datalst.begin()) fout << NGPdelm2 << endl;
    fout << "%" << dpos->sdata(0) << "\n";
    for (int j = 0; j < naxis; ++j)
    {
      if (dpos->fdata(j + 1) != BLANKf)
      {
        double thetaj = theta * (double)j;
        double a = dpos->fdata(j + 1) - dmin;
        double x = a * sin(thetaj), y = a * cos(thetaj);
        fout << x << " " << y << "\n";
      }
    }
  }
}

int rchartclass::get(const char* c_fname, option& opt) // データを読み込む
{
  if (c_fname == nullptr) fname.erase();
  else fname = c_fname;
  int nc = fgetdata(fname, id, datalst);
  if (nc < 0) throw runtime_error("実行時エラー！");
  if (nc < 1) throw runtime_error("データがない！");
  if (id.ni() < 7) throw runtime_error("項目が7つ以上必要！");
  ldata_itr dpos = datalst.begin();
  if (dpos->fdata(id.ni() - 3) == BLANKf) throw runtime_error("座標軸の最小値がない！");
  if (dpos->fdata(id.ni() - 2) == BLANKf) throw runtime_error("座標軸の最大値がない！");
  if (dpos->fdata(id.ni() - 1) == BLANKf) throw runtime_error("座標軸の目盛り間隔がない！");
  return nc;
}

void rchartclass::put(option& opt) // 基礎統計量を出力する
{
  cout << "-s1 -dline";
  ldata_itr dpos = datalst.begin();
  double amax = dpos->fdata(id.ni() - 2) - dpos->fdata(id.ni() - 3);
  cout << " -zx" << -amax << "," << amax << "," << amax;
  cout << " -zy" << -amax << "," << amax << "," << amax << "\n";
  cout << "%";  puttitle(cout, Title);
  cout << "%\n";
  id.put_title(cout, formngp);
  id.put_stra(cout, formngp);
  put_ngp(cout);
}

int main(int argc, char* argv[]) // メインルーチン
{
  rchartclass rchart;           // メインクラス変数
  option opt(argv[0]);          // オプション
  try
  {
    opt.setdef();               // オプションの初期設定
    bool fok = true;            // ファイル処理フラッグ
    for (int i = 1; i <= argc; ++i)
    {
      if (i >= argc)
      {
        if (fok) rchart.get(nullptr, opt); // 標準入力から読み込む
      }
      else if (*(argv[i]) == CHRopt)
      { opt.set(argv[i] + 1);  fok = true; }
      else
      { rchart.get(argv[i], opt);  fok = false; }
    }
    rchart.put(opt);
  }
  catch (help_except& helpex)   // ヘルプファイル表示
  { return 0; }
  catch (option_error& opterr)  // オプション指定エラー
  { return 1; }
  catch (runtime_error& rterr)  // 実行時エラー
  {
    disperr(opt.pname(), rterr.what());
    return 2;
  }
  catch (...)                   // 予期せぬ例外
  {
    disperr(opt.pname(), "内容不明なエラー発生！");
    return 255;
  }
  return 0;
}
