
/*

  KLayout Layout Viewer
  Copyright (C) 2006-2020 Matthias Koefferlein

  This program 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 2 of the License, or
  (at your option) any later version.

  This program 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 this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

*/


#ifndef HDR_dbLayout
#define HDR_dbLayout

#include "dbCommon.h"

#include "dbArray.h"
#include "dbPropertiesRepository.h"
#include "dbObject.h"
#include "dbText.h"
#include "dbCell.h"
#include "dbLayoutStateModel.h"
#include "dbLayerProperties.h"
#include "dbMetaInfo.h"
#include "dbCellInst.h"
#include "tlException.h"
#include "tlVector.h"
#include "tlString.h"
#include "tlThreads.h"
#include "tlObject.h"
#include "tlUniqueId.h"
#include "gsi.h"

#include <cstring>
#include <map>
#include <set>
#include <string>
#include <list>
#include <vector>


namespace db
{

class Manager;
class MemStatistics;
class PCellVariant;
class PCellDeclaration;
class PCellHeader;
class Library;
class LibraryProxy;
class CellMapping;
class LayerMapping;
class Region;
class Edges;
class EdgePairs;

template <class Coord> class generic_repository;
typedef generic_repository<db::Coord> GenericRepository;

/**
 *  @brief The cell iterator
 *
 *  Since we are using a custom cell list, we have to provide our own iterator
 */
template <class C>
class DB_PUBLIC_TEMPLATE cell_list_iterator
{
public:
  typedef C cell_type;
  typedef cell_type value_type;
  typedef cell_type *pointer; 
  typedef cell_type &reference; 
  typedef std::bidirectional_iterator_tag iterator_category;
  typedef void difference_type;

  /**
   *  @brief Default constructor
   */
  cell_list_iterator ()
    : mp_cell (0)
  { }

  /**
   *  @brief Constructor pointing to a certain element
   */
  cell_list_iterator (cell_type *cell)
    : mp_cell (cell)
  { }

  /**
   *  @brief Equality
   */
  bool operator== (const cell_list_iterator &d) const
  {
    return mp_cell == d.mp_cell;
  }

  /**
   *  @brief Inequality
   */
  bool operator!= (const cell_list_iterator &d) const
  {
    return mp_cell != d.mp_cell;
  }

  /**
   *  @brief Increment
   */
  cell_list_iterator &operator++ () 
  {
    mp_cell = mp_cell->mp_next;
    return *this;
  }

  /**
   *  @brief Decrement
   */
  cell_list_iterator &operator-- () 
  {
    mp_cell = mp_cell->mp_last;
    return *this;
  }

  /**
   *  @brief Access
   */
  cell_type &operator* () const
  {
    return *mp_cell;
  }

  /**
   *  @brief Access
   */
  cell_type *operator-> () const
  {
    return mp_cell;
  }

private:
  cell_type *mp_cell;
};

/**
 *  @brief The cell iterator
 *
 *  Since we are using a custom cell list, we have to provide our own iterator
 */
template <class C>
class cell_list_const_iterator
{
public:
  typedef C cell_type;
  typedef const cell_type value_type;
  typedef const cell_type *pointer; 
  typedef const cell_type &reference; 
  typedef std::bidirectional_iterator_tag iterator_category;
  typedef void difference_type;

  /**
   *  @brief Default constructor
   */
  cell_list_const_iterator ()
    : mp_cell (0)
  { }

  /**
   *  @brief Constructor pointing to a certain element
   */
  cell_list_const_iterator (const cell_type *cell)
    : mp_cell (cell)
  { }

  /**
   *  @brief Default constructor
   */
  cell_list_const_iterator (cell_list_iterator<cell_type> iter)
    : mp_cell (& (*iter))
  { }

  /**
   *  @brief Equality
   */
  bool operator== (const cell_list_const_iterator &d) const
  {
    return mp_cell == d.mp_cell;
  }

  /**
   *  @brief Inequality
   */
  bool operator!= (const cell_list_const_iterator &d) const
  {
    return mp_cell != d.mp_cell;
  }

  /**
   *  @brief Increment
   */
  cell_list_const_iterator &operator++ () 
  {
    mp_cell = mp_cell->mp_next;
    return *this;
  }

  /**
   *  @brief Decrement
   */
  cell_list_const_iterator &operator-- () 
  {
    mp_cell = mp_cell->mp_last;
    return *this;
  }

  /**
   *  @brief Access
   */
  const cell_type &operator* () const
  {
    return *mp_cell;
  }

  /**
   *  @brief Access
   */
  const cell_type *operator-> () const
  {
    return mp_cell;
  }

private:
  const cell_type *mp_cell;
};

/**
 *  @brief The cell list 
 */
template <class C>
class cell_list
{
public:
  typedef C cell_type;
  typedef cell_list_iterator<cell_type> iterator;
  typedef cell_list_const_iterator<cell_type> const_iterator;

  /**
   *  @brief The default constructor
   */
  cell_list ()
    : mp_first (0), mp_last (0)
  {
    //  .. nothing yet ..
  }

  /**
   *  @brief Destructor
   */
  ~cell_list ()
  {
    clear ();
  }

  /**
   *  @brief Clear the cell list
   */
  void clear ()
  {
    while (! empty ()) {
      erase (begin ());
    }
  }

  /**
   *  @brief Push back a new pointer
   *
   *  The ownership over that pointer is transferred to the CellList.
   */
  void push_back_ptr (cell_type *new_cell)
  {
    new_cell->mp_last = mp_last;
    new_cell->mp_next = 0;
    if (mp_last) {
      mp_last->mp_next = new_cell;
    } else {
      mp_first = new_cell;
    }
    mp_last = new_cell;
  }
  
  /**
   *  @brief empty predicate
   *
   *  @return true, if the list is empty
   */
  bool empty () const
  {
    return mp_last == 0 && mp_first == 0;
  }
  
  /**
   *  @brief begin iterator
   */
  iterator begin () 
  {
    return iterator (mp_first);
  }
  
  /**
   *  @brief end iterator
   */
  iterator end () 
  {
    return iterator (0);
  }
  
  /**
   *  @brief begin iterator (const)
   */
  const_iterator begin () const
  {
    return const_iterator (mp_first);
  }
  
  /**
   *  @brief end iterator (const)
   */
  const_iterator end () const
  {
    return const_iterator (0);
  }

  /**
   *  @brief Take out an element from the list
   *
   *  This removes the element from the list but does not
   *  destroy it. The ownership is given back to the 
   *  caller.
   */
  cell_type *take (iterator iter) 
  {
    cell_type *cell = &(*iter);
    
    if (cell->mp_last) {
      cell->mp_last->mp_next = cell->mp_next;
    } else {
      mp_first = cell->mp_next;
    }

    if (cell->mp_next) {
      cell->mp_next->mp_last = cell->mp_last;
    } else {
      mp_last = cell->mp_last;
    }

    cell->mp_last = 0;
    cell->mp_next = 0;

    return cell;
  }

  /**
   *  @brief Erase an element from the list
   *
   *  This will destroy the underlying cell object.
   */
  void erase (iterator iter)
  {
    delete take (iter);
  }

private:
  //  No copy, no assignment (because the is no good cell copy constructor)
  cell_list &operator= (const cell_list &d);
  cell_list (const cell_list &d);

  cell_type *mp_first, *mp_last;
};

/**
 *  @brief A layer iterator (for valid layers)
 *
 *  The layer iterator delivers layer indices and layer properties of layer layers.
 */
class DB_PUBLIC LayerIterator
{
public:
  /**
   *  @brief Constructor
   */
  LayerIterator (unsigned int layer_index, const db::Layout &layout);

  /**
   *  @brief Increment operator
   */
  LayerIterator &operator++();

  /**
   *  @brief Equality
   */
  bool operator== (const LayerIterator &i)
  {
    return i.m_layer_index == m_layer_index;
  }

  /**
   *  @brief Inequality
   */
  bool operator!= (const LayerIterator &i)
  {
    return i.m_layer_index != m_layer_index;
  }

  /**
   *  @brief Access operator
   */
  std::pair<unsigned int, const db::LayerProperties *> operator*() const;

private:
  unsigned int m_layer_index;
  const db::Layout &m_layout;
};

/**
 *  @brief An interface that is used to map layer between libraries and PCells and the layout
 */
class ImportLayerMapping
{
public:
  /**
   *  @brief Destructor
   */
  virtual ~ImportLayerMapping () { }

  /**
   *  @brief Perform the mapping, i.e. deliver a layer index for a given LayerProperties information
   *
   *  This method can return false in the first member of the returned pair to indicate that no mapping shall
   *  be performed. Otherwise it must return the layer index in the second member.
   */
  virtual std::pair <bool, unsigned int> map_layer (const LayerProperties &lprops) = 0;
};

/**
 *  @brief The layout object
 *
 *  The layout object basically wraps the cell graphs and
 *  adds functionality for managing cell names and layer names.
 */

class DB_PUBLIC Layout 
  : public db::Object,
    public db::LayoutStateModel,
    public gsi::ObjectBase,
    public tl::Object,
    public tl::UniqueId
{
public:
  typedef db::Box box_type;
  typedef db::CellInst cell_inst_type;
  typedef db::Cell cell_type;
  typedef db::cell_list<cell_type> cell_list;
  typedef db::PCellVariant pcell_variant_type;
  typedef db::PCellHeader pcell_header_type;
  typedef db::PCellDeclaration pcell_declaration_type;
  typedef db::LibraryProxy lib_proxy_type;
  typedef cell_list::iterator iterator;
  typedef cell_list::const_iterator const_iterator;
  typedef tl::vector<db::cell_index_type> cell_index_vector;
  typedef cell_index_vector::reverse_iterator bottom_up_iterator;
  typedef cell_index_vector::const_reverse_iterator bottom_up_const_iterator;
  typedef cell_index_vector::iterator top_down_iterator;
  typedef cell_index_vector::const_iterator top_down_const_iterator;
  typedef tl::vector<cell_type *> cell_ptr_vector;
  typedef db::properties_id_type properties_id_type;
  typedef size_t pcell_id_type;
  typedef std::map<std::string, pcell_id_type> pcell_name_map;
  typedef pcell_name_map::const_iterator pcell_iterator;
  typedef std::map<std::pair<lib_id_type, cell_index_type>, cell_index_type> lib_proxy_map;
  typedef LayerIterator layer_iterator;
  typedef std::vector<MetaInfo> meta_info;
  typedef meta_info::const_iterator meta_info_iterator;

  /**
   *  @brief A helper functor to compare "const char *" by the content
   */
  struct name_cmp_f 
  {
    bool operator() (const char *a, const char *b) const {
      return strcmp (a, b) < 0;
    }
  };

  typedef std::map<const char *, cell_index_type, name_cmp_f> cell_map_type;

  /**
   *  @brief Standard constructor
   *
   *  The editable mode will be taken from db::default_editable_mode.
   */
  Layout (db::Manager *manager = 0);

  /**
   *  @brief Standard constructor which allows one to specify editable mode
   */
  Layout (bool editable, db::Manager *manager = 0);

  /**
   *  @brief The copy ctor
   *
   *  This copy constructor inherits the attachment to a manager.
   *  For copying without attachement, create a layout without a manager attached
   *  and use the assignment operator.
   */
  Layout (const Layout &d);

  /**
   *  @brief Destructor
   */
  ~Layout ();

  /**
   *  @brief Assignment operator
   */
  Layout &operator= (const Layout &d);

  /**
   *  @brief Specifies, if the layout participates in cleanup
   *
   *  "cleanup" will be called to get rid of top level proxies.
   *  This flag controls whether cleanup happens or not. Library
   *  layouts for example must not loose proxies as they might
   *  themselves be referenced.
   *
   *  The default is OFF.
   */
  void do_cleanup (bool f)
  {
    m_do_cleanup = f;
  }

  /**
   *  @brief Clear the layout
   */
  void clear ();

  /**
   *  @brief Accessor to the array repository
   */
  ArrayRepository &array_repository ()
  {
    return m_array_repository;
  }

  /**
   *  @brief Accessor to the string repository
   */
  StringRepository &string_repository ()
  {
    return m_string_repository;
  }

  /**
   *  @brief Accessor to the shape repository
   */
  GenericRepository &shape_repository ()
  {
    return m_shape_repository;
  }

  /**
   *  @brief Accessor to the properties repository
   */
  PropertiesRepository &properties_repository ()
  {
    return m_properties_repository;
  }

  /**
   *  @brief Accessor to the properties repository
   */
  const PropertiesRepository &properties_repository () const
  {
    return m_properties_repository;
  }

  /**
   *  @brief Gets the lock for the layout object
   *  This is a generic lock that can be used to lock modifications against multiple threads.
   */
  tl::Mutex &lock ()
  {
    return m_lock;
  }

  /**
   *  @brief Collect memory statistics
   */
  void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const;

  /**
   *  @brief Sets the properties ID
   */
  void prop_id (db::properties_id_type id);

  /**
   *  @brief Gets the properties ID
   */
  db::properties_id_type prop_id () const
  {
    return m_prop_id;
  }

  /**
   *  @brief Query, if a cell with a given name is present
   *
   *  Since internally just a "const char *" is required, the interface
   *  does not use std::string for the name to avoid unnecessary string
   *  allocations.
   *
   *  @param s The name of the cell
   *  @return true, if the cell is present
   */
  bool has_cell (const char *name);

  /**
   *  @brief Obtain the index of a cell with the given name
   *
   *  Since internally just a "const char *" is required, the interface
   *  does not use std::string for the name to avoid unnecessary string
   *  allocations.
   *
   *  @param name The name of the cell
   *  @return A pair, telling if the cell was present (first) and
   *          it's index if it is present (second)
   */ 
  std::pair<bool, cell_index_type> cell_by_name (const char *name) const;

  /** 
   *  @brief Tell the name of a cell with the given index
   *  
   *  @param index The index of the cell
   *  @return The name of the cell
   */
  const char *cell_name (cell_index_type index) const;

  /**
   *  @brief Return the display name for the given cell
   *
   *  This method is forwarded to the respective method of the cell.
   *  The display name is a nicely formatted name reflecting the
   *  library source and PCell parameters (if supported by the 
   *  PCell implementation).
   */
  std::string display_name (cell_index_type cell_index) const;

  /**
   *  @brief Return the basic name for the given cell 
   *
   *  This method is forwarded to the respective method of the cell.
   *  The basic name is the "original"  cell name within the library or
   *  of the PCell. The actual cell name may differ from that by
   *  a unique extension.
   */
  std::string basic_name (cell_index_type cell_index) const;

  /** 
   *  @brief Add a cell object with the given ID and name
   *
   *  This method is basically supposed to be used for "undo" and "redo". 
   *  It is not intended for general use. It requires that the cell was already 
   *  created before and has gone "invalid" in between. The cell object's ownership is transferred to 
   *  the layout. 
   *
   *  @param id The name of the new cell
   *  @param name The name of the new cell
   *  @param cell The pointer of the cell object to transfer
   */
  void insert_cell (cell_index_type ci, const std::string &name, db::Cell *cell);

  /** 
   *  @brief Take a cell object with the given ID and name
   *
   *  This method is basically supposed to be used for "undo" and "redo". 
   *  It is not intended for general use. It takes out the cell object and released ownership
   *  within the layout object.
   *
   *  @param id The name of the new cell
   *  @return The pointer to the "free" cell object
   */
  db::Cell *take_cell (cell_index_type ci);

  /**
   *  @brief Uniquify the given name by appending a suitable suffix
   *
   *  @param name The input name 
   *  @return A similar name that is unique
   */
  std::string uniquify_cell_name (const char *name) const;

  /** 
   *  @brief Add a cell with a given name
   *
   *  Since internally just a "const char *" is required, the interface
   *  does not use std::string for the name to avoid unnecessary string
   *  allocations.
   *  If the name pointer is 0, the cell is given a unique name.
   *
   *  @param s The name of the new cell
   *  @return The index of the new cell
   */
  cell_index_type add_cell (const char *name = 0);

  /** 
   *  @brief Rename a cell
   *
   *  Rename the cell with the given id.
   *
   *  @param id The index of the cell to rename
   *  @param name The new name of the cell
   */
  void rename_cell (cell_index_type id, const char *name);

  /**
   *  @brief Delete a cell 
   *
   *  This deletes a cell but not the sub cells of the cell.
   *  These subcells will likely become new top cells unless they are used
   *  otherwise.
   *  All instances of this cell are deleted as well.
   *  Hint: to delete multiple cells, use "delete_cells" which is 
   *  far more efficient in this case.
   *
   *  @param id The index of the cell to delete
   */
  void delete_cell (cell_index_type id);

  /**
   *  @brief Delete multiple cells
   *
   *  This deletes the cells but not the sub cells of these cells.
   *  These subcells will likely become new top cells unless they are used
   *  otherwise.
   *  All instances of these cells are deleted as well.
   *
   *  @param from A begin type iterator that delivers the ids of the cells to delete
   *  @param to A end type iterator that delivers the ids of the cells to delete
   */
  template <class Iter>
  void delete_cells (Iter from, Iter to)
  {
    std::set<cell_index_type> cells_to_delete;
    cells_to_delete.insert (from, to);
    delete_cells (cells_to_delete);
  }

  /**
   *  @brief Delete multiple cells
   *
   *  This deletes the cells but not the sub cells of these cells.
   *  These subcells will likely become new top cells unless they are used
   *  otherwise.
   *  All instances of these cells are deleted as well.
   *
   *  @param cells_to_delete A set containing the ids of the cells to delete
   */
  void delete_cells (const std::set<cell_index_type> &cells_to_delete);

  /** 
   *  @brief Convert a PCell variant to a static cell
   *
   *  @param cell_index The index of the PCell
   *  @return The index of the new cell or cell_index if the cell is not a PCell or library proxy
   */
  db::cell_index_type convert_cell_to_static (db::cell_index_type cell_index);

  /** 
   *  @brief Get a PCell variant
   *
   *  @param pcell_id The Id of the PCell declaration
   *  @param parameters The PCell parameters
   *  @return The index of the new cell
   */
  cell_index_type get_pcell_variant (pcell_id_type pcell_id, const std::vector<tl::Variant> &parameters);

  /**
   *  @brief Gets a PCell variant 
   *
   *  Unlike the first version, this one allows specification of the parameters through a 
   *  key/value dictionary. Parameters not listed there are replaced by their defaults.
   *
   *  @param pcell_id The Id of the PCell declaration
   *  @param parameters A dictionary of key/value value pairs for the parameters
   *  @return The index of the new cell
   */
  cell_index_type get_pcell_variant_dict (pcell_id_type pcell_id, const std::map<std::string, tl::Variant> &p);

  /** 
   *  @brief Get a PCell variant and replace the given cell
   *
   *  @param pcell_id The Id of the PCell declaration
   *  @param parameters The PCell parameters
   *  @param cell_index The cell index which is to be replaced by the PCell variant proxy
   *  @param layer_mapping The optional layer mapping object that maps the PCell layers to the layout's layers
   */
  void get_pcell_variant_as (pcell_id_type pcell_id, const std::vector<tl::Variant> &parameters, cell_index_type cell_index, ImportLayerMapping *layer_mapping = 0);

  /** 
   *  @brief Get the PCell variant cell of a existing cell with new parameters
   *
   *  This method is intended for internal use.
   *
   *  @param cell_index The current PCell variant proxy cell (must be a PCellVariant)
   *  @param new_parameters The new parameters
   *  @return The cell index of the new PCell variant proxy cell.
   */
  cell_index_type get_pcell_variant_cell (cell_index_type cell_index, const std::vector<tl::Variant> &new_parameters);

  /**
   *  @brief Get the PCell header of the given PCell Id
   *
   *  This method returns 0, if the id is not a valid one.
   *
   *  @param pcell_id The Id of the PCell.
   */
  const pcell_header_type *pcell_header (pcell_id_type pcell_id) const;

  /**
   *  @brief Get the PCell header of the given PCell Id (non-const version)
   *
   *  This method returns 0, if the id is not a valid one.
   *
   *  @param pcell_id The Id of the PCell.
   */
  pcell_header_type *pcell_header (pcell_id_type pcell_id);

  /**
   *  @brief Get the PCell declaration of the given PCell Id
   *
   *  This method returns 0, if the id is not a valid one.
   *
   *  @param pcell_id The Id of the PCell.
   */
  const pcell_declaration_type *pcell_declaration (pcell_id_type pcell_id) const;

  /**
   *  @brief Get the PCell Id for a given PCell name
   *
   *  If a PCell with that name does not exist, a PCell will be created.
   *
   *  @param name The name of the PCell in the scope of this layout.
   *  @return A pair of an id and a boolean which is true, if the PCell with that name exists.
   */
  std::pair<bool, pcell_id_type> pcell_by_name (const char *name) const;

  /**
   *  @brief Register a pcell declaration
   *
   *  If a PCell with that name is already registered, the definition will be overwritten, but 
   *  no update of any cell content is performed.
   *  The layout object becomes owner of the declaration object and will delete it when it is destroyed.
   */
  pcell_id_type register_pcell (const std::string &name, pcell_declaration_type *declaration);

  /** 
   *  @brief The PCell iterator (begin)
   *
   *  This iterator delivers the PCell names and ID's. iterator->first is the PCell name and iterator->second
   *  the PCell ID.
   */
  pcell_iterator begin_pcells () const
  {
    return m_pcell_ids.begin ();
  }

  /**
   *  @brief The PCell iterator (end)
   */
  pcell_iterator end_pcells () const
  {
    return m_pcell_ids.end ();
  }

  /**
   *  @brief Test, if the given cell is a PCell variant
   *
   *  The return value is a pair of a boolean which is true when the instance is a PCell
   *  instance and the PCell id of the instance if this is the case.
   *
   *  @param ref The cell to test
   *  @return See above
   */
  std::pair<bool, db::pcell_id_type> is_pcell_instance (cell_index_type cell_index) const;

  /**
   *  @brief Returns the library where the cell is finally defined 
   *
   *  In the first part of the returned pair, this method returns the pointer to the library 
   *  where the cell is defined. If the cell is not a library proxy, the return value is 0.
   *  If the cell is defined in a library, the second part of the returned pair will contain
   *  the cell index inside this library. 
   */
  std::pair<db::Library *, db::cell_index_type> defining_library (cell_index_type cell_index) const;

  /**
   *  @brief Gets the PCell declaration object for a PCell instance
   *
   *  This method determines the PCell declaration object for a given PCell variant cell.
   *  Note, that the declaration may originate from a different layout than this, if the PCell
   *  is imported from a library.
   *
   *  The cell given cell is not a PCell variant cell, 0 is returned.
   */
  const Layout::pcell_declaration_type *pcell_declaration_for_pcell_variant (cell_index_type cell_index) const;

  /**
   *  @brief Get the PCell parameters of a PCell instance
   *
   *  For the order of the parameters, ask the PCell declaration (available trough Layout::pcell_declaration
   *  from the PCell id or from Layout::pcell_declaration_for_pcell_variant from the cell_index).
   *
   *  @return A list of parameters in the order they are declared.
   */
  const std::vector<tl::Variant> &get_pcell_parameters (cell_index_type cell_index) const;

  /**
   *  @brief Gets a PCell parameter of a PCell instance
   *
   *  @return The value of the PCell parameter with the given name or a nil variant if there is no such parameter
   */
  tl::Variant get_pcell_parameter (cell_index_type cell_index, const std::string &name) const;

  /**
   *  @brief Get the PCell parameters of a PCell instance as a name to value map
   *
   *  @return A map with the parameter names and their values
   */
  std::map<std::string, tl::Variant> get_named_pcell_parameters (cell_index_type cell_index) const;

  /**
   *  @brief Get the proxy cell (index) for a given library an cell index (inside that library)
   *
   *  This method caches library proxies and delivers an existing one, if a
   *  proxy for that library/cell configuration is registered.
   *  If that is not the case, a new proxy will be created.
   */
  cell_index_type get_lib_proxy (Library *lib, cell_index_type cell_index);

  /**
   *  @brief Get the proxy cell (index) for a given library an cell index (inside that library)
   *
   *  This method replaces the cell with the given target cell index by a library. 
   */
  void get_lib_proxy_as (Library *lib, cell_index_type cell_index, cell_index_type target_cell_index, ImportLayerMapping *layer_mapping = 0);

  /**
   *  @brief Get the context information for a given cell (for writing into a file)
   *
   *  The context information is a sequence of strings which is pushed onto the given
   *  vector. It can be used to recover a respective proxy cell with the recover_proxy method.
   *  If the given cell is not a valid proxy or library references are missing, the method
   *  will return false.
   */
  bool get_context_info (cell_index_type cell_index, std::vector <std::string> &context_info) const;

  /**
   *  @brief Recover a proxy cell from the given context info.
   *
   *  Creates a proxy cell from the context information given by two iterators into a string list.
   *  If no cell can be created from the context information, null is returned. 
   *
   *  @param from The begin iterator for the strings from which to recover the cell
   *  @param to The end iterator for the strings from which to recover the cell
   */
  db::Cell *recover_proxy (std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to);

  /**
   *  @brief Recover a proxy cell from the given context info.
   *
   *  Creates a proxy cell from the context information given by two iterators into a string list.
   *  If no cell can be created from the context information, null is returned. 
   *  This creates the proxy as a cell with the given cell index.
   *
   *  @param cell_index The cell which to prepare
   *  @param from The begin iterator for the strings from which to recover the cell
   *  @param to The end iterator for the strings from which to recover the cell
   *  @param layer_mapping The optional layer mapping object that maps the PCell layers to the layout's layers
   *  @return true, if the proxy cell could be created
   */
  bool recover_proxy_as (cell_index_type cell_index, std::vector <std::string>::const_iterator from, std::vector <std::string>::const_iterator to, ImportLayerMapping *layer_mapping = 0);

  /**
   *  @brief Delete a cell plus the subcells not used otherwise
   *
   *  All subcells referenced directy or indirectly but not used otherwise
   *  are deleted as well. This basically prunes the cell tree by this cell.
   *  All instances of this cell are deleted as well.
   *
   *  @param id The index of the cell to delete
   *  @param levels The number of hierarchy levels to look for (-1: all, 0: none, 1: one level etc.)
   */
  void prune_cell (cell_index_type id, int levels = -1);

  /**
   *  @brief Delete cells plus their subcells not used otherwise
   *
   *  All subcells referenced directy or indirectly but not used otherwise
   *  are deleted as well. This basically prunes the cell tree by this cell.
   *  All instances of this cell are deleted as well.
   *  This method is more efficent than calling prune_cell multiple times.
   *
   *  @param from A begin iterator delivering the cell id's to delete
   *  @param to An end iterator delivering the cell id's to delete
   *  @param levels The number of hierarchy levels to look for (-1: all, 0: none, 1: one level etc.)
   */
  template <class Iter>
  void prune_cells (Iter from, Iter to, int levels = -1)
  {
    std::set<cell_index_type> cells_to_delete;
    cells_to_delete.insert (from, to);
    prune_cells (cells_to_delete, levels);
  }

  /**
   *  @brief Delete cells plus their subcells not used otherwise
   *
   *  All subcells referenced directy or indirectly but not used otherwise
   *  are deleted as well. This basically prunes the cell tree by this cell.
   *  All instances of this cell are deleted as well.
   *  This method is more efficent than calling prune_cell multiple times.
   *
   *  @param cells A set of cell id's to prune
   *  @param levels The number of hierarchy levels to look for (-1: all, 0: none, 1: one level etc.)
   */
  void prune_cells (const std::set<cell_index_type> &cells, int levels = -1);

  /**
   *  @brief Delete the subcells of the given cell which are not used otherwise
   *
   *  All subcells of the given cell which are referenced directy or indirectly but not used otherwise
   *  are deleted. 
   *
   *  @param id The index whose subcells to delete
   *  @param levels The number of hierarchy levels to look for (-1: all, 0: none, 1: one level etc.)
   */
  void prune_subcells (cell_index_type id, int levels = -1);

  /**
   *  @brief Delete the subcells of the given cells which are not used otherwise
   *
   *  All subcells referenced directy or indirectly but not used otherwise
   *  are deleted as well. This basically prunes the cell tree by this cell.
   *  All instances of this cell are deleted as well.
   *  This method is more efficent than calling prune_subcells for single cells multiple times.
   *
   *  @param from A begin iterator delivering the cell id's to delete
   *  @param to An end iterator delivering the cell id's to delete
   *  @param levels The number of hierarchy levels to look for (-1: all, 0: none, 1: one level etc.)
   */
  template <class Iter>
  void prune_subcells (Iter from, Iter to, int levels = -1)
  {
    std::set<cell_index_type> cells_to_delete;
    cells_to_delete.insert (from, to);
    prune_subcells (cells_to_delete, levels);
  }

  /**
   *  @brief Delete the subcells of the given cells which are not used otherwise
   *
   *  All subcells referenced directy or indirectly but not used otherwise
   *  are deleted as well. This basically prunes the cell tree by this cell.
   *  All instances of this cell are deleted as well.
   *  This method is more efficent than calling prune_subcells for single cells multiple times.
   *
   *  @param cells A set of cell id's to prune
   *  @param levels The number of hierarchy levels to look for (-1: all, 0: none, 1: one level etc.)
   */
  void prune_subcells (const std::set<cell_index_type> &cells, int levels = -1);

  /**
   *  @brief Flatten a cell into another cell
   *
   *  @param source_cell Where to take the content from
   *  @param target_cell Where to put the content to
   *  @param t The transformation to apply (can be unity for first level)
   *  @param levels The number of levels to flatten or -1 for all levels (0: just copy and transform if source cell != target cell, 1: flatten on level of instances etc.)
   */
  void flatten (const db::Cell &source_cell, db::Cell &target_cell, const db::ICplxTrans &t, int levels);

  /**
   *  @brief Flatten a cell 
   *
   *  This convenience method is a special version of the other flatten method.
   *
   *  @param cell The cell to flatten
   *  @param levels The number of levels to flatten or -1 for all levels (0: nothing, 1: flatten on level of instances etc.)
   *  @param prune If true, remove all cells which became orphans by the flattening
   */
  void flatten (db::Cell &cell, int levels, bool prune = false);

  /**
   *  @brief Inserts a region (potentially hierarchical) into the given cell and layer
   *
   *  If the region is flat (conceptionally), it will be put into the cell.
   *  If the region is hierarchical, a cell hierarchy will be built below the
   *  given cell.
   */
  void insert (db::cell_index_type cell, int layer, const db::Region &region);

  /**
   *  @brief Inserts a edge collection (potentially hierarchical) into the given cell and layer
   *
   *  If the edge collection is flat (conceptionally), it will be put into the cell.
   *  If the edge collection is hierarchical, a cell hierarchy will be built below the
   *  given cell.
   */
  void insert (db::cell_index_type cell, int layer, const db::Edges &edges);

  /**
   *  @brief Inserts a edge pair collection (potentially hierarchical) into the given cell and layer
   *
   *  If the edge pair collection is flat (conceptionally), it will be put into the cell.
   *  If the edge pair collection is hierarchical, a cell hierarchy will be built below the
   *  given cell.
   */
  void insert (db::cell_index_type cell, int layer, const db::EdgePairs &edge_pairs);

  /**
   *  @brief Delete a cell plus all subcells 
   *
   *  All subcells referenced directy or indirectly are deleted as well.
   *  All instances of these cells are deleted as well.
   *
   *  @param id The index of the cell to delete
   */
  void delete_cell_rec (cell_index_type id);

  /**
   *  @brief Update the parent/child relationships between the cells
   *
   *  Basically this method needs to be called if changes have been
   *  made to the graph. It will update the parent instance lists
   *  from the child instance lists.
   */
  void update_relations ();

  /**
   *  @brief Transforms the layout with the given transformation
   */
  template <class T>
  void transform (const T &t)
  {
    for (iterator c = begin (); c != end (); ++c) {
      c->transform_into (t);
    }
  }

  /**
   *  @brief Return the number of cells
   *
   *  @return The number of cells (the maximum cell index)
   */
  cell_index_type cells () const
  {
    return (cell_index_type) m_cell_ptrs.size ();
  }
  
  /**
   *  @brief Address a cell by index
   *
   *  @param i The cell index
   *  @return A reference to the cell
   */
  cell_type &cell (cell_index_type i)
  {
    return *(m_cell_ptrs [i]);
  }

  /**
   *  @brief Address a cell by index (const version)
   *
   *  @param i The cell index
   *  @return A reference to the cell
   */
  const cell_type &cell (cell_index_type i) const
  {
    return *(m_cell_ptrs [i]);
  }

  /**
   *  @brief Reserve space for the given number of cells
   */
  void reserve (size_t n)
  {
    m_cell_ptrs.reserve (n);
  }

  /**  
   *  @brief Swap layers
   *
   *  Swaps the shapes of both layers.
   */
  void swap_layers (unsigned int a, unsigned int b);

  /**  
   *  @brief Move a layer
   *
   *  Move a layer from the source to the target. The target is not cleared before, so that this method 
   *  merges shapes from the source with the target layer. The source layer is empty after that operation.
   */
  void move_layer (unsigned int src, unsigned int dest);

  /**  
   *  @brief Copy a layer
   *
   *  Copy a layer from the source to the target. The target is not cleared before, so that this method 
   *  merges shapes from the source with the target layer.
   */
  void copy_layer (unsigned int src, unsigned int dest);

  /**  
   *  @brief Clear a layer
   *
   *  Clears the layer: removes all shapes.
   */
  void clear_layer (unsigned int n);

  /**  
   *  @brief Delete a layer
   *
   *  This does free the shapes of the cells and remembers the
   *  layer's index for recycling.
   */
  void delete_layer (unsigned int n);

  /**
   *  @brief Return true, if the cell index is a valid one
   */
  bool is_valid_cell_index (cell_index_type ci) const;

  /**
   *  @brief Returns true, if a layer index is a valid index for a normal layout layer
   */
  bool is_valid_layer (unsigned int n) const
  {
    return (n < layers () && m_layer_states [n] == Normal);
  }

  /**
   *  @brief Returns true, if a layer index is a free (unused) layer
   */
  bool is_free_layer (unsigned int n) const
  {
    return (n >= layers () || m_layer_states [n] == Free);
  }

  /**
   *  @brief Returns true, if a layer index is a special layer index
   */
  bool is_special_layer (unsigned int n) const
  {
    return (n < layers () && m_layer_states [n] == Special);
  }

  /**
   *  @brief Query the number of layers defined so far
   *  
   *  TODO: the list of 0 to nlayers-1 also contains the free layers -
   *  we should get a vector containing the layers that are acually
   *  allocated.
   */
  unsigned int layers () const
  {
    return (cell_index_type) m_layer_states.size ();
  }

  /**
   *  @brief The iterator of valid layers: begin 
   */
  layer_iterator begin_layers () const
  {
    return layer_iterator (0, *this);
  }

  /**
   *  @brief The iterator of valid layers: end 
   */
  layer_iterator end_layers () const
  {
    return layer_iterator (layers (), *this);
  }

  /**
   *  @brief Reserve space for n layers
   */
  void reserve_layers (unsigned int n);

  /**
   *  @brief begin iterator of the unsorted cell list
   */
  iterator begin () 
  {
    return m_cells.begin ();
  }
  
  /**
   *  @brief end iterator of the unsorted cell list
   */
  iterator end () 
  {
    return m_cells.end ();
  }
  
  /**
   *  @brief begin iterator of the unsorted const cell list
   */
  const_iterator begin () const
  {
    return m_cells.begin ();
  }
  
  /**
   *  @brief end iterator of the unsorted const cell list
   */
  const_iterator end () const
  {
    return m_cells.end ();
  }

  /**
   *  @brief begin iterator of the bottom-up sorted cell list
   *
   *  In bottom-up traversal a cell is not delivered before
   *  the last child cell of this cell has been delivered.
   *  The bottom-up iterator does not deliver cells but cell
   *  indices actually.
   */
  bottom_up_iterator begin_bottom_up () 
  {
    update ();
    return m_top_down_list.rbegin ();
  }
  
  /**
   *  @brief end iterator of the bottom-up sorted cell list
   */
  bottom_up_iterator end_bottom_up () 
  {
    update ();
    return m_top_down_list.rend ();
  }
  
  /**
   *  @brief begin iterator of the const bottom-up sorted cell list
   *
   *  See the non-const version for a detailed description.
   */
  bottom_up_const_iterator begin_bottom_up () const
  {
    update ();
    return m_top_down_list.rbegin ();
  }
  
  /**
   *  @brief end iterator of the const bottom-up sorted cell list
   */
  bottom_up_const_iterator end_bottom_up () const
  {
    update ();
    return m_top_down_list.rend ();
  }
  
  /**
   *  @brief begin iterator of the top-down sorted cell list
   *
   *  The top-down cell list has the property of delivering all
   *  cells before they are instantiated. In addition the first
   *  cells are all top cells. There is at least one top cell.
   *  The top-down iterator does not deliver cells but cell
   *  indices actually.
   */
  top_down_iterator begin_top_down () 
  {
    update ();
    return m_top_down_list.begin ();
  }
  
  /**
   *  @brief end iterator of the top-down sorted cell list
   */
  top_down_iterator end_top_down () 
  {
    update ();
    return m_top_down_list.end ();
  }
  
  /**
   *  @brief begin iterator of the const top-down sorted cell list
   *
   *  See the non-const version for a detailed description.
   */
  top_down_const_iterator begin_top_down () const
  {
    update ();
    return m_top_down_list.begin ();
  }
  
  /**
   *  @brief end iterator of the const top-down sorted cell list
   */
  top_down_const_iterator end_top_down () const
  {
    update ();
    return m_top_down_list.end ();
  }
  
  /**
   *  @brief end iterator of the top cells
   * 
   *  The begin iterator is identical to begin_top_down()
   */
  top_down_iterator end_top_cells ();
  
  /**
   *  @brief end iterator of the top cells
   * 
   *  The begin iterator is identical to begin_top_down()
   */
  top_down_const_iterator end_top_cells () const;
  
  /**
   *  @brief Provide a const version of the update method
   *
   *  This pseudo-const version is required in order to automatically call
   *  update within the begin method for example.
   */
  void update () const;

  /**
   *  @brief Forces an update even if the layout is under construction
   *
   *  This method behaves like "update" but forces and update even if the 
   *  "under_construction" state is active. This allows one to do the update
   *  in certain stages without triggering the update automatically and
   *  too frequently.
   */
  void force_update ();

  /**
   *  @brief Cleans up the layout
   *
   *  This method removes proxy objects which are no longer used.
   *  It can be given a list of cells which need to be kept.
   */
  void cleanup (const std::set<db::cell_index_type> &keep = std::set<db::cell_index_type> ());

  /**
   *  @brief Implementation of the undo operations
   */
  virtual void undo (db::Op *op);

  /**
   *  @brief Implementation of the redo operations
   */
  virtual void redo (db::Op *op);

  /** 
   *  @brief Database unit read accessor
   */
  double dbu () const
  {
    return m_dbu;
  }

  /**
   *  @brief Database unit write accessor
   */
  void dbu (double d);

  /**
   *  @brief Insert a new layer with the given properties
   */
  unsigned int insert_layer (const LayerProperties &props = LayerProperties ());

  /**
   *  @brief Insert a new layer with the given properties at the given index
   */
  void insert_layer (unsigned int index, const LayerProperties &props = LayerProperties ());

  /**
   *  @brief Gets or creates a layer with the given properties
   *
   *  If there already is a layer matching the given properties, it's index will be
   *  returned. Otherwise a new layer with these properties is created.
   */
  unsigned int get_layer (const db::LayerProperties &props);

  /**
   *  @brief Insert a new special layer with the given properties
   *
   *  A special layers is used for example to represent rulers.
   */
  unsigned int insert_special_layer (const LayerProperties &props = LayerProperties ());

  /**
   *  @brief Insert a new layer with the given properties at the given index
   *
   *  A special layers is used for example to represent rulers.
   */
  void insert_special_layer (unsigned int index, const LayerProperties &props = LayerProperties ());

  /**
   *  @brief Gets the guiding shape layer
   *
   *  The guiding shape layer is used to store the guiding shapes of PCells
   */
  unsigned int guiding_shape_layer () const;

  /**
   *  @brief Gets the waste layer
   *
   *  The waste layer is used to store shapes that should not be visible and can be cleared at any time.
   */
  unsigned int waste_layer () const;

  /**
   *  @brief Set the properties for a specified layer
   */
  void set_properties (unsigned int i, const LayerProperties &props);

  /**
   *  @brief Get the properties for a specified layer
   */
  const LayerProperties &get_properties (unsigned int i) const
  {
    return m_layer_props [i];
  }

  /**
   *  @brief Signal the start of an operation bringing the layout into invalid state
   *
   *  This method should be called whenever the layout is
   *  about to be brought into an invalid state. After calling
   *  this method, "under_construction" returns false which 
   *  tells foreign code (such as update which might be called
   *  asynchroneously for example because of a repaint event)
   *  not to use this layout object.
   *  This state is cancelled by the end_changes () method.
   *  The start_changes () method can be called multiple times
   *  and must be cancelled the same number of times.
   *  If a transaction is used to bracket the start and end of
   *  an operation, the start/end_changes method pair does not
   *  need to be called.
   */
  void start_changes ()
  {
    ++m_invalid;
  }

  /**
   *  @brief Cancel the "in changes" state (see "start_changes")
   */
  void end_changes ()
  {
    if (m_invalid > 0) {
      --m_invalid;
      if (! m_invalid) {
        update ();
      }
    }
  }

  /**
   *  @brief Cancel the "in changes" state (see "start_changes")
   *  This version does not force an update
   */
  void end_changes_no_update ()
  {
    if (m_invalid > 0) {
      --m_invalid;
    }
  }

  /**
   *  @brief Tell if the layout object is under construction
   *
   *  A layout object is either under construction if 
   *  the layout is brought into invalid state by "start_changes".
   */
  bool under_construction () const
  {
    return m_invalid > 0;
  }

  /**
   *  @brief Register a library proxy
   *
   *  This method is used by LibraryProxy to register itself.
   */
  void register_lib_proxy (db::LibraryProxy *lib_proxy);

  /**
   *  @brief Unregister a library proxy
   *
   *  This method is used by LibraryProxy to unregister itself.
   */
  void unregister_lib_proxy (db::LibraryProxy *lib_proxy);

  /**
   *  @brief Gets the editable status of this layout
   *
   *  If this value is true, the layout is editable, i.e. shapes and properties
   *  can be changed.
   */
  bool is_editable () const
  {
    return m_editable;
  }

  /**
   *  @brief Delivers the meta information (begin iterator)
   *
   *  Meta information is additional data that usually is set by the
   *  layout reader and holds information that was obtained when reading
   *  the file. Meta information is format specific.
   */
  meta_info_iterator begin_meta () const
  {
    return m_meta_info.begin ();
  }

  /**
   *  @brief Delivers the meta information (end iterator)
   */
  meta_info_iterator end_meta () const
  {
    return m_meta_info.end ();
  }

  /**
   *  @brief Clears the meta information
   */
  void clear_meta ();

  /**
   *  @brief Adds meta information
   *  The given meta information object is appended at the end of the meta information list.
   *  If a meta info object with the same name already exists it is overwritten.
   */
  void add_meta_info (const MetaInfo &i);

  /**
   *  @brief Removes the meta information object with the given name
   *  The method will do nothing if no object with that name exists.
   */
  void remove_meta_info (const std::string &name);

  /**
   *  @brief Gets the meta info value for a meta info object with the given name
   *  If no object with that name exists, an empty string is returned
   */
  const std::string &meta_info_value (const std::string &name) const;

protected:
  /**
   *  @brief Establish the graph's internals according to the dirty flags
   *
   *  This reimplements the LayoutStateModel interface.
   *  Calling do_update investigates the dirty flags and issues update
   *  calls on the cells and it's components as far as necessary.
   *  This will guarantee mainly that region queries can be performed
   *  on all levels of the graph.
   */
  virtual void do_update ();

private:
  enum LayerState { Normal, Free, Special };

  cell_list m_cells;
  size_t m_cells_size;
  cell_ptr_vector m_cell_ptrs;
  cell_index_vector m_free_cell_indices;
  mutable unsigned int m_invalid;
  cell_index_vector m_top_down_list;
  size_t m_top_cells;
  std::vector<unsigned int> m_free_indices;
  std::vector<LayerState> m_layer_states;
  std::vector<const char *> m_cell_names;
  cell_map_type m_cell_map;
  std::vector<LayerProperties> m_layer_props;
  double m_dbu;
  db::properties_id_type m_prop_id;
  StringRepository m_string_repository;
  GenericRepository m_shape_repository;
  PropertiesRepository m_properties_repository;
  ArrayRepository m_array_repository;
  std::vector<pcell_header_type *> m_pcells;
  pcell_name_map m_pcell_ids;
  lib_proxy_map m_lib_proxy_map;
  int m_guiding_shape_layer;
  int m_waste_layer;
  bool m_do_cleanup;
  bool m_editable;
  meta_info m_meta_info;
  tl::Mutex m_lock;

  /**
   *  @brief Sort the cells topologically
   *
   *  Establish a sorting order top-down. The sorted 
   *  cell list can be retrieved using the begin_bottom_up 
   *  ..end_bottom_up iterator pair. Alternatively the
   *  begin_top_down..end_top_down iterator pair can be used
   *  to retrieve the cell indices in top-down order after
   *  the cells have been sorted bottom-up.
   *  This method must be called whenever the graph has changed.
   *  Before this method can be called, update_relations must have
   *  been called.
   *
   *  @return true if the cell graph is OK, false if recursive
   */
  bool topological_sort ();

  /**
   *  @brief Register a cell name for the cell index 
   */
  void register_cell_name (const char *name, cell_index_type ci);

  /**
   *  @brief Allocate a cell index for a new cell
   */
  cell_index_type allocate_new_cell ();

  /**  
   *  @brief Insert a new layer
   *
   *  This creates a new index number, either from the free list
   *  of by creating a new one.
   */
  unsigned int do_insert_layer (bool special = false);

  /**  
   *  @brief Insert a new layer at the given index
   *
   *  If the index is unused, create a new layer there.
   */
  void do_insert_layer (unsigned int index, bool special = false);

  /**
   *  @brief Implementation of prune_cell and prune_subcells
   */
  void do_prune_cell_or_subcell (cell_index_type id, int levels, bool subcells);

  /**
   *  @brief Implementation of prune_cells and some prune_subcells variants
   */
  void do_prune_cells_or_subcells (const std::set<cell_index_type> &ids, int levels, bool subcells);
};

/**
 *  @brief Collect memory statistics
 */
inline void
mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const Layout &x, bool no_self, void *parent)
{
  x.mem_stat (stat, purpose, cat, no_self, parent);
}

/**
 *  @brief A nice helper class that employs RAII for locking the layout against updates
 *
 *  If a layout shall be locked against internal updates temporarily, use this locker:
 *  @code
 *  Layout *ly = ...;
 *  {
 *    db::LayoutLocker locker (ly);
 *    //  the layout is not updated here
 *    ... modify the layout
 *  }
 *  //  now only the layout gets updated
 *  @endcode
 */
class DB_PUBLIC LayoutLocker
{
public:
  explicit LayoutLocker (db::Layout *layout = 0, bool no_update = false)
    : mp_layout (layout), m_no_update (no_update)
  {
    if (mp_layout) {
      mp_layout->start_changes ();
    }
  }

  ~LayoutLocker ()
  {
    set (0, false);
  }

  LayoutLocker (const LayoutLocker &other)
    : mp_layout (other.mp_layout), m_no_update (other.m_no_update)
  {
    if (mp_layout) {
      mp_layout->start_changes ();
    }
  }

  LayoutLocker &operator= (const LayoutLocker &other)
  {
    if (this == &other) {
      return *this;
    }

    set (other.mp_layout, other.m_no_update);
    return *this;
  }

private:
  db::Layout *mp_layout;
  bool m_no_update;

  void set (db::Layout *layout, bool no_update)
  {
    if (mp_layout) {
      if (m_no_update) {
        mp_layout->end_changes_no_update ();
      } else {
        mp_layout->end_changes ();
      }
    }
    mp_layout = layout;
    m_no_update = no_update;
    if (mp_layout) {
      mp_layout->start_changes ();
    }
  }

};

}

#endif


