/*=========================================================================

  Program:   CMake - Cross-Platform Makefile Generator
  Module:    $RCSfile$
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#ifndef cmDefinitions_h
#define cmDefinitions_h

#include "cmStandardIncludes.h"

/** \class cmDefinitions
 * \brief Store a scope of variable definitions for CMake language.
 *
 * This stores the state of variable definitions (set or unset) for
 * one scope.  Sets are always local.  Gets search parent scopes
 * transitively and save results locally.
 */
class cmDefinitions
{
public:
  /** Construct with the given parent scope.  */
  cmDefinitions(cmDefinitions* parent = 0);

  /** Reset object as if newly constructed.  */
  void Reset(cmDefinitions* parent = 0);

  /** Returns the parent scope, if any.  */
  cmDefinitions* GetParent() const { return this->Up; }

  /** Get the value associated with a key; null if none.
      Store the result locally if it came from a parent.  */
  const char* Get(const char* key);

  /** Set (or unset if null) a value associated with a key.  */
  const char* Set(const char* key, const char* value);

  /** Compute the closure of all defined keys with values.
      This flattens the scope.  The result has no parent.  */
  cmDefinitions Closure() const;

  /** Compute the set of all defined keys.  */
  std::set<cmStdString> ClosureKeys() const;

private:
  // String with existence boolean.
  struct Def: public cmStdString
  {
    Def(): cmStdString(), Exists(false) {}
    Def(const char* v): cmStdString(v?v:""), Exists(v?true:false) {}
    Def(Def const& d): cmStdString(d), Exists(d.Exists) {}
    bool Exists;
  };
  static Def NoDef;

  // Parent scope, if any.
  cmDefinitions* Up;

  // Local definitions, set or unset.
  typedef std::map<cmStdString, Def> MapType;
  MapType Map;

  // Internal query and update methods.
  Def const& GetInternal(const char* key);
  Def const& SetInternal(const char* key, Def const& def);

  // Implementation of Closure() method.
  struct ClosureTag {};
  cmDefinitions(ClosureTag const&, cmDefinitions const* root);
  void ClosureImpl(std::set<cmStdString>& undefined,
                   cmDefinitions const* defs);

  // Implementation of ClosureKeys() method.
  void ClosureKeys(std::set<cmStdString>& defined,
                   std::set<cmStdString>& undefined) const;
};

#endif
