
/*

  KLayout Layout Viewer
  Copyright (C) 2006-2016 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_extNetTracerDialog
#define HDR_extNetTracerDialog

#include "NetTracerDialog.h"
#include "NetTracerTechComponentEditor.h"

#include "extNetTracer.h"
#include "extNetTracerConfig.h"

#include "layBrowser.h"
#include "layPlugin.h"
#include "layViewObject.h"
#include "layMarker.h"
#include "layTechnology.h"

#include "tlObserver.h"

namespace lay
{
  class FileDialog;
}

namespace ext
{

class NetTracerTechnologyComponent;

class KLAYOUT_DLL NetTracerLayerExpressionInfo
{
public:
  NetTracerLayerExpressionInfo ();
  ~NetTracerLayerExpressionInfo ();
  NetTracerLayerExpressionInfo (const NetTracerLayerExpressionInfo &other);
  NetTracerLayerExpressionInfo &operator= (const NetTracerLayerExpressionInfo &other);

  bool operator== (const NetTracerLayerExpressionInfo &other) const
  {
    return m_expression == other.m_expression;
  }

  static NetTracerLayerExpressionInfo compile (const std::string &s);
  static NetTracerLayerExpressionInfo parse (tl::Extractor &ex);

  const std::string &to_string () const
  {
    return m_expression;
  }
  
  NetTracerLayerExpression *get (const db::Layout &layout, const NetTracerTechnologyComponent &tech) const;

private:
  std::string m_expression;
  db::LayerProperties m_a, m_b;
  NetTracerLayerExpressionInfo *mp_a, *mp_b;
  NetTracerLayerExpression::Operator m_op;

  void merge (NetTracerLayerExpression::Operator op, const NetTracerLayerExpressionInfo &other);
  static NetTracerLayerExpressionInfo parse_add (tl::Extractor &ex);
  static NetTracerLayerExpressionInfo parse_mult (tl::Extractor &ex);
  static NetTracerLayerExpressionInfo parse_atomic (tl::Extractor &ex);

  NetTracerLayerExpression *get (const db::Layout &layout, const NetTracerTechnologyComponent &tech, const std::set<std::string> &used_symbols) const;
  NetTracerLayerExpression *get_expr (const db::LayerProperties &lp, const db::Layout &layout, const NetTracerTechnologyComponent &tech, const std::set<std::string> &used_symbols) const;
};

class KLAYOUT_DLL NetTracerConnectionInfo
{
public:
  NetTracerConnectionInfo ();
  NetTracerConnectionInfo (const NetTracerLayerExpressionInfo &la, const NetTracerLayerExpressionInfo &lb);
  NetTracerConnectionInfo (const NetTracerLayerExpressionInfo &la, const NetTracerLayerExpressionInfo &via, const NetTracerLayerExpressionInfo &lb);

  NetTracerConnection get (const db::Layout &layout, const NetTracerTechnologyComponent &tech, NetTracerData &data) const;

  std::string to_string () const;
  void parse (tl::Extractor &ex);

  const NetTracerLayerExpressionInfo &layer_a () const 
  {
    return m_la;
  }

  void set_layer_a (const NetTracerLayerExpressionInfo &l) 
  {
    m_la = l;
  }

  const NetTracerLayerExpressionInfo &via_layer () const 
  {
    return m_via;
  }

  void set_via_layer (const NetTracerLayerExpressionInfo &l) 
  {
    m_via = l;
  }

  const NetTracerLayerExpressionInfo &layer_b () const 
  {
    return m_lb;
  }

  void set_layer_b (const NetTracerLayerExpressionInfo &l) 
  {
    m_lb = l;
  }

private:
  NetTracerLayerExpressionInfo m_la, m_via, m_lb;
};

class KLAYOUT_DLL NetTracerSymbolInfo
{
public:
  NetTracerSymbolInfo ();
  NetTracerSymbolInfo (const db::LayerProperties &symbol, const std::string &expression);

  std::string to_string () const;
  void parse (tl::Extractor &ex);

  const db::LayerProperties &symbol () const 
  {
    return m_symbol;
  }

  void set_symbol (const db::LayerProperties &s) 
  {
    m_symbol = s;
  }

  const std::string &expression () const 
  {
    return m_expression;
  }

  void set_expression (const std::string &e) 
  {
    m_expression = e;
  }

private:
  db::LayerProperties m_symbol;
  std::string m_expression;
};

class KLAYOUT_DLL Net
{
public:
  typedef std::vector <NetTracerShape>::const_iterator iterator;

  /**
   *  @brief Default constructor
   */
  Net ();

  /**
   *  @brief Constructor
   */
  Net (const NetTracer &tracer, const db::ICplxTrans &trans, const db::Layout &layout, db::cell_index_type cell_index, const std::string &layout_filename, const std::string &layout_name, const NetTracerData &data);

  /**
   *  @brief Iterate the shapes (begin)
   */
  iterator begin () const
  {
    return m_net_shapes.begin ();
  }

  /**
   *  @brief Iterate the shapes (end)
   */
  iterator end () const
  {
    return m_net_shapes.end ();
  }

  /**
   *  @brief Gets the number of shapes
   */
  size_t size () const
  {
    return m_net_shapes.size ();
  }

  /**
   *  @brief Gets the color in which the net is drawn
   */
  QColor color () const
  {
    return m_color;
  }

  /**
   *  @brief Sets the color in which the net is drawn
   */
  void set_color (QColor c) 
  {
    m_color = c;
  }

  /**
   *  @brief Get a name for the net
   *
   *  The name can be empty if not specific net name could be determined (i.e. from a label or property)
   */
  std::string name () const
  {
    return m_name;
  }

  /**
   *  @brief Set a name for the net
   */
  void set_name (const std::string &n)
  {
    m_name = n;
  }

  /**
   *  @brief Gets the database unit 
   */
  double dbu () const
  {
    return m_dbu;
  }

  /**
   *  @brief Returns true, if the net is incomplete
   *
   *  This flag is true if the extractor was aborted
   *  for example by the user.
   *  The shapes do not fully cover the net.
   */
  bool incomplete () const
  {
    return m_incomplete;
  }

  /**
   *  @brief Gets the file name
   */
  const std::string &layout_filename () const
  {
    return m_layout_filename;
  }

  /**
   *  @brief Gets the layout name
   */
  const std::string &layout_name () const
  {
    return m_layout_name;
  }

  /**
   *  @brief Gets the top cell name
   */
  const std::string &top_cell_name () const
  {
    return m_top_cell_name;
  }

  /**
   *  @brief Gets the cell name for a given cell index
   */
  const std::string &cell_name (db::cell_index_type cell_index) const;

  /**
   *  @brief Provides the 
   */
  db::LayerProperties representative_layer_for (unsigned int log_layer) const;

  /**
   *  @brief Provides a mapping for logical layers to original ones
   */
  db::LayerProperties layer_for (unsigned int log_layer) const;

  /**
   *  @brief Export the net to another layout/cell
   */
  std::vector<unsigned int> export_net (db::Layout &layout, db::Cell &export_cell);

  /**
   *  @brief Set the start search box for redo
   */
  void set_start_search_box (const db::DBox &p)
  {
    m_start_search_box = p;
  }

  /**
   *  @brief Gets the start search box
   */
  const db::DBox &start_search_box () const
  {
    return m_start_search_box;
  }

  /**
   *  @brief Set the stop search box for redo
   */
  void set_stop_search_box (const db::DBox &p)
  {
    m_stop_search_box = p;
  }

  /**
   *  @brief Gets the stop search box
   */
  const db::DBox &stop_search_box () const
  {
    return m_stop_search_box;
  }

  /**
   *  @brief Sets the "trace path" flag for redo
   */
  void set_trace_path_flag (bool tp) 
  {
    m_trace_path = tp;
  }

  /**
   *  @brief Gets the "trace path" flag
   */
  bool trace_path_flag () const
  {
    return m_trace_path;
  }

private:
  double m_dbu;
  std::string m_name;
  std::string m_layout_filename;
  std::string m_layout_name;
  std::string m_top_cell_name;
  bool m_incomplete;
  std::vector <NetTracerShape> m_net_shapes;
  db::Shapes m_shapes;
  std::map <unsigned int, std::pair <db::LayerProperties, db::LayerProperties> > m_layers;
  std::map <unsigned int, std::string> m_cell_names;
  QColor m_color;
  db::DBox m_start_search_box, m_stop_search_box;
  bool m_trace_path;

  void define_layer (unsigned int l, const db::LayerProperties &lp, const db::LayerProperties &lp_representative);
};

class NetTracerDialog
  : public lay::Browser,
    public lay::ViewService, 
    public Ui::NetTracerDialog,
    public tl::Observer
{
Q_OBJECT

public:
  NetTracerDialog (lay::MainWindow *main_window, lay::LayoutView *view);
  virtual ~NetTracerDialog ();

  virtual bool mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio);
  virtual bool mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio);
  virtual void menu_activated (const std::string &symbol);
  virtual lay::ViewService *view_service_interface ();
  virtual void deactivated ();
  virtual void activated ();
  virtual bool configure (const std::string &name, const std::string &value);

protected slots:
  void net_color_changed (QColor);
  void trace_net_button_clicked ();
  void trace_path_button_clicked ();
  void delete_button_clicked ();
  void clear_all_button_clicked ();
  void layer_stack_clicked ();
  void export_clicked ();
  void export_text_clicked ();
  void detailed_mode_clicked ();
  void sticky_mode_clicked ();
  void configure_clicked ();
  void item_selection_changed ();
  void item_double_clicked (QListWidgetItem *item);
  void redo_trace_clicked ();

private:
  std::vector <Net *> mp_nets;
  std::vector <lay::ShapeMarker *> mp_markers;
  unsigned int m_cv_index;
  int m_net_index;
  nt_window_type m_window;
  double m_window_dim;
  unsigned int m_max_marker_count;
  QColor m_marker_color;
  int m_marker_line_width;
  int m_marker_vertex_size;
  int m_marker_halo;
  int m_marker_dither_pattern;
  int m_marker_intensity;
  bool m_auto_color_enabled;
  lay::ColorPalette m_auto_colors;
  int m_auto_color_index;

  db::DPoint m_mouse_first_point;
  int m_mouse_state;
  std::string m_export_cell_name;
  lay::FileDialog *mp_export_file_dialog;
  std::string m_export_file_name;

  void update_highlights ();
  void adjust_view ();
  void clear_markers ();
  void clear_nets ();
  void update_list ();
  void update_info ();
  void signal_observed ();
  void release_mouse ();
  Net *do_trace (const db::DBox &start_search_box, const db::DBox &stop_search_box, bool trace_path);
};

class KLAYOUT_DLL NetTracerTechnologyComponent
  : public lay::TechnologyComponent
{
public:
  typedef std::vector<NetTracerConnectionInfo>::const_iterator const_iterator;
  typedef std::vector<NetTracerConnectionInfo>::iterator iterator;
  typedef std::vector<NetTracerSymbolInfo>::const_iterator const_symbol_iterator;
  typedef std::vector<NetTracerSymbolInfo>::iterator symbol_iterator;

  NetTracerTechnologyComponent ();
  NetTracerTechnologyComponent (const NetTracerTechnologyComponent &d);

  const_iterator begin () const
  {
    return m_connections.begin ();
  }

  iterator begin ()
  {
    return m_connections.begin ();
  }

  const_iterator end () const
  {
    return m_connections.end ();
  }

  iterator end ()
  {
    return m_connections.end ();
  }

  const_symbol_iterator begin_symbols () const
  {
    return m_symbols.begin ();
  }

  symbol_iterator begin_symbols ()
  {
    return m_symbols.begin ();
  }

  const_symbol_iterator end_symbols () const
  {
    return m_symbols.end ();
  }

  symbol_iterator end_symbols ()
  {
    return m_symbols.end ();
  }

  void clear ()
  {
    m_connections.clear ();
    m_symbols.clear ();
  }

  void erase (iterator p)
  {
    m_connections.erase (p);
  }

  void insert (iterator p, const NetTracerConnectionInfo &info)
  {
    m_connections.insert (p, info);
  }

  void add (const NetTracerConnectionInfo &info)
  {
    m_connections.push_back (info);
  }

  void erase_symbol (symbol_iterator p)
  {
    m_symbols.erase (p);
  }

  void insert_symbol (symbol_iterator p, const NetTracerSymbolInfo &info)
  {
    m_symbols.insert (p, info);
  }

  void add_symbol (const NetTracerSymbolInfo &info)
  {
    m_symbols.push_back (info);
  }

  size_t size () const
  {
    return m_connections.size ();
  }

  size_t symbols () const
  {
    return m_symbols.size ();
  }

  NetTracerData get (const db::Layout &layout) const;

  virtual lay::TechnologyComponentEditor *create_editor (QWidget *parent);

  lay::TechnologyComponent *clone () const
  {
    return new NetTracerTechnologyComponent (*this);
  }

private:
  std::vector<NetTracerConnectionInfo> m_connections;
  std::vector<NetTracerSymbolInfo> m_symbols;
};

class NetTracerTechComponentEditor
  : public lay::TechnologyComponentEditor,
    public Ui::NetTracerTechComponentEditor
{
Q_OBJECT

public:
  NetTracerTechComponentEditor (QWidget *parent);

  void commit ();
  void setup ();

public slots:
  void add_clicked ();
  void del_clicked ();
  void move_up_clicked ();
  void move_down_clicked ();
  void symbol_add_clicked ();
  void symbol_del_clicked ();
  void symbol_move_up_clicked ();
  void symbol_move_down_clicked ();

private:
  NetTracerTechnologyComponent m_data;

  void update ();
};

}

#endif

