#ifndef ASTL_BINARY_CLASS
#define ASTL_BINARY_CLASS

// Implements the common behavior of ASTL binaries

#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <iterator>

#include <astl.h>
#include <alphabet.h>
#include <dfa_map.h>
#include <dfa_matrix.h>
#include <dfa_bin.h>
#include <dfa_tr.h>
#include <dfa_mtf.h>
#include <dfa_hash.h>
#include <ccopy.h>
#include <cursor.h>
#include <string.h>
#include <stream.h>
#include <set_operation.h>
#include <astl_tree.h>
#include <language.h>
#include <stats.h>
#include <minimize.h>

const int TYPES_COUNT = 6;
string dfa_types[TYPES_COUNT] = { "matrix", "map", "bin", "mtf", "tr", "hash" };

class usage : public vector<string>
{
protected:
  string executable;
  
public:
  usage(const string &exe = string())
    : executable(exe)
  { }

  void exit(int code = 1) const; 
  void check(int argc, char **argv, int mandatory, int optional);
};
  
void usage::exit(int code = 1) const 
{
  cerr << "Usage: " << executable << " [-type matrix|map|bin|mtf|tr|hash]";
  copy(begin(), end(), ostream_iterator<string>(cerr, "\n       "));
  cerr << endl;
  ::exit(code);
}

void usage::check(int argc, char **argv, int mandatory, int optional) 
{
  --argc; ++argv;  // skip the executable name
  vector<string> tmp;
  if (argc > 0) {
    if (string(argv[0]) == "-h") exit(0);
    if (string(argv[0]) == "-type") 
      if (argc > 1) {
	string *p = find(dfa_types, dfa_types + TYPES_COUNT, string(argv[1]));
	if (p == dfa_types + TYPES_COUNT) exit(1);
	tmp.push_back(argv[1]);
	argv += 2;
	argc -= 2;
      }
      else exit(1);
  }
  if (tmp.empty())
    tmp.push_back("bin");    // default type
  
      
  if (argc >= mandatory && argc - mandatory <= optional) {
    vector<string>::operator=(tmp);
    for(; argc > 0; --argc, ++argv)
      push_back(argv[0]);
  } 
  else exit(1);

  for(; (int) size() < mandatory + optional + 1; push_back(string()));
}

template <class DFA>
void load_dfa(DFA &A, const string &filename = string())
{
  if (!filename.empty()) {
    ifstream input_file(filename.c_str());
    if (!input_file) {
      perror(filename.c_str());
      exit(2);
    }
    A.initial(clone(A, istream_cursor(input_file))); 
    input_file.close();
  }
  else
    A.initial(clone(A, istream_cursor(cin))); 
}
    
#endif

