/*
  Command-line interface to the Lambert W function
  Copyright (C) 2011 Darko Veberic, darko.veberic@ijs.si
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  You should have received a copy of the GNU General Public License
  along with this program.  If not, see .
*/
/*
  This source implements an utility "lambertw" so that the
  numerical implementation of the Lambert W function can be
  easily obtained from the command line or be used in shell
  scripts.
  Usage:
  lambertw [branch] x
  - "branch" value is optional (default 0 is assumed) and can
    be only 0 or -1
  - x value for W(x); note that the definition range for
    branch 0 is [-1/e, infinity] and for branch -1 it is
    [-1/e, 0) where 1/e is approx. 0.367879
  Examples:
  ./lambertw 3.14     -->   1.073395661239825
  ./lambertw -0.2     -->  -0.2591711018190738
  ./lambertw 0 1      -->   0.5671432904097838
  ./lambertw 0 0      -->   0
  ./lambertw -1 -0.2  -->  -2.542641357773526
  ./lambertw -1 -0.3  -->  -1.781337023421628
*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
void
Usage(const char* const argv[], const int argc = 0, const int index = -1)
{
  cout << "Usage: " << argv[0] << " [-f] [-p #] [-b #] -x #" << endl;
  if (argc) {
    int len = 0;
    string line;
    for (int i = 0; i < argc; ++i) {
      line += argv[i];
      if (i == index-1)
        len = line.length();
      line += ' ';
    }
    if (argc == index)
      len = line.length() - 1;
    cout << "Your input:\n"
         << line << '\n'
         << string(len, ' ') << '^' << endl;
  }
  exit(1);
}
int
main(int argc, char* argv[])
{
  enum EVariant {
    eVeberic = 0,
    eFukushima
  };
  EVariant variant = eVeberic;
  int precision = 20;
  int branch = 0;
  double x = -1;
  opterr = 0;
  int c;
  while ((c = getopt(argc, argv, "fp:b:x:")) != -1) {
    switch (c) {
    case 'f':
      if (variant == eVeberic)
        variant = eFukushima;
      else
        Usage(argv, argc, optind);
      break;
    case 'p':
      precision = atoi(optarg);
      if (precision < 1 || precision > 30)
        Usage(argv, argc, optind);
      break;
    case 'b':
      branch = atoi(optarg);
      if (!(branch == -1 || branch == 0))
        Usage(argv, argc, optind);
      break;
    case 'x':
      x = atof(optarg);
      break;
    default:
      Usage(argv, argc, optind);
      break;
    }
  }
  if (x < -1/M_E || (branch == -1 && x > 0))
    Usage(argv, argc, argc);
  cout << setprecision(precision);
  switch (variant) {
  case eVeberic:
    cout << utl::LambertW(branch, x);
    break;
  case eFukushima:
   cout << Fukushima::LambertW(branch, x);
   break;
  }
  cout << endl;
  return EXIT_SUCCESS;
}