
/*

  KLayout Layout Viewer
  Copyright (C) 2006-2017 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_layCellView
#define HDR_layCellView

#include "laybasicCommon.h"

#include <string>
#include <vector>

#include "tlObject.h"
#include "tlFileSystemWatcher.h"
#include "layTechnology.h"
#include "dbLayout.h"
#include "dbMetaInfo.h"
#include "dbReader.h"
#include "dbSaveLayoutOptions.h"
#include "dbLoadLayoutOptions.h"
#include "dbInstElement.h"
#include "gsi.h"

namespace lay 
{

class LayoutView;

/**
 *  @brief A layout handle
 *
 *  This object controls a layout object. A layout object can be
 *  identified through a name. Additionally, a reference count
 *  is maintained that controls when the layout object is deleted.
 */
class LAYBASIC_PUBLIC LayoutHandle
  : public tl::Object
{
public:
  /**
   *  @brief Creates a layout handle to the given object
   *
   *  This constructor creates a new handle to the given 
   *  layout object. The handle takes over the ownership over the
   *  layout object.
   *  The initial reference count is zero (see remove_ref).
   *  The filename is a string that is supposed to identify
   *  the layout further. It can be retrieved with the filename 
   *  method.
   */
  LayoutHandle (db::Layout *layout, const std::string &filename);

  /**
   *  @brief Destructor
   *
   *  The destructor will delete the layout object that
   *  was associated with this handle.
   */
  ~LayoutHandle ();

  /**
   *  @brief Renames the layout object
   *
   *  If "force" is set to true, the layout will be given that name, irregardless if
   *  the name already is being used. If "force" is false, a new unique name is created.
   */
  void rename (const std::string &name, bool force = false) throw (tl::Exception);

  /**
   *  @brief Gets the name of the handle
   */
  const std::string &name () const;

  /**
   *  @brief Gets the layout object that this handle points to
   */
  db::Layout &layout () const;

  /**
   *  @brief Sets the file name associated with this handle
   */
  void set_filename (const std::string &);

  /**
   *  @brief Gets the file name associated with this handle
   */
  const std::string &filename () const;

  /**
   *  @brief Gets the technology attached to this layout
   */
  const lay::Technology *technology () const;

  /**
   *  @brief Gets the technology name for this layout
   *
   *  An empty name indicates the default technology should be used.
   */
  const std::string &tech_name () const
  {
    return m_tech_name;
  }

  /**
   *  @brief Applies the given technology
   *
   *  This will set the technology to the new one and send the apply event.
   *  This event is sent always, even if the technology did not change.
   */
  void apply_technology (const std::string &tn);

  /**
   *  @brief Sets the technology name
   *
   *  If there is no technology with that name, the default technology
   *  will be used.
   */
  void set_tech_name (const std::string &tn);

  /**
   *  @brief Finds a layout object by name
   *
   *  @param name The name under which to find the layout object
   *  @return 0, if there is no layout object with this name. Otherwise a pointer to its handle
   */
  static LayoutHandle *find (const std::string &name);

  /**
   *  @brief Gets the names of all registered layout objects
   */
  static void get_names (std::vector <std::string> &names);

  /**
   *  @brief Gets the reference count
   */
  int get_ref_count () const
  {
    return m_ref_count;
  }

  /**
   *  @brief Adds a reference to the layout handle
   * 
   *  This method will increment the reference counter of this handle
   */
  void add_ref ();

  /**
   *  @brief Removes a reference to the layout handle
   *
   *  This method will decrement the reference counter. Once the 
   *  reference count reaches zero, the layout object and the
   *  handle is deleted.
   *  Upon initialization, the reference count is zero.
   *  Hint: it is generally not safe to access the handle after
   *  a remove_ref was issued.
   */
  void remove_ref ();

  /**
   *  @brief Returns true, if the layout is "dirty"
   *
   *  A layout is "dirty", if it needs to be saved. 
   *  It is set dirty if one of the signal handlers is triggered.
   */
  bool is_dirty () const
  {
    return m_dirty;
  }

  /**
   *  @brief Loads the layout
   *
   *  Load the layout from the file given in the constructor using the given layer map.
   *  The dirty flag is reset.
   *
   *  @param lmap The layer map specifying the layers to read
   *  @param technology The technology to use for layer map and other settings or empty for "default technology"
   *  @return The new layer map (can differ from the input since layers may be created)
   */
  db::LayerMap load (const db::LoadLayoutOptions &options, const std::string &technology);

  /**
   *  @brief Loads the layout
   *
   *  Load the layout from the file given in the constructor.
   *  The dirty flag is reset.
   *
   *  @return The new layer map
   */
  db::LayerMap load ();

  /**
   *  @brief Saves the layout
   *
   *  Save the layout under the given file name and with the given options.
   *  If update is true, this method updates the cell view's filename, title, save options and dirty flag.
   */
  void save_as (const std::string &filename, tl::OutputStream::OutputStreamMode om, const db::SaveLayoutOptions &options, bool update = true);

  /**
   *  @brief Sets the save options and a flag indicating whether they are valid
   *
   *  This method is mainly used by the session restore feature to restore the handle's state.
   */
  void set_save_options (const db::SaveLayoutOptions &options, bool valid);

  /**
   *  @brief Gets the current saving options
   *
   *  The saving options are set by the last save_as method call.
   */
  const db::SaveLayoutOptions &save_options () const
  {
    return m_save_options;
  }

  /**
   *  @brief Gets a flag indicating whether the save options are valid
   *
   *  The save options are valid once the layout has been saved with specific
   *  options using "save_as" with the "update" options.
   */
  bool save_options_valid () const
  {
    return m_save_options_valid;
  }

  /**
   *  @brief Gets the current reader options
   *
   *  The reader options are set by the load method call.
   */
  const db::LoadLayoutOptions &load_options () const
  {
    return m_load_options;
  }

  /**
   *  @brief An event indicating that the technology has changed
   *  This event is triggered if the technology was changed.
   */
  tl::Event technology_changed_event;

  /**
   *  @brief An event indicating that a technology shall be applied
   *  This event is triggered to make the listeners apply a new technology
   *  to the layout.
   */
  tl::Event apply_technology_event;

  /**
   *  @brief An event indicating that a technology shall be applied
   *  This event is triggered to make the listeners apply a new technology
   *  to the layout. This version supplies a sender pointer.
   */
  tl::event<lay::LayoutHandle *> apply_technology_with_sender_event;

  /**
   *  @brief An event handler for a layout change
   *  This handler is attached to a layout changed event and will invalidate the handle.
   */
  void layout_changed ();

  /**
   *  @brief Gets the file system watcher that delivers events when one of the layouts gets updated
   */
  static tl::FileSystemWatcher &file_watcher ();

private:
  db::Layout *mp_layout;
  int m_ref_count;
  std::string m_name;
  std::string m_filename;
  std::string m_tech_name;
  bool m_dirty;
  db::SaveLayoutOptions m_save_options;
  bool m_save_options_valid;
  db::LoadLayoutOptions m_load_options;

  static std::map <std::string, LayoutHandle *> ms_dict;
  static tl::FileSystemWatcher *mp_file_watcher;
};

/**
 *  @brief A layout handle reference
 *
 *  This class encapsulates a reference to a layout handle.
 *  The main purpose for this class is to automate the reference
 *  counting on the handle.
 */
class LAYBASIC_PUBLIC LayoutHandleRef 
{
public:
  LayoutHandleRef ();
  LayoutHandleRef (LayoutHandle *h);
  LayoutHandleRef (const LayoutHandleRef &r);
  ~LayoutHandleRef ();

  LayoutHandleRef &operator= (const LayoutHandleRef &r);
  
  bool operator== (const LayoutHandleRef &r) const;

  bool operator!= (const LayoutHandleRef &r) const
  {
    return !operator== (r);
  }

  LayoutHandle *operator-> () const;

  LayoutHandle *get () const;
  void set (LayoutHandle *h);

private:
  LayoutHandle *mp_handle;
};

/**
 *  @brief A "cell view" reference
 *
 *  A cell view reference points to a certain cell within a certain layout.
 *  The layout pointer can be 0, indicating that it is invalid.
 *  Also, the cell view describes a cell within that layout. The cell
 *  is addressed by an cell_index or a cell pointer. 
 *  The cell is not only identified by it's index or pointer but as well 
 *  by the path leading to that cell. This path describes how to find the
 *  cell in the context of parent cells. 
 *  The path is in fact composed in twofold: once in an unspecific fashion,
 *  just describing which parent cells are used. The target of this path
 *  is called the context cell. It is accessible by the ctx_cell_index
 *  or ctx_cell method.
 *  Additionally the path may further identify a certain instance of a certain
 *  subcell in the context cell. This is done through a set of db::InstElement
 *  objects. The target of this context path is the actual cell addressed by the
 *  cellview.
 *  In the viewer, the target cell is shown in the context of the context cell.
 *  The hierarchy levels are counted from the context cell, which is on level 0.
 *  If the context path is empty, the context cell is identical with the target cell.
 */

class LAYBASIC_PUBLIC CellView
  : public tl::Object
{
public:
  typedef db::cell_index_type cell_index_type;
  typedef std::vector <cell_index_type> unspecific_cell_path_type;
  typedef std::vector <db::InstElement> specific_cell_path_type;

  /**
   *  @brief Constructor: create an invalid cellview
   */
  CellView ();

  /**
   *  @brief Equality: compares the cell the cv points to, not the path
   */
  bool operator== (const CellView &cv) const;

  /**
   *  @brief Inequality
   */
  bool operator!= (const CellView &cv) const
  {
    return !operator== (cv);
  }

  /**
   *  @brief Test if the cv points to a valid cell
   */
  bool is_valid () const;

  /**
   *  @brief Return the layout handle
   */
  lay::LayoutHandle *operator-> () const
  {
    return m_layout_href.get ();
  }

  /**
   *  @brief Return the layout handle (not via operator->)
   */
  lay::LayoutHandle *handle () const
  {
    return m_layout_href.get ();
  }

  /**
   *  @brief Set the unspecific part of the path explicitly
   *
   *  Setting the unspecific part will clear the context part and
   *  update the context and target cell.
   */
  void set_unspecific_path (const unspecific_cell_path_type &p);

  /**
   *  @brief Set the context part of the path explicitly
   *
   *  This method assumes that the unspecific part of the path 
   *  is established already and that the context part starts
   *  from the context cell.
   */
  void set_specific_path (const specific_cell_path_type &p);

  /**
   *  @brief Set the path to the given cell
   *
   *  This method will construct any path to this cell, not a 
   *  particular one. It will clear the context part of the path
   *  and update the context and target cell.
   */
  void set_cell (cell_index_type index);

  /**
   *  @brief Set the cell by name
   *
   *  If the name is not a valid one, the cellview will become
   *  invalid.
   *  This method will construct any path to this cell, not a 
   *  particular one. It will clear the context part of the path
   *  and update the context and target cell.
   */
  void set_cell (const std::string &name);

  /**
   *  @brief Reset the cell 
   *
   *  The cellview will become invalid. The layout object will
   *  still be attached to the cellview.
   */
  void reset_cell ();

  /**
   *  @brief Set the layout handle
   *
   *  Connect the cellview with a certain layout.
   *  This will reset the target and context cell.
   */
  void set (lay::LayoutHandle *handle);

  /**
   *  @brief Get the context cell pointer
   */
  db::Cell *ctx_cell () const
  {
    return mp_ctx_cell;
  }

  /**
   *  @brief Get the context cell index
   */
  cell_index_type ctx_cell_index () const
  {
    return m_ctx_cell_index;
  }

  /**
   *  @brief Get the target cell pointer
   */
  db::Cell *cell () const
  {
    return mp_cell;
  }

  /**
   *  @brief Get the target cell index
   */
  cell_index_type cell_index () const
  {
    return m_cell_index;
  }

  /**
   *  @brief Get the cell's combined path in an unspecific form
   */
  unspecific_cell_path_type combined_unspecific_path () const;

  /**
   *  @brief Get the cell's unspecific part of the path
   */
  const unspecific_cell_path_type &unspecific_path () const
  {
    return m_unspecific_path;
  }

  /**
   *  @brief Get the cell's unspecific part of the path
   */
  const specific_cell_path_type &specific_path () const
  {
    return m_specific_path;
  }

  /**
   *  @brief Retrive the accumulated transformation induced by the context part of the path
   */
  db::ICplxTrans context_trans () const;

  /**
   *  @brief Deep copy of the cellview
   *
   *  This method performs a deep copy on the cellview.
   *  A layout must be set already. Rather the creating another reference to the layout
   *  (which is done on operator= for example), this method copies the content of the 
   *  source layout to the current one and transfers cell path and other parameters.
   *
   *  @param manager The database object manager that the new layout is put under
   */
  CellView deep_copy (db::Manager *manager) const;

private:
  lay::LayoutHandleRef m_layout_href;
  db::Cell *mp_ctx_cell;
  cell_index_type m_ctx_cell_index;
  db::Cell *mp_cell;
  cell_index_type m_cell_index;
  unspecific_cell_path_type m_unspecific_path;
  specific_cell_path_type m_specific_path;
};

/**
 *  @brief A cellview reference
 *
 *  This object acts like a proxy to a lay::CellView object. It is connected to a cellview
 *  and a LayoutView and upon changes, the LayoutView will be configured accordingly.
 */
class LAYBASIC_PUBLIC CellViewRef
  : public gsi::ObjectBase
{
public:
  typedef CellView::unspecific_cell_path_type unspecific_cell_path_type;
  typedef CellView::specific_cell_path_type specific_cell_path_type;
  typedef CellView::cell_index_type cell_index_type;

  /**
   *  @brief Default constructor
   *  This constructor creates an invalid cellview reference
   */
  CellViewRef ();

  /**
   *  @brief Constructor
   *  @param cv The reference to the target cellview
   *  @param view The reference to the layout view
   */
  CellViewRef (lay::CellView *cv, lay::LayoutView *view);

  /**
   *  @brief Gets the cellview index of this reference
   *  If the cellview is not valid, -1 will be returned.
   */
  int index () const;

  /**
   *  @brief Gets the LayoutView the reference is pointing to
   */
  lay::LayoutView *view ();

  /**
   *  @brief Equality: Gives true, if the cellviews are identical
   */
  bool operator== (const CellView &cv) const;

  /**
   *  @brief Inequality
   */
  bool operator!= (const CellView &cv) const
  {
    return !operator== (cv);
  }

  /**
   *  @brief Equality: Gives true, if the references point to the same cellview
   */
  bool operator== (const CellViewRef &cv) const
  {
    return mp_cv.get () == cv.mp_cv.get ();
  }

  /**
   *  @brief Inequality
   */
  bool operator!= (const CellViewRef &cv) const
  {
    return !operator== (cv);
  }

  /**
   *  @brief Test if the cv points to a valid cell and is valid otherwise
   */
  bool is_valid () const;

  /**
   *  @brief Returns the layout handle
   */
  lay::LayoutHandle *operator-> () const;

  /**
   *  @brief Return the layout handle (not via operator->)
   */
  lay::LayoutHandle *handle () const
  {
    return operator-> ();
  }

  /**
   *  @brief Sets the name of the cellview
   *
   *  This equivalent to calling Layout#rename_cellview.
   *  The name is made unique, hence the final name may
   *  differ from the one given.
   */
  void set_name (const std::string &name);

  /**
   *  @brief Set the unspecific part of the path explicitly
   *
   *  Setting the unspecific part will clear the context part and
   *  update the context and target cell.
   */
  void set_unspecific_path (const unspecific_cell_path_type &p);

  /**
   *  @brief Set the context part of the path explicitly
   *
   *  This method assumes that the unspecific part of the path
   *  is established already and that the context part starts
   *  from the context cell.
   */
  void set_specific_path (const specific_cell_path_type &p);

  /**
   *  @brief Set the path to the given cell
   *
   *  This method will construct any path to this cell, not a
   *  particular one. It will clear the context part of the path
   *  and update the context and target cell.
   */
  void set_cell (cell_index_type index);

  /**
   *  @brief Set the cell by name
   *
   *  If the name is not a valid one, the cellview will become
   *  invalid.
   *  This method will construct any path to this cell, not a
   *  particular one. It will clear the context part of the path
   *  and update the context and target cell.
   */
  void set_cell (const std::string &name);

  /**
   *  @brief Resets the cell
   */
  void reset_cell ();

  /**
   *  @brief Get the context cell pointer
   *  An invalid cellview reference will return a null pointer.
   */
  db::Cell *ctx_cell () const;

  /**
   *  @brief Get the context cell index
   */
  cell_index_type ctx_cell_index () const
  {
    db::Cell *c = ctx_cell ();
    return c ? c->cell_index () : 0;
  }

  /**
   *  @brief Get the target cell pointer
   *  An invalid cellview reference will return a null pointer.
   */
  db::Cell *cell () const;

  /**
   *  @brief Get the target cell index
   */
  cell_index_type cell_index () const
  {
    db::Cell *c = cell ();
    return c ? c->cell_index () : 0;
  }

  /**
   *  @brief Get the cell's combined path in an unspecific form
   */
  unspecific_cell_path_type combined_unspecific_path () const;

  /**
   *  @brief Get the cell's unspecific part of the path
   */
  const unspecific_cell_path_type &unspecific_path () const;

  /**
   *  @brief Get the cell's unspecific part of the path
   */
  const specific_cell_path_type &specific_path () const;

  /**
   *  @brief Retrive the accumulated transformation induced by the context part of the path
   */
  db::ICplxTrans context_trans () const;

private:
  tl::weak_ptr<lay::CellView> mp_cv;
  tl::weak_ptr<lay::LayoutView> mp_view;
};

}

#endif

