// ---------------------------------------------------------------------
//   Params.h (created on Tue Aug 23 01:08:35 BRT 2005)
// 
//   Genetic Algorithm File Fitter (gaffitter)
//
//   Copyright (C) 2005-2015 Douglas A. Augusto
// 
// This file is part of gaffitter.
// 
// gaffitter 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.
// 
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------

#ifndef params_hh
#define params_hh

#include <iostream>
#include <string>
#include <sstream>
#include <list>
#include <limits>

//----------------------------------------------------------------------
/** 
 * @class Params
 *
 * @brief This class gets and processes parameters (general and GA-related)
 * specified by the user.
 */
class Params {
public:
   /**
    * @typedef Size_t
    *
    * @brief For file/item sizes and Score/Evaluate functions.
    *
    * - double can hold usually a max integer of 2^53 = 8192TiB
    * - long double can hold usually a max integer of 2^64 = 16777216TiB :)
    * - long int = 2^32 = 4GiB :(
    * - long long int = 2^64 = 16777216TiB :), but isn't ANSI C++ :(
   */
   typedef double Size_t;    
   typedef long double BigFloat; /**< big float datatype. */
   typedef long long BigInt; /**< big signed int. */
   typedef unsigned long long UBigInt; /**< big unsigned int. Must have 
                                         at least off_t (from stat.h) bits. */

public:
   /**
    * @brief Params' constructor.
    */
   Params(int& argc, char** argv): m_argc(argc), m_argv(argv),
                                   m_no_metric(false) {}
   /**
    * Print gaffitter version and exit
    */
   void ShowVersion() const;
   /**
    * Show a brief help text and exit.
    */
   void ShowUsage(const char*) const;
   /**
    * Set gaffitter options from user args.
    */
   bool Initialize();
   /**
    * Print filesizes using Bytes, KiB, MiB or GiB units ("human"
    * readable form); KB, MB or GB if '--si' option is set. Also, if
    * Gaffitter is using direct input without units then PrettySize will
    * just print the raw size (no suffixes).
    *
    * If --show-bytes is set then PrettySize prints output sizes in
    * bytes too (except for direct input without a metric).
    */
   std::string PrettySize(Size_t) const;

public:
   int& m_argc;
   char** m_argv;

   /** A list of pointers to characters ("list of strings"). This list
    * holds the arguments that could not be identified from the
    * command-line (argv). Its values are probably files or item names.
    */
   std::list<const char*> m_cmdline_items;

public:

   // General options.
   Size_t m_target; /**< target in bytes (or just a number if "no metric"). */
   Size_t m_min_size, m_max_size; /**< min and max size for the input 
                                                               files/items. */
   unsigned m_max_bins; /**< max number of desired bins (volumes). After the
                             process finishes, the m_max_bins better filled 
                             bins are printed. */
   int m_block_size; /**< the smallest amount of bytes a file can occupy. */
   bool m_verbose; /**< switch to verbose mode. */
   bool m_pipe; /**< accept input from pipe. */
   bool m_hide_items; /**< don't print the selected items. */
   bool m_hide_summary; /**< don't print footer summary. */
   bool m_show_size; /**< print file size.*/
   bool m_show_bytes; /**< also print size in bytes. */
   bool m_direct_input; /**< accept "by hand" input (files not required). */
   bool m_no_metric; /**< direct input does not require a metric (KB, MB...). */

   // Sorting options
   bool m_sort_by_size; /**< sort output by size instead of by name. */
   bool m_sort_reverse; /**< reverse order while sorting. */
   bool m_no_case; /**< ignore case distinctions when sorting. */

   bool m_null_data; /**< assumes NULL (\\0) as the delimiter of input files */
   char m_bins_separator; /**< char to separate the bins (default = newline) */
   char m_enclose_chr; /**< char to enclose the filenames (default = none) */
   bool m_enclose; /**< don't print anything if "--ew" was not used */
   char m_delimit_chr; /**< char to delimit lines (default = newline) */

   // Genetic Algorithm options
   unsigned m_ga_pop_size; /**< Population size */
   int m_ga_num_gens; /**< Number of generations */
   long m_ga_seed; /**< GA seed */
   int m_ga_sel_pressure; /**< Selection pressure */
   float m_ga_cross_prob; /**< Crossover probability */
   float m_ga_mut_prob; /**< Mutation probability */

   int m_ga_psf; /**<  Factor to adjust the population size */
   int m_ga_ngf; /**<  Factor to adjust the number of generations */

   bool m_theoretical; /**< stop if the theoretical minimum number 
                            of bins is reached */
   unsigned m_bins_theo; /**< holds the theoretical minimum number of bins (can be
                         entered by the user). It differs from m_max_bins in the 
                         sense that if m_bins_theo is reached, then the process
                         stops immediately and does not try to optimize (fill
                         better) the bins. */

   // Search options
   bool m_approximate; /**< Local approximation using Best First search 
                            (non-optimal but very fast). */
   bool m_split;       /**< Split "Search" (very fast, but just 
                            split sequentially the input according to target.*/
#if 0
   bool m_brute_force; /**< Try all combinations, may be very slow. Not 
                            recommended when |input| > 10. Use carefully! */
#endif

private:
   /** XiB ou XB (if SI), where X is K, M or G. */
   char m_unit_symbol;
   /** power equal 1000 if --si is set; 1024 otherwise. */
   float m_unit_power;

   // constants
   double KB(double power) const { return power; }
   double KB() const { return KB(m_unit_power); }

   double MB(double power) const { return power*power; }
   double MB() const { return MB(m_unit_power); }
   
   /* 1024^3 = 2^30, but 'float' usually supports only 2^24 integer
    * numbers without loss (mantissa). However 'double' supports 2^53. */
   double GB(double power) const { return power*power*power; }
   double GB() const { return GB(m_unit_power); }

   double TB(double power) const { return power*power*power*power; }
   double TB() const { return TB(m_unit_power); }

public:
   /**
    * Converts a given string to \ref Size_t, checking for errors.
    */
   static bool StringToDouble(Size_t& d, const std::string& s)
   {
      std::istringstream iss(s); return !(iss >> std::dec >> d).fail();
   }

   /** Get the correct size for target, min and max values. This
    * function already applies the correct factor.
    */
   bool GetSize( const std::string&, Size_t& ) const; 

   double DI_Factor() const { return m_di_factor; }

private:
   double m_di_factor; /**< Factor to convert in bytes a size in KB, MB or GB. 
                                                           (for direct input). */
};

//----------------------------------------------------------------------
#endif
