// *****************************************************************************
// *****************************************************************************
// Copyright 2012 - 2015, Cadence Design Systems
// 
// This  file  is  part  of  the  Cadence  LEF/DEF  Open   Source
// Distribution,  Product Version 5.8. 
// 
// Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
// 
//        http://www.apache.org/licenses/LICENSE-2.0
// 
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
//    implied. See the License for the specific language governing
//    permissions and limitations under the License.
// 
// For updates, support, or to become part of the LEF/DEF Community,
// check www.openeda.org for details.
// 
//  $Author: dell $
//  $Revision: #1 $
//  $Date: 2017/06/06 $
//  $State:  $
// *****************************************************************************
// *****************************************************************************

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lex.h"
#include "lefiViaRule.hpp"
#include "lefiDebug.hpp"

BEGIN_LEFDEF_PARSER_NAMESPACE

// *****************************************************************************
// lefiViaRuleLayer
// *****************************************************************************

lefiViaRuleLayer::lefiViaRuleLayer()
: name_(NULL),
  direction_(0),
  overhang1_(0.0),
  overhang2_(0.0),
  hasWidth_(0),
  hasResistance_(0),
  hasOverhang_(0),
  hasMetalOverhang_(0),
  hasSpacing_(0),
  hasRect_(0),
  widthMin_(0.0),
  widthMax_(0.0),
  overhang_(0.0),
  metalOverhang_(0.0),
  resistance_(0.0),
  spacingStepX_(0.0),
  spacingStepY_(0.0),
  xl_(0.0),
  yl_(0.0),
  xh_(0.0),
  yh_(0.0)
{
    Init();
}

void
lefiViaRuleLayer::Init()
{
    name_ = 0;
    overhang1_ = -1;
    overhang2_ = -1;
}

void
lefiViaRuleLayer::clearLayerOverhang()
{
    overhang1_ = -1;
    overhang2_ = -1;
}

void
lefiViaRuleLayer::setName(const char *name)
{
    int len = strlen(name) + 1;
    if (name_)
        lefFree(name_);
    name_ = (char*) lefMalloc(len);
    strcpy(name_, CASE(name));
    direction_ = '\0';
    // overhang1_ = -1;    already reset in clearLayerOverhang
    // overhang2_ = -1;
    hasWidth_ = 0;
    hasResistance_ = 0;
    hasOverhang_ = 0;
    hasMetalOverhang_ = 0;
    hasSpacing_ = 0;
    hasRect_ = 0;
}

void
lefiViaRuleLayer::Destroy()
{
    if (name_)
        lefFree(name_);
}

lefiViaRuleLayer::~lefiViaRuleLayer()
{
    // Destroy will be called explicitly
    // so do nothing here.
}

void
lefiViaRuleLayer::setHorizontal()
{
    direction_ = 'H';
}

void
lefiViaRuleLayer::setVertical()
{
    direction_ = 'V';
}

// 5.5
void
lefiViaRuleLayer::setEnclosure(double   overhang1,
                               double   overhang2)
{
    overhang1_ = overhang1;
    overhang2_ = overhang2;
}

void
lefiViaRuleLayer::setWidth(double   minW,
                           double   maxW)
{
    hasWidth_ = 1;
    widthMin_ = minW;
    widthMax_ = maxW;
}

void
lefiViaRuleLayer::setOverhang(double d)
{
    hasOverhang_ = 1;
    overhang_ = d;
}

// 5.6
void
lefiViaRuleLayer::setOverhangToEnclosure(double d)
{
    if ((overhang1_ != -1) && (overhang2_ != -1))
        return;                    // both overhang1_ & overhang2_ are set
    if (overhang1_ == -1)
        overhang1_ = d;      // set value to overhang1_
    else
        overhang2_ = d;      // overhang1_ already set, set to overhang2_
    return;
}

// 5.5
void
lefiViaRuleLayer::setMetalOverhang(double d)
{
    hasMetalOverhang_ = 1;
    metalOverhang_ = d;
}

void
lefiViaRuleLayer::setResistance(double d)
{
    hasResistance_ = 1;
    resistance_ = d;
}

void
lefiViaRuleLayer::setSpacing(double x,
                             double y)
{
    hasSpacing_ = 1;
    spacingStepX_ = x;
    spacingStepY_ = y;
}

void
lefiViaRuleLayer::setRect(double    xl,
                          double    yl,
                          double    xh,
                          double    yh)
{
    hasRect_ = 1;
    xl_ = xl;
    yl_ = yl;
    xh_ = xh;
    yh_ = yh;
}

int
lefiViaRuleLayer::hasRect() const
{
    return hasRect_;
}

int
lefiViaRuleLayer::hasDirection() const
{
    return direction_ ? 1 : 0;
}

// 5.5
int
lefiViaRuleLayer::hasEnclosure() const
{
    return overhang1_ == -1 ? 0 : 1;
}

int
lefiViaRuleLayer::hasWidth() const
{
    return hasWidth_;
}

int
lefiViaRuleLayer::hasResistance() const
{
    return hasResistance_;
}

int
lefiViaRuleLayer::hasOverhang() const
{
    return hasOverhang_;
}

int
lefiViaRuleLayer::hasMetalOverhang() const
{
    return hasMetalOverhang_;
}

int
lefiViaRuleLayer::hasSpacing() const
{
    return hasSpacing_;
}

char *
lefiViaRuleLayer::name() const
{
    return name_;
}

int
lefiViaRuleLayer::isHorizontal() const
{
    return direction_ == 'H' ? 1 : 0;
}

int
lefiViaRuleLayer::isVertical() const
{
    return direction_ == 'V' ? 1 : 0;
}

// 5.5
double
lefiViaRuleLayer::enclosureOverhang1() const
{
    return overhang1_;
}

// 5.5
double
lefiViaRuleLayer::enclosureOverhang2() const
{
    return overhang2_;
}

double
lefiViaRuleLayer::widthMin() const
{
    return widthMin_;
}

double
lefiViaRuleLayer::widthMax() const
{
    return widthMax_;
}

double
lefiViaRuleLayer::overhang() const
{
    return overhang_;
}

double
lefiViaRuleLayer::metalOverhang() const
{
    return metalOverhang_;
}

double
lefiViaRuleLayer::resistance() const
{
    return resistance_;
}

double
lefiViaRuleLayer::spacingStepX() const
{
    return spacingStepX_;
}

double
lefiViaRuleLayer::spacingStepY() const
{
    return spacingStepY_;
}

double
lefiViaRuleLayer::xl() const
{
    return xl_;
}

double
lefiViaRuleLayer::yl() const
{
    return yl_;
}

double
lefiViaRuleLayer::xh() const
{
    return xh_;
}

double
lefiViaRuleLayer::yh() const
{
    return yh_;
}

void
lefiViaRuleLayer::print(FILE *f) const
{
    fprintf(f, "  Layer %s", name_);

    if (isHorizontal())
        fprintf(f, " HORIZONTAL");
    if (isVertical())
        fprintf(f, " VERTICAL");
    fprintf(f, "\n");

    if (hasWidth())
        fprintf(f, "    WIDTH %g %g\n", widthMin(),
                widthMax());

    if (hasResistance())
        fprintf(f, "    RESISTANCE %g\n", resistance());

    if (hasOverhang())
        fprintf(f, "    OVERHANG %g\n", overhang());

    if (hasMetalOverhang())
        fprintf(f, "    METALOVERHANG %g\n",
                metalOverhang());

    if (hasSpacing())
        fprintf(f, "    SPACING %g %g\n",
                spacingStepX(),
                spacingStepY());

    if (hasRect())
        fprintf(f, "    RECT %g,%g %g,%g\n",
                xl(), yl(),
                xh(), yh());
}

// *****************************************************************************
// lefiViaRule
// *****************************************************************************

lefiViaRule::lefiViaRule()
: name_(NULL),
  nameSize_(0),
  hasGenerate_(0),
  hasDefault_(0),
  numLayers_(0),
  numVias_(0),
  viasAllocated_(0),
  vias_(NULL),
  numProps_(0),
  propsAllocated_(0),
  names_(NULL),
  values_(NULL),
  dvalues_(NULL),
  types_(NULL)
{
    Init();
}

void
lefiViaRule::Init()
{
    nameSize_ = 16;
    name_ = (char*) lefMalloc(16);
    viasAllocated_ = 2;
    vias_ = (char**) lefMalloc(sizeof(char*) * 2);
    layers_[0].Init();
    layers_[1].Init();
    layers_[2].Init();
    numLayers_ = 0;
    numVias_ = 0;
    numProps_ = 0;
    propsAllocated_ = 1;
    names_ = (char**) lefMalloc(sizeof(char*));
    values_ = (char**) lefMalloc(sizeof(char*));
    dvalues_ = (double*) lefMalloc(sizeof(double));
    types_ = (char*) lefMalloc(sizeof(char));
}

void
lefiViaRule::clear()
{
    int i;
    hasGenerate_ = 0;
    hasDefault_ = 0;
    for (i = 0; i < numProps_; i++) {
        lefFree(names_[i]);
        lefFree(values_[i]);
        dvalues_[i] = 0;
    }
    numProps_ = 0;
    numLayers_ = 0;
    for (i = 0; i < numVias_; i++) {
        lefFree(vias_[i]);
    }
    numVias_ = 0;
}

void
lefiViaRule::clearLayerOverhang()
{
    layers_[0].clearLayerOverhang();
    layers_[1].clearLayerOverhang();
}

void
lefiViaRule::setName(const char *name)
{
    int len = strlen(name) + 1;
    if (len > nameSize_) {
        lefFree(name_);
        name_ = (char*) lefMalloc(len);
        nameSize_ = len;
    }
    strcpy(name_, CASE(name));
    clear();
}

void
lefiViaRule::Destroy()
{
    clear();
    lefFree(name_);
    lefFree((char*) (vias_));
    lefFree((char*) (names_));
    lefFree((char*) (values_));
    lefFree((char*) (dvalues_));
    lefFree((char*) (types_));
    layers_[0].Destroy();
    layers_[1].Destroy();
    layers_[2].Destroy();
}

lefiViaRule::~lefiViaRule()
{
    Destroy();
}

void
lefiViaRule::setGenerate()
{
    hasGenerate_ = 1;
}

void
lefiViaRule::setDefault()
{
    hasDefault_ = 1;
}

void
lefiViaRule::addViaName(const char *name)
{
    // Add one of possibly many via names
    int len = strlen(name) + 1;
    if (numVias_ == viasAllocated_) {
        int     i;
        char    **nn;
        if (viasAllocated_ == 0)
            viasAllocated_ = 2;
        else
            viasAllocated_ *= 2;
        nn = (char**) lefMalloc(sizeof(char*) * viasAllocated_);
        for (i = 0; i < numVias_; i++)
            nn[i] = vias_[i];
        lefFree((char*) (vias_));
        vias_ = nn;
    }
    vias_[numVias_] = (char*) lefMalloc(len);
    strcpy(vias_[numVias_], CASE(name));
    numVias_ += 1;
}

void
lefiViaRule::setRect(double xl,
                     double yl,
                     double xh,
                     double yh)
{
    layers_[numLayers_ - 1].setRect(xl, yl, xh, yh);
}

void
lefiViaRule::setSpacing(double  x,
                        double  y)
{
    layers_[numLayers_ - 1].setSpacing(x, y);
}

void
lefiViaRule::setWidth(double    x,
                      double    y)
{
    layers_[numLayers_ - 1].setWidth(x, y);
}

void
lefiViaRule::setResistance(double d)
{
    layers_[numLayers_ - 1].setResistance(d);
}

void
lefiViaRule::setOverhang(double d)
{
    layers_[numLayers_ - 1].setOverhang(d);
}

// 5.6, try to set value to layers_[0] & layers_[1]
void
lefiViaRule::setOverhangToEnclosure(double d)
{
    layers_[0].setOverhangToEnclosure(d);
    layers_[1].setOverhangToEnclosure(d);
}

void
lefiViaRule::setMetalOverhang(double d)
{
    layers_[numLayers_ - 1].setMetalOverhang(d);
}

void
lefiViaRule::setVertical()
{
    layers_[numLayers_ - 1].setVertical();
}

void
lefiViaRule::setHorizontal()
{
    layers_[numLayers_ - 1].setHorizontal();
}

void
lefiViaRule::setEnclosure(double    overhang1,
                          double    overhang2)
{
    layers_[numLayers_ - 1].setEnclosure(overhang1,
                                         overhang2);
}

void
lefiViaRule::setLayer(const char *name)
{
    if (numLayers_ == 3) {
        lefiError(0, 1430, "ERROR (LEFPARS-1430): too many via rule layers");
        return;
    }
    // This routine sets and creates the active layer.
    layers_[numLayers_].setName(name);
    numLayers_ += 1;
}

int
lefiViaRule::hasGenerate() const
{
    return hasGenerate_;
}

int
lefiViaRule::hasDefault() const
{
    return hasDefault_;
}

int
lefiViaRule::numLayers() const
{
    // There are 2 or 3 layers in a rule.
    // numLayers() tells how many.
    // If a third layer exists then it is the cut layer.
    return numLayers_;
}

lefiViaRuleLayer *
lefiViaRule::layer(int index) const
{
    if (index < 0 || index > 2)
        return 0;
    return (lefiViaRuleLayer*) &(layers_[index]);
}

char *
lefiViaRule::name() const
{
    return name_;
}

void
lefiViaRule::print(FILE *f) const
{
    int i;
    fprintf(f, "VIA RULE %s", name());
    if (hasGenerate())
        fprintf(f, " GENERATE");
    fprintf(f, "\n");

    for (i = 0; i < numLayers(); i++) {
        layers_[i].print(f);
    }

    for (i = 0; i < numVias(); i++) {
        fprintf(f, "  Via %s\n", viaName(i));
    }
}

int
lefiViaRule::numVias() const
{
    return numVias_;
}

char *
lefiViaRule::viaName(int index) const
{
    if (index < 0 || index >= numVias_)
        return 0;
    return vias_[index];
}

int
lefiViaRule::numProps() const
{
    return numProps_;
}

void
lefiViaRule::addProp(const char *name,
                     const char *value,
                     const char type)
{
    int len = strlen(name) + 1;
    if (numProps_ == propsAllocated_) {
        int     i;
        int     max;
        int     lim;
        char    **nn;
        char    **nv;
        double  *nd;
        char    *nt;

        if (propsAllocated_ == 0)
            propsAllocated_ = 1;    // initialize propsAllocated_
        max = propsAllocated_ *= 2;
        lim = numProps_;
        nn = (char**) lefMalloc(sizeof(char*) * max);
        nv = (char**) lefMalloc(sizeof(char*) * max);
        nd = (double*) lefMalloc(sizeof(double) * max);
        nt = (char*) lefMalloc(sizeof(char) * max);
        for (i = 0; i < lim; i++) {
            nn[i] = names_[i];
            nv[i] = values_[i];
            nd[i] = dvalues_[i];
            nt[i] = types_[i];
        }
        lefFree((char*) (names_));
        lefFree((char*) (values_));
        lefFree((char*) (dvalues_));
        lefFree((char*) (types_));
        names_ = nn;
        values_ = nv;
        dvalues_ = nd;
        types_ = nt;
    }
    names_[numProps_] = (char*) lefMalloc(sizeof(char) * len);
    strcpy(names_[numProps_], name);
    len = strlen(value) + 1;
    values_[numProps_] = (char*) lefMalloc(sizeof(char) * len);
    strcpy(values_[numProps_], value);
    dvalues_[numProps_] = 0;
    types_[numProps_] = type;
    numProps_ += 1;
}

void
lefiViaRule::addNumProp(const char      *name,
                        const double    d,
                        const char      *value,
                        const char      type)
{
    int len = strlen(name) + 1;
    if (numProps_ == propsAllocated_) {
        int     i;
        int     max;
        int     lim;
        char    **nn;
        char    **nv;
        double  *nd;
        char    *nt;

        if (propsAllocated_ == 0)
            propsAllocated_ = 1;    // initialize propsAllocated_
        max = propsAllocated_ *= 2;
        lim = numProps_;
        nn = (char**) lefMalloc(sizeof(char*) * max);
        nv = (char**) lefMalloc(sizeof(char*) * max);
        nd = (double*) lefMalloc(sizeof(double) * max);
        nt = (char*) lefMalloc(sizeof(char) * max);
        for (i = 0; i < lim; i++) {
            nn[i] = names_[i];
            nv[i] = values_[i];
            nd[i] = dvalues_[i];
            nt[i] = types_[i];
        }
        lefFree((char*) (names_));
        lefFree((char*) (values_));
        lefFree((char*) (dvalues_));
        lefFree((char*) (types_));
        names_ = nn;
        values_ = nv;
        dvalues_ = nd;
        types_ = nt;
    }
    names_[numProps_] = (char*) lefMalloc(sizeof(char) * len);
    strcpy(names_[numProps_], name);
    len = strlen(value) + 1;
    values_[numProps_] = (char*) lefMalloc(sizeof(char) * len);
    strcpy(values_[numProps_], value);
    dvalues_[numProps_] = d;
    types_[numProps_] = type;
    numProps_ += 1;
}

const char *
lefiViaRule::propName(int i) const
{
    char msg[160];
    if (i < 0 || i >= numProps_) {
        sprintf(msg, "ERROR (LEFPARS-1431): The index number %d given for the VIARULE PROPERTY is invalid.\nValid index is from 0 to %d", i, numProps_);
        lefiError(0, 1431, msg);
        return 0;
    }
    return names_[i];
}

const char *
lefiViaRule::propValue(int i) const
{
    char msg[160];
    if (i < 0 || i >= numProps_) {
        sprintf(msg, "ERROR (LEFPARS-1431): The index number %d given for the VIARULE PROPERTY is invalid.\nValid index is from 0 to %d", i, numProps_);
        lefiError(0, 1431, msg);
        return 0;
    }
    return values_[i];
}

double
lefiViaRule::propNumber(int i) const
{
    char msg[160];
    if (i < 0 || i >= numProps_) {
        sprintf(msg, "ERROR (LEFPARS-1431): The index number %d given for the VIARULE PROPERTY is invalid.\nValid index is from 0 to %d", i, numProps_);
        lefiError(0, 1431, msg);
        return 0;
    }
    return dvalues_[i];
}

const char
lefiViaRule::propType(int i) const
{
    char msg[160];
    if (i < 0 || i >= numProps_) {
        sprintf(msg, "ERROR (LEFPARS-1431): The index number %d given for the VIARULE PROPERTY is invalid.\nValid index is from 0 to %d", i, numProps_);
        lefiError(0, 1431, msg);
        return 0;
    }
    return types_[i];
}

int
lefiViaRule::propIsNumber(int i) const
{
    char msg[160];
    if (i < 0 || i >= numProps_) {
        sprintf(msg, "ERROR (LEFPARS-1431): The index number %d given for the VIARULE PROPERTY is invalid.\nValid index is from 0 to %d", i, numProps_);
        lefiError(0, 1431, msg);
        return 0;
    }
    return dvalues_[i] ? 1 : 0;
}

int
lefiViaRule::propIsString(int i) const
{
    char msg[160];
    if (i < 0 || i >= numProps_) {
        sprintf(msg, "ERROR (LEFPARS-1431): The index number %d given for the VIARULE PROPERTY is invalid.\nValid index is from 0 to %d", i, numProps_);
        lefiError(0, 1431, msg);
        return 0;
    }
    return dvalues_[i] ? 0 : 1;
}
END_LEFDEF_PARSER_NAMESPACE

