/*---------------------------------------------------------------------------*\
                          ____  _ _ __ _ __  ___ _ _
                         |_ / || | '_ \ '_ \/ -_) '_|
                         /__|\_, | .__/ .__/\___|_|
                             |__/|_|  |_|
\*---------------------------------------------------------------------------*/

/** \file PackageArgs.h
 *
 */

#ifndef ZYPPER_PACKAGEARGS_H_
#define ZYPPER_PACKAGEARGS_H_

#include <set>
#include <vector>
#include <string>
#include <utility>
#include <iosfwd>

#include <zypp/Capability.h>
using namespace zypp;

class Zypper;

struct PackageSpec
{
  PackageSpec() : modified(false) {}

  std::string orig_str;
  Capability parsed_cap;
  std::string repo_alias;
  bool modified;
};

/**
 * Only comparing parsed capabilities. Even though repository may be different,
 * if capability is the same, we must rule out one of them.
 */
struct PackageSpecCompare
{
  bool operator()( const PackageSpec & lhs, const PackageSpec & rhs ) const
  { return lhs.parsed_cap < rhs.parsed_cap; }
};

class PackageArgs
{
public:
  typedef std::set<std::string> StringSet;
  typedef std::set<PackageSpec, PackageSpecCompare> PackageSpecSet;

  struct Options
  {
    Options()
    : do_by_default( true )
    {}

    /** Whether to do (install/update) or dont (remove) by default
     *  (if +/- not specified in argument).*/
    bool do_by_default;
  };

public:
  /** Takes arguments as a vector of strings */
  PackageArgs( const std::vector<std::string> & args,
               const ResKind & kind = ResKind::package,
               const Options & opts = Options() );

  ~PackageArgs() {}

  const Options & options() const
  { return _opts; }

  const StringSet & asStringSet() const
  { return _args; }
  /** Capabilities we want to install/upgrade and don't want to remove, plus
   * associated requested repo */
  const PackageSpecSet & dos() const
  { return _dos; }
  /** Capabilities we don't want to install/upgrade or want to remove. */
  const PackageSpecSet & donts() const
  { return _donts; }

  bool empty() const
  { return dos().empty() && donts().empty(); }

protected:
  /** join arguments at comparison operators ('=', '>=', and the like) */
  void preprocess( const std::vector<std::string> & args );
  void argsToCaps( const ResKind & kind );

private:
  PackageArgs();

  Zypper & zypper;
  Options _opts;
  StringSet _args;
  PackageSpecSet _dos;
  PackageSpecSet _donts;
};

std::ostream & operator<<( std::ostream & out, const PackageSpec & spec );

#endif /* ZYPPER_PACKAGEARGS_H_ */
