// OpenSTA, Static Timing Analyzer
// Copyright (c) 2026, Parallax Software, Inc.
// 
// 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 3 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, see <https://www.gnu.org/licenses/>.
// 
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
// 
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 
// This notice may not be removed or altered from any source distribution.

%module search

%include "std_string.i" 

%{

#include <string>

#include "Units.hh"
#include "PathGroup.hh"
#include "Search.hh"
#include "search/Levelize.hh"
#include "search/ReportPath.hh"
#include "PathExpanded.hh"
#include "Bfs.hh"
#include "Scene.hh"
#include "Sta.hh"
#include "StaConfig.hh"

using namespace sta;

%}

////////////////////////////////////////////////////////////////
//
// Empty class definitions to make swig happy.
// Private constructor/destructor so swig doesn't emit them.
//
////////////////////////////////////////////////////////////////

class VertexPathIterator
{
private:
  VertexPathIterator();
  ~VertexPathIterator();
};

class Path
{
private:
  Path();
  ~Path();
};

class PathEnd
{
private:
  PathEnd();
  ~PathEnd();
};

%inline %{

using std::string;

int group_path_count_max = PathGroup::group_path_count_max;

////////////////////////////////////////////////////////////////

// Initialize sta after delete_all_memory.
void
init_sta()
{
  initSta();
}

// Clear all state except network.
void
clear_sta()
{
  Sta::sta()->clear();
}

void
make_sta(Tcl_Interp *interp)
{
  Sta *sta = new Sta;
  Sta::setSta(sta);
  sta->makeComponents();
  sta->setTclInterp(interp);
}

Tcl_Interp *
tcl_interp()
{
  return Sta::sta()->tclInterp();
}

void
clear_network()
{
  Sta *sta = Sta::sta();
  sta->network()->clear();
}

void
delete_all_memory()
{
  deleteAllMemory();
}

////////////////////////////////////////////////////////////////

void
find_timing_cmd(bool full)
{
  Sta::sta()->updateTiming(full);
}

void
arrivals_invalid()
{
  Sta *sta = Sta::sta();
  sta->arrivalsInvalid();
}

PinSet
endpoints()
{
  return Sta::sta()->endpointPins();
}

size_t
endpoint_count()
{
  return Sta::sta()->endpointPins().size();
}

void
find_requireds()
{
  Sta::sta()->findRequireds();
}

float
total_negative_slack_cmd(const MinMax *min_max)
{
  Sta *sta = Sta::sta();
  return delayAsFloat(sta->totalNegativeSlack(min_max), min_max, sta);
}

float
total_negative_slack_scene_cmd(const Scene *scene,
                               const MinMax *min_max)
{
  Sta *sta = Sta::sta();
  return delayAsFloat(sta->totalNegativeSlack(scene, min_max), min_max, sta);
}

float
worst_slack_cmd(const MinMax *min_max)
{
  Sta *sta = Sta::sta();
  Slack worst_slack;
  Vertex *worst_vertex;
  sta->worstSlack(min_max, worst_slack, worst_vertex);
  return delayAsFloat(worst_slack, min_max, sta);
}

Vertex *
worst_slack_vertex(const MinMax *min_max)
{
  Slack worst_slack;
  Vertex *worst_vertex;
  Sta::sta()->worstSlack(min_max, worst_slack, worst_vertex);
  return worst_vertex;;
}

float
worst_slack_scene(const Scene *scene,
                   const MinMax *min_max)
{
  Sta *sta = Sta::sta();
  Slack worst_slack;
  Vertex *worst_vertex;
  sta->worstSlack(scene, min_max, worst_slack, worst_vertex);
  return delayAsFloat(worst_slack, min_max, sta);
}

Path *
vertex_worst_arrival_path(Vertex *vertex,
                          const MinMax *min_max)
{
  Sta *sta = Sta::sta();
  sta->ensureLibLinked();
  return sta->vertexWorstArrivalPath(vertex, min_max);
}

Path *
vertex_worst_arrival_path_rf(Vertex *vertex,
                             const RiseFall *rf,
                             MinMax *min_max)
{
  Sta *sta = Sta::sta();
  sta->ensureLibLinked();
  return sta->vertexWorstArrivalPath(vertex, rf, min_max);
}

Path *
vertex_worst_slack_path(Vertex *vertex,
                        const MinMax *min_max)
{
  Sta *sta = Sta::sta();
  sta->ensureLibLinked();
  return sta->vertexWorstSlackPath(vertex, min_max);
}

float
endpoint_slack(const Pin *pin,
               const char *path_group_name,
               const MinMax *min_max)
{
  Sta *sta = Sta::sta();
  sta->ensureLibLinked();
  if (sta->isGroupPathName(path_group_name, sta->cmdSdc())) {
    Slack slack = sta->endpointSlack(pin, std::string(path_group_name), min_max);
    return sta->units()->timeUnit()->staToUser(delayAsFloat(slack, min_max, sta));
  }
  else {
    sta->report()->error(1577, "{} is not a known path group name.",
                         path_group_name);
    return INF;
  }
}

StringSeq
path_group_names()
{
  Sta *sta = Sta::sta();
  return sta->pathGroupNames(sta->cmdSdc());
}

int
tag_group_count()
{
  return Sta::sta()->tagGroupCount();
}

void
report_tag_groups()
{
  Sta::sta()->search()->reportTagGroups();
}

void
report_tag_arrivals_cmd(Vertex *vertex,
                        bool report_tag_index)
{
  Sta::sta()->search()->reportArrivals(vertex, report_tag_index);
}

void
report_path_count_histogram()
{
  Sta::sta()->search()->reportPathCountHistogram();
}

int
tag_count()
{
  return Sta::sta()->tagCount();
}

void
report_tags()
{
  Sta::sta()->search()->reportTags();
}

void
report_clk_infos()
{
  Sta::sta()->search()->reportClkInfos();
}

int
clk_info_count()
{
  return Sta::sta()->clkInfoCount();
}

int
path_count()
{
  return Sta::sta()->pathCount();
}

int
endpoint_violation_count(const MinMax *min_max)
{
  return  Sta::sta()->endpointViolationCount(min_max);
}

void
report_loops()
{
  Sta *sta = Sta::sta();
  Report *report = sta->report();
  for (GraphLoop *loop : sta->graphLoops()) {
    loop->report(sta);
    report->reportLine("");
  }
}

char
pin_sim_logic_value(const Pin *pin)
{
  Sta *sta = Sta::sta();
  const Mode *sdc = sta->cmdMode();
  return logicValueString(sta->simLogicValue(pin, sdc));
}

InstanceSeq
slow_drivers(int count)
{
  return Sta::sta()->slowDrivers(count);
}

bool
is_ideal_clock(const Pin *pin)
{
  Sta *sta = Sta::sta();
  const Mode *mode = sta->cmdMode();
  return sta->isIdealClock(pin, mode);
}

////////////////////////////////////////////////////////////////

PathEndSeq
find_path_ends(ExceptionFrom *from,
               ExceptionThruSeq *thrus,
               ExceptionTo *to,
               bool unconstrained,
               SceneSeq scenes,
               const MinMaxAll *delay_min_max,
               int group_path_count,
               int endpoint_path_count,
               bool unique_pins,
               bool unique_edges,
               float slack_min,
               float slack_max,
               bool sort_by_slack,
               StringSeq path_groups,
               bool setup,
               bool hold,
               bool recovery,
               bool removal,
               bool clk_gating_setup,
               bool clk_gating_hold)
{
  Sta *sta = Sta::sta();
  PathEndSeq ends = sta->findPathEnds(from, thrus, to, unconstrained,
                                      scenes, delay_min_max,
                                      group_path_count, endpoint_path_count,
                                      unique_pins, unique_edges,
                                      slack_min, slack_max,
                                      sort_by_slack, path_groups,
                                      setup, hold,
                                      recovery, removal,
                                      clk_gating_setup, clk_gating_hold);
  return ends;
}

////////////////////////////////////////////////////////////////

void
report_path_end(PathEnd *end)
{
  Sta::sta()->reportPathEnd(end);
}

void
set_report_path_format(ReportPathFormat format)
{
  Sta::sta()->setReportPathFormat(format);
}
    
void
set_report_path_field_order(const StringSeq &field_names)
{
  Sta::sta()->setReportPathFieldOrder(field_names);
}

void
set_report_path_fields(bool report_input_pin,
                       bool report_hier_pins,
                       bool report_net,
                       bool report_cap,
                       bool report_slew,
                       bool report_fanout,
                       bool report_variation,
                       bool report_src_attr)
{
  Sta::sta()->setReportPathFields(report_input_pin,
                                  report_hier_pins,
                                  report_net,
                                  report_cap,
                                  report_slew,
                                  report_fanout,
                                  report_variation,
                                  report_src_attr);
}

void
set_report_path_field_properties(const char *field_name,
                                 const char *title,
                                 int width,
                                 bool left_justify)
{
  Sta *sta = Sta::sta();
  ReportField *field = sta->findReportPathField(field_name);
  if (field)
    field->setProperties(title, width, left_justify);
  else
    sta->report()->warn(1575, "unknown report path field {}", field_name);
}

void
set_report_path_digits(int digits)
{
  Sta::sta()->setReportPathDigits(digits);
}

void
set_report_path_no_split(bool no_split)
{
  Sta::sta()->setReportPathNoSplit(no_split);
}

void
report_path_cmd(Path *path)
{
  Sta::sta()->reportPath(path);
}

void
report_path_ends(PathEndSeq *ends)
{
  Sta::sta()->reportPathEnds(ends);
  delete ends;
}

////////////////////////////////////////////////////////////////

void
report_arrival_wrt_clks(const Pin *pin,
                        const Scene *scene,
                        bool report_variance,
                        int digits)
{
  Sta::sta()->reportArrivalWrtClks(pin, scene, report_variance, digits);
}

void
report_required_wrt_clks(const Pin *pin,
                         const Scene *scene,
                         bool report_variance,
                         int digits)
{
  Sta::sta()->reportRequiredWrtClks(pin, scene, report_variance, digits);
}

void
report_slack_wrt_clks(const Pin *pin,
                      const Scene *scene,
                      bool report_variance,
                      int digits)
{
  Sta::sta()->reportSlackWrtClks(pin, scene, report_variance, digits);
}

////////////////////////////////////////////////////////////////

void
report_clk_skew(ConstClockSeq clks,
                const SceneSeq scenes,
                const SetupHold *setup_hold,
                bool include_internal_latency,
                int digits)
{
  Sta::sta()->reportClkSkew(clks, scenes, setup_hold,
                            include_internal_latency, digits);
}

float
worst_clk_skew_cmd(const SetupHold *setup_hold,
                   bool include_internal_latency)
{
  Sta *sta = Sta::sta();
  Delay skew = sta->findWorstClkSkew(setup_hold, include_internal_latency);
  return delayAsFloat(skew, MinMax::max(), sta);
}

////////////////////////////////////////////////////////////////

void
report_clk_latency(ConstClockSeq clks,
                   const SceneSeq scenes,
                   bool include_internal_latency,
                   int digits)
{
  Sta::sta()->reportClkLatency(clks, scenes, include_internal_latency, digits);
}

////////////////////////////////////////////////////////////////

void
report_min_pulse_width_checks(const Net *net,
                              size_t max_count,
                              bool violations,
                              bool verbose,
                              const SceneSeq scenes)
{
  return Sta::sta()->reportMinPulseWidthChecks(net, max_count, violations,
                                               verbose, scenes);
}

////////////////////////////////////////////////////////////////

void
report_min_period_checks(const Net *net,
                         size_t max_count,
                         bool violations,
                         bool verbose,
                         const SceneSeq scenes)
{
  Sta::sta()->reportMinPeriodChecks(net, max_count, violations, verbose, scenes);
}

////////////////////////////////////////////////////////////////

void
report_max_skew_checks(const Net *net,
                       size_t max_count,
                       bool violators,
                       bool verbose,
                       const SceneSeq scenes)
{
  Sta::sta()->reportMaxSkewChecks(net, max_count, violators, verbose, scenes);
}

////////////////////////////////////////////////////////////////

float
find_clk_min_period(const Clock *clk,
                    bool ignore_port_paths)
{
  return Sta::sta()->findClkMinPeriod(clk, ignore_port_paths);
}

////////////////////////////////////////////////////////////////

void
report_slew_checks(const Net *net,
                   size_t max_count,
                   bool violators,
                   bool verbose,
                   const SceneSeq scenes,
                   const MinMax *min_max)
{
  return Sta::sta()->reportSlewChecks(net, max_count, violators, verbose,
                                      scenes, min_max);
}

size_t
max_slew_violation_count()
{
  return Sta::sta()->maxSlewViolationCount();
}

float
max_slew_check_slack()
{
  Sta *sta = Sta::sta();
  const Pin *pin;
  Slew slew;
  float slack;
  float limit;
  sta->maxSlewCheck(pin, slew, slack, limit);
  return sta->units()->timeUnit()->staToUser(slack);
}

float
max_slew_check_limit()
{
  Sta *sta = Sta::sta();
  const Pin *pin;
  Slew slew;
  float slack;
  float limit;
  sta->maxSlewCheck(pin, slew, slack, limit);
  return sta->units()->timeUnit()->staToUser(limit);
}

////////////////////////////////////////////////////////////////

void
report_fanout_checks(const Net *net,
                     size_t max_count,
                     bool violators,
                     bool verbose,
                     const SceneSeq scenes,
                     const MinMax *min_max)
{
  Sta *sta = Sta::sta();
  return sta->reportFanoutChecks(net, max_count, violators, verbose,
                                 scenes, min_max);
}

size_t
max_fanout_violation_count()
{
  Sta *sta = Sta::sta();
  return sta->fanoutViolationCount(MinMax::max(), sta->modes());
}

float
max_fanout_min_slack()
{
  Sta *sta = Sta::sta();
  const Pin *pin;
  float fanout, limit, slack;
  const Mode *mode; 
  sta->maxFanoutMinSlackPin(sta->modes(), pin, fanout, limit, slack, mode);
  return slack;;
}

// Deprecated 11/16/2025
float
max_fanout_check_slack()
{
  return max_fanout_min_slack();
}

float
max_fanout_min_slack_limit()
{
  Sta *sta = Sta::sta();
  const Pin *pin;
  float fanout, limit, slack;
  const Mode *mode;
  sta->maxFanoutMinSlackPin(sta->modes(), pin, fanout, limit, slack, mode);
  return limit;;
}

// Deprecated 11/16/2025
float
max_fanout_check_limit()
{
  return max_fanout_min_slack_limit();
}

////////////////////////////////////////////////////////////////

void
report_capacitance_checks(const Net *net,
                          size_t max_count,
                          bool violators,
                          bool verbose,
                          const SceneSeq scenes,
                          const MinMax *min_max)
{
  Sta::sta()->reportCapacitanceChecks(net, max_count, violators, verbose,
                                      scenes, min_max);
}

size_t
max_capacitance_violation_count()
{
  return Sta::sta()->maxCapacitanceViolationCount();
}

float
max_capacitance_check_slack()
{
  Sta *sta = Sta::sta();
  const Pin *pin;
  float capacitance;
  float slack;
  float limit;
  sta->maxCapacitanceCheck(pin, capacitance, slack, limit);
  return sta->units()->capacitanceUnit()->staToUser(slack);
}

float
max_capacitance_check_limit()
{
  Sta *sta = Sta::sta();
  const Pin *pin;
  float capacitance;
  float slack;
  float limit;
  sta->maxCapacitanceCheck(pin, capacitance, slack, limit);
  return sta->units()->capacitanceUnit()->staToUser(limit);
}

////////////////////////////////////////////////////////////////

void
write_timing_model_cmd(const char *lib_name,
                       const char *cell_name,
                       const char *filename,
                       const Scene *scene)
{
  Sta::sta()->writeTimingModel(lib_name, cell_name, filename, scene);
}

////////////////////////////////////////////////////////////////

void
define_scene_cmd(const char *name,
                 const char *mode_name,
                 const StringSeq liberty_min_files,
                 const StringSeq liberty_max_files,
                 const char *spef_min_file,
                 const char *spef_max_file)
{
  Sta *sta = Sta::sta();
  sta->makeScene(name, mode_name,
                 liberty_min_files, liberty_max_files,
                 spef_min_file, spef_max_file);
}

void
define_scenes_cmd(const StringSeq &scene_names)
{
  Sta *sta = Sta::sta();
  sta->makeScenes(scene_names);
}

Scene *
cmd_scene()
{
  return Sta::sta()->cmdScene();
}

void
set_cmd_scene(Scene *scene)
{
  Sta::sta()->setCmdScene(scene);
}

const SceneSeq
scenes()
{
  Sta *sta = Sta::sta();
  return sta->scenes();
}

Scene *
find_scene(const char *scene_name)
{
  return Sta::sta()->findScene(scene_name);
}

SceneSeq
find_scenes_matching(std::string scene_name)
{
  return Sta::sta()->findScenes(scene_name);
}

SceneSeq
find_mode_scenes_matching(std::string scene_name,
                          ModeSeq modes)
{
  return Sta::sta()->findScenes(scene_name, modes);
}

bool
multi_scene()
{
  return Sta::sta()->multiScene();
}

ClockSeq
get_scene_clocks(SceneSeq scenes)
{
  ClockSeq clks;
  ModeSet modes = Scene::modeSet(scenes);
  for (const Mode *mode : modes) {
    for (Clock *clk : mode->sdc()->clocks())
      clks.push_back(clk);
  }
  return clks;
}

////////////////////////////////////////////////////////////////

std::string
cmd_mode_name()
{
  return Sta::sta()->cmdMode()->name();
}

void
set_mode_cmd(std::string mode_name)
{
  Sta::sta()->setCmdMode(mode_name);
}

ModeSeq
find_modes(std::string mode_name)
{
  return Sta::sta()->findModes(mode_name);
}

////////////////////////////////////////////////////////////////

CheckErrorSeq &
check_timing_cmd(bool no_input_delay,
                 bool no_output_delay,
                 bool reg_multiple_clks,
                 bool reg_no_clks,
                 bool unconstrained_endpoints,
                 bool loops,
                 bool generated_clks)
{
  Sta *sta = Sta::sta();
  const Mode *sdc = sta->cmdMode();
  return sta->checkTiming(sdc, no_input_delay, no_output_delay,
                          reg_multiple_clks, reg_no_clks,
                          unconstrained_endpoints,
                          loops, generated_clks);
}

////////////////////////////////////////////////////////////////

PinSet
find_fanin_pins(PinSeq *to,
                bool flat,
                bool startpoints_only,
                int inst_levels,
                int pin_levels,
                bool thru_disabled,
                bool thru_constants)
{
  Sta *sta = Sta::sta();
  const Mode *mode = sta->cmdMode();
  PinSet fanin = sta->findFaninPins(to, flat, startpoints_only,
                                    inst_levels, pin_levels,
                                    thru_disabled, thru_constants, mode);
  delete to;
  return fanin;
}

InstanceSet
find_fanin_insts(PinSeq *to,
                 bool flat,
                 bool startpoints_only,
                 int inst_levels,
                 int pin_levels,
                 bool thru_disabled,
                 bool thru_constants)
{
  Sta *sta = Sta::sta();
  const Mode *mode = sta->cmdMode();
  InstanceSet fanin = sta->findFaninInstances(to, flat, startpoints_only,
                                              inst_levels, pin_levels,
                                              thru_disabled, thru_constants, mode);
  delete to;
  return fanin;
}

PinSet
find_fanout_pins(PinSeq *from,
                 bool flat,
                 bool endpoints_only,
                 int inst_levels,
                 int pin_levels,
                 bool thru_disabled,
                 bool thru_constants)
{
  Sta *sta = Sta::sta();
  const Mode *mode = sta->cmdMode();
  PinSet fanout = sta->findFanoutPins(from, flat, endpoints_only,
                                      inst_levels, pin_levels,
                                      thru_disabled, thru_constants, mode);
  delete from;
  return fanout;
}

InstanceSet
find_fanout_insts(PinSeq *from,
                  bool flat,
                  bool endpoints_only,
                  int inst_levels,
                  int pin_levels,
                  bool thru_disabled,
                  bool thru_constants)
{
  Sta *sta = Sta::sta();
  const Mode *mode = sta->cmdMode();
  InstanceSet fanout = sta->findFanoutInstances(from, flat, endpoints_only,
                                                inst_levels, pin_levels,
                                                thru_disabled, thru_constants, mode);
  delete from;
  return fanout;
}

////////////////////////////////////////////////////////////////
//
// Variables
//
////////////////////////////////////////////////////////////////

bool
crpr_enabled()
{
  return Sta::sta()->crprEnabled();
}

void
set_crpr_enabled(bool enabled)
{
  return Sta::sta()->setCrprEnabled(enabled);
}

const char *
crpr_mode()
{
  switch (Sta::sta()->crprMode()) {
  case CrprMode::same_transition:
    return "same_transition";
  case CrprMode::same_pin:
    return "same_pin";
  default:
    return "";
  }
}

void
set_crpr_mode(const char *mode)
{
  Sta *sta = Sta::sta();
  if (stringEq(mode, "same_pin"))
    sta->setCrprMode(CrprMode::same_pin);
  else if (stringEq(mode, "same_transition"))
    sta->setCrprMode(CrprMode::same_transition);
  else
    sta->report()->error(1573, "unknown common clk pessimism mode.");
}

const char *
pocv_mode()
{
  return pocvModeName(Sta::sta()->pocvMode());
}

void
set_pocv_mode(const char *mode_name)
{
  Sta *sta = Sta::sta();
  PocvMode mode = findPocvMode(mode_name);
  sta->setPocvMode(mode);
}

float
pocv_quantile()
{
  return Sta::sta()->pocvQuantile();
}

void
set_pocv_quantile(float quantile)
{
  Sta::sta()->setPocvQuantile(quantile);
}

bool
propagate_gated_clock_enable()
{
  return Sta::sta()->propagateGatedClockEnable();
}

void
set_propagate_gated_clock_enable(bool enable)
{
  Sta::sta()->setPropagateGatedClockEnable(enable);
}

bool
preset_clr_arcs_enabled()
{
  return Sta::sta()->presetClrArcsEnabled();
}

void
set_preset_clr_arcs_enabled(bool enable)
{
  Sta::sta()->setPresetClrArcsEnabled(enable);
}

bool
cond_default_arcs_enabled()
{
  return Sta::sta()->condDefaultArcsEnabled();
}

void
set_cond_default_arcs_enabled(bool enabled)
{
  Sta::sta()->setCondDefaultArcsEnabled(enabled);
}

bool
bidirect_inst_paths_enabled()
{
  return Sta::sta()->bidirectInstPathsEnabled();
}

void
set_bidirect_inst_paths_enabled(bool enabled)
{
  Sta::sta()->setBidirectInstPathsEnabled(enabled);
}

bool
recovery_removal_checks_enabled()
{
  return Sta::sta()->recoveryRemovalChecksEnabled();
}

void
set_recovery_removal_checks_enabled(bool enabled)
{
  Sta::sta()->setRecoveryRemovalChecksEnabled(enabled);
}

bool
gated_clk_checks_enabled()
{
  return Sta::sta()->gatedClkChecksEnabled();
}

void
set_gated_clk_checks_enabled(bool enabled)
{
  Sta::sta()->setGatedClkChecksEnabled(enabled);
}

bool
dynamic_loop_breaking()
{
  return Sta::sta()->dynamicLoopBreaking();
}

void
set_dynamic_loop_breaking(bool enable)
{
  Sta::sta()->setDynamicLoopBreaking(enable);
}

bool
use_default_arrival_clock()
{
  return Sta::sta()->useDefaultArrivalClock();
}

void
set_use_default_arrival_clock(bool enable)
{
  Sta::sta()->setUseDefaultArrivalClock(enable);
}

// For regression tests.
void
report_arrival_entries()
{
  Sta *sta = Sta::sta();
  Search *search = sta->search();
  search->arrivalIterator()->reportEntries();
}

// For regression tests.
void
report_required_entries()
{
  Sta *sta = Sta::sta();
  Search *search = sta->search();
  search->requiredIterator()->reportEntries();
}

// For regression tests.
void
levelize()
{
  Sta *sta = Sta::sta();
  sta->levelize()->levelize();
}

%} // inline

////////////////////////////////////////////////////////////////
//
// Object Methods
//
////////////////////////////////////////////////////////////////

%extend PathEnd {
bool is_unconstrained() { return self->isUnconstrained(); }
bool is_check() { return self->isCheck(); }
bool is_latch_check() { return self->isLatchCheck(); }
bool is_data_check() { return self->isDataCheck(); }
bool is_output_delay() { return self->isOutputDelay(); }
bool is_path_delay() { return self->isPathDelay(); }
bool is_gated_clock() { return self->isGatedClock(); }
Pin *pin() { return self->vertex(Sta::sta())->pin(); }
Vertex *vertex() { return self->vertex(Sta::sta()); }
Path *path() { return self->path(); }
RiseFall *end_transition()
{ return const_cast<RiseFall*>(self->path()->transition(Sta::sta())); }

float
slack()
{
  Sta *sta = Sta::sta();
  return delayAsFloat(self->slack(sta), self->minMax(sta), sta);
}

float
margin()
{
  Sta *sta = Sta::sta();
  return delayAsFloat(self->margin(sta), self->minMax(sta), sta);
}

float
data_required_time()
{
  Sta *sta = Sta::sta();
  return delayAsFloat(self->requiredTimeOffset(sta), self->minMax(sta), sta);
}

float
data_arrival_time()
{
  Sta *sta = Sta::sta();
  return delayAsFloat(self->dataArrivalTimeOffset(sta), self->minMax(sta), sta);
}

float
target_clk_delay()
{
  Sta *sta = Sta::sta();
  return delayAsFloat(self->targetClkDelay(sta), self->minMax(sta), sta);
}

float
source_clk_latency()
{
  Sta *sta = Sta::sta();
  return delayAsFloat(self->sourceClkLatency(sta), self->minMax(sta), sta);
}

float
clk_skew()
{
  Sta *sta = Sta::sta();
  return delayAsFloat(self->clkSkew(sta), self->minMax(sta), sta);
}

const TimingRole *check_role() { return self->checkRole(Sta::sta()); }
MinMax *min_max() { return const_cast<MinMax*>(self->minMax(Sta::sta())); }
const Clock *target_clk() { return self->targetClk(Sta::sta()); }
const ClockEdge *target_clk_edge() { return self->targetClkEdge(Sta::sta()); }
Path *target_clk_path() { return self->targetClkPath(); }
}

%extend Path {
float
arrival()
{
  Sta *sta = Sta::sta();
  return delayAsFloat(self->arrival(), self->minMax(sta), sta);
}

float
required()
{
  Sta *sta = Sta::sta();
  return delayAsFloat(self->required(), self->minMax(sta), sta);
}

float
slack()
{
  Sta *sta = Sta::sta();
  return delayAsFloat(self->slack(sta), self->minMax(sta), sta);
}

const Pin *
pin()
{
  Sta *sta = Sta::sta();
  return self->pin(sta);
}

const RiseFall *
edge()
{
  return self->transition(Sta::sta());
}

std::string
tag()
{
  Sta *sta = Sta::sta();
  return self->tag(sta)->to_string(sta);
}

// mea_opt3
PinSeq
pins()
{
  Sta *sta = Sta::sta();
  PinSeq pins;
  Path *path1 = self;
  while (path1) {
    pins.push_back(path1->vertex(sta)->pin());
    path1 = path1->prevPath();
  }
  return pins;
}

const Path *
start_path()
{
  PathExpanded expanded(self, Sta::sta());
  return expanded.startPath();
}

}

%extend VertexPathIterator {
bool has_next() { return self->hasNext(); }
Path *
next()
{
  return self->next();
}

void finish() { delete self; }
}
