#include "program_options.h"

#include <stdexcept>
#include <iostream>
#include <vector>
#include <sys/stat.h>

bool IsPathExist(const std::string &s)
{
  struct stat buffer;
  return (stat (s.c_str(), &buffer) == 0);
}

namespace
{
  static std::string _stl_file;
  static std::string _sb_file;
  static std::string _ref_sb_file;
  static bool  _stl     = false;
  static bool  _sb      = false;
  static bool  _ref_sb  = false;
  static bool  _GUI     = true; // by default, GUI will be launched
  static bool  _compare = false;
  static std::string _empty("");
}  // namespace

void program_options::help(void)
{
    std::cerr << "Usage : dentaire [-h|--help] \n\t\t [-n|--noGUI] \n\t\t [-c|--compare] (needs -sb and -rsb) \n\t\t [-stl|--stl <stl_file>] \n\t\t [-sb|--scanbodies <scanbodies file>] \n\t\t [-rsb|--refscanbodies <reference scanbodies file>]\n\nexample : dentaire -n -c -sb file1.txt -rsb file2.txt\n";
}

void program_options::parse(int argc, char* argv[])
{
  if (argc > 9)
  {
    throw std::runtime_error("too many input parameters!");
  }
  const std::vector<std::string> args(argv + 1, argv + argc);
  bool sstl=false;
  bool ssb=false;
  bool srsb=false;
  
  for (const auto& arg : args)
  {
    if (sstl)
    {
      sstl=false;
      if (!IsPathExist(arg))
      {
        throw std::runtime_error(std::string(arg) + ": No such file or directory");
      }
      _stl=true;
      _stl_file=arg;
      continue;
    }
    if (ssb)
    {
      ssb=false;
      if (!IsPathExist(arg))
      {
        throw std::runtime_error(std::string(arg) + ": No such file or directory");
      }
      _sb=true;
      _sb_file=arg;
      continue;
    }
    if (srsb)
    {
      srsb=false;
      if (!IsPathExist(arg))
      {
        throw std::runtime_error(std::string(arg) + ": No such file or directory");
      }
      _ref_sb=true;
      _ref_sb_file=arg;
      continue;
    }

    if (arg == "-n" || arg == "--noGUI")
    {
      _GUI = false;
      continue;
    }
    if (arg == "-c" || arg == "--compare")
    {
      if (_compare)
      {
        throw std::runtime_error("cannot use -c/--compare twice!");
      }
      _compare = true;
      continue;
    }

    if (arg == "-stl" || arg == "--stl")
    {
      if (_stl)
      {
        throw std::runtime_error("cannot load multiple STL files!");
      }
      sstl = true;
      continue;
    }

    if (arg == "-sb" || arg == "--scanbodies")
    {
      if (_sb)
      {
        throw std::runtime_error("cannot load multiple sb files!");
      }
      ssb = true;
      continue;
    }

    if (arg == "-rsb" || arg == "--refscanbodies")
    {
      if (_ref_sb)
      {
        throw std::runtime_error("cannot load multiple refsb files!");
      }
      srsb=true;
      continue;
    }
    if (arg == "-h" || arg == "--help")
    {
      _GUI = false;
      help();
      continue;
    }
    throw std::runtime_error("unrecognized argument!"); // argument unknown
  }

  if (sstl) //option was followed by a filename
  {
    throw std::runtime_error("missing STL filename!");
  }

  if (ssb) //option was followed by a filename
  {
    throw std::runtime_error("missing scanbodies filename!");
  }
    
  if (srsb) //option was followed by a filename
  {
    throw std::runtime_error("missing reference scanbodies filename!");
  }
  
  if (_compare) //cannot compare inexistent data
  {
    if ((!_sb)||(!_ref_sb))
    {
      throw std::runtime_error("need two sb files to compare!");
    }
  }
}

const std::string& program_options::stl_file()
{
  if (_stl)
    return _stl_file;
  else std::runtime_error("no STL file has been provided!");
  return(_empty);
}

const std::string& program_options::sb_file()
{
  if (_sb)
    return _sb_file;
  else std::runtime_error("no scanbodies file has been provided!");
  return(_empty);
}

const std::string& program_options::ref_sb_file()
{
  if (_ref_sb)
    return _ref_sb_file;
  else std::runtime_error("no ref scanbodies file has been provided!");
  return(_empty);
}

bool program_options::stl()
{
  return _stl;
}

bool program_options::sb()
{
  return _sb;
}

bool program_options::ref_sb()
{
  return _ref_sb;
}

bool program_options::GUI()
{
  return _GUI;
}

bool program_options::compare()
{
  return _compare;
}
