// *****************************************************************************
// *****************************************************************************
// Copyright 2012 - 2014, 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 "lefiMisc.hpp"
#include <string.h>
#include <stdlib.h>
#include "lex.h"
#include "lefiDebug.hpp"
#include "lefiUtil.hpp"

BEGIN_LEFDEF_PARSER_NAMESPACE

// *****************************************************************************
// lefiGeometries
// *****************************************************************************

lefiGeometries::lefiGeometries()
{
    Init();
}

void
lefiGeometries::Init()
{
    itemsAllocated_ = 2;
    numItems_ = 0;
    itemType_ = (lefiGeomEnum*) lefMalloc(sizeof(lefiGeomEnum) * 2);
    items_ = (void**) lefMalloc(sizeof(void*) * 2);
    numPoints_ = 0;
    pointsAllocated_ = 0;
    x_ = 0;
    y_ = 0;
    xStart_ = -1;
    yStart_ = -1;
    xStep_ = -1;
    yStep_ = -1;
}

void
lefiGeometries::Destroy()
{
    clear();
    lefFree((char*) (items_));
    lefFree((char*) (itemType_));
    if (x_) {
        lefFree((double*) (x_));
        lefFree((double*) (y_));
    }
    pointsAllocated_ = 0;
}

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

void
lefiGeometries::clear()
{
    for (int i = 0; i < numItems_; i++) {
        if (itemType_[i] == lefiGeomViaE) {
            lefFree(((lefiGeomVia*) (items_[i]))->name);
        }
        if (itemType_[i] == lefiGeomViaIterE) {
            lefFree(((lefiGeomViaIter*) (items_[i]))->name);
        }
        if (itemType_[i] == lefiGeomPathE) {
            ((lefiGeomPath*) (items_[i]))->numPoints = 0;
            lefFree((double*) ((lefiGeomPath*) items_[i])->x);
            lefFree((double*) ((lefiGeomPath*) items_[i])->y);
        }
        if (itemType_[i] == lefiGeomPathIterE) {
            ((lefiGeomPathIter*) (items_[i]))->numPoints = 0;
            lefFree((double*) ((lefiGeomPathIter*) items_[i])->x);
            lefFree((double*) ((lefiGeomPathIter*) items_[i])->y);
        }
        if (itemType_[i] == lefiGeomPolygonE) {
            ((lefiGeomPolygon*) (items_[i]))->numPoints = 0;
            lefFree((double*) ((lefiGeomPolygon*) items_[i])->x);
            lefFree((double*) ((lefiGeomPolygon*) items_[i])->y);
        }
        if (itemType_[i] == lefiGeomPolygonIterE) {
            ((lefiGeomPolygonIter*) (items_[i]))->numPoints = 0;
            lefFree((double*) ((lefiGeomPolygonIter*) items_[i])->x);
            lefFree((double*) ((lefiGeomPolygonIter*) items_[i])->y);
        }
        lefFree((char*) (items_[i]));
    }
    numItems_ = 0;
}

void
lefiGeometries::clearPolyItems()
{
    lefFree((char*) (items_));
    lefFree((char*) (itemType_));
    if (x_) {
        lefFree((double*) (x_));
        lefFree((double*) (y_));
    }
    numPoints_ = 0;
    pointsAllocated_ = 0;
    numItems_ = 0;
}

void
lefiGeometries::add(void            *v,
                    lefiGeomEnum    e)
{
    if (numItems_ == itemsAllocated_) {
        int             i;
        void            **newi;
        lefiGeomEnum    *newe;
        if (itemsAllocated_ == 0)   // 9/12/2002 - for C version
            itemsAllocated_ = 2;
        else
            itemsAllocated_ *= 2;
        newe = (lefiGeomEnum*) lefMalloc(sizeof(lefiGeomEnum) * itemsAllocated_);
        newi = (void**) lefMalloc(sizeof(void*) * itemsAllocated_);
        for (i = 0; i < numItems_; i++) {
            newe[i] = itemType_[i];
            newi[i] = items_[i];
        }
        lefFree((char*) (items_));
        lefFree((char*) (itemType_));
        items_ = newi;
        itemType_ = newe;
    }
    items_[numItems_] = v;
    itemType_[numItems_] = e;
    numItems_ += 1;
}

void
lefiGeometries::addLayer(const char *name)
{
    char *c = (char*) lefMalloc(strlen(name) + 1);
    strcpy(c, CASE(name));
    add((void*) c, lefiGeomLayerE);
}

// 5.7
void
lefiGeometries::addLayerExceptPgNet()
{
    int *d = (int*) lefMalloc(sizeof(int));
    *d = 1;
    add((void*) d, lefiGeomLayerExceptPgNetE);
}

void
lefiGeometries::addLayerMinSpacing(double spacing)
{
    double *d = (double*) lefMalloc(sizeof(double));
    *d = spacing;
    add((void*) d, lefiGeomLayerMinSpacingE);
}

void
lefiGeometries::addLayerRuleWidth(double width)
{
    double *d = (double*) lefMalloc(sizeof(double));
    *d = width;
    add((void*) d, lefiGeomLayerRuleWidthE);
}

void
lefiGeometries::addClass(const char *name)
{
    char *c = (char*) lefMalloc(strlen(name) + 1);
    strcpy(c, CASE(name));
    add((void*) c, lefiGeomClassE);
}

void
lefiGeometries::addWidth(double w)
{
    double *d = (double*) lefMalloc(sizeof(double));
    *d = w;
    add((void*) d, lefiGeomWidthE);
}

void
lefiGeometries::addPath(int colorMask)
{
    int             i;
    int             lim;
    lefiGeomPath    *p = (lefiGeomPath*) lefMalloc(sizeof(lefiGeomPath));

    lim = p->numPoints = numPoints_;

    if (lim > 0) {
        p->x = (double*) lefMalloc(sizeof(double) * lim);
        p->y = (double*) lefMalloc(sizeof(double) * lim);
        for (i = 0; i < lim; i++) {
            p->x[i] = x_[i];
            p->y[i] = y_[i];
        }
    } else {
        p->x = 0;
        p->y = 0;
    }

    p->colorMask = colorMask;

    add((void*) p, lefiGeomPathE);
}

void
lefiGeometries::addPathIter(int colorMask)
{
    int                 i;
    int                 lim;
    lefiGeomPathIter    *p = (lefiGeomPathIter*) lefMalloc(sizeof(lefiGeomPathIter));

    lim = p->numPoints = numPoints_;

    if (lim > 0) {
        p->x = (double*) lefMalloc(sizeof(double) * lim);
        p->y = (double*) lefMalloc(sizeof(double) * lim);
        for (i = 0; i < lim; i++) {
            p->x[i] = x_[i];
            p->y[i] = y_[i];
        }
    } else {
        p->x = 0;
        p->y = 0;
    }

    p->colorMask = colorMask;
    p->xStart = xStart_;
    p->yStart = yStart_;
    p->xStep = xStep_;
    p->yStep = yStep_;

    add((void*) p, lefiGeomPathIterE);
}

// pcr 481783 & 560504 
void
lefiGeometries::addRect(int     colorMask,
                        double  xl,
                        double  yl,
                        double  xh,
                        double  yh)
{
    lefiGeomRect *p = (lefiGeomRect*) lefMalloc(sizeof(lefiGeomRect));
    p->xl = xl;
    p->yl = yl;
    p->xh = xh;
    p->yh = yh;
    p->colorMask = colorMask;

    add((void*) p, lefiGeomRectE);
}

void
lefiGeometries::addRectIter(int     colorMask,
                            double  xl,
                            double  yl,
                            double  xh,
                            double  yh)
{
    lefiGeomRectIter *p = (lefiGeomRectIter*) lefMalloc(sizeof(lefiGeomRectIter));

    p->xl = xl;
    p->yl = yl;
    p->xh = xh;
    p->yh = yh;
    p->xStart = xStart_;
    p->yStart = yStart_;
    p->xStep = xStep_;
    p->yStep = yStep_;
    p->colorMask = colorMask;

    add((void*) p, lefiGeomRectIterE);
}

void
lefiGeometries::addPolygon(int colorMask)
{
    int             i;
    int             lim;
    lefiGeomPolygon *p = (lefiGeomPolygon*) lefMalloc(sizeof(lefiGeomPolygon));

    lim = p->numPoints = numPoints_;

    if (lim > 0) {
        p->x = (double*) lefMalloc(sizeof(double) * lim);
        p->y = (double*) lefMalloc(sizeof(double) * lim);
        for (i = 0; i < lim; i++) {
            p->x[i] = x_[i];
            p->y[i] = y_[i];
        }
    } else {
        p->x = 0;
        p->y = 0;
    }


    p->colorMask = colorMask;

    add((void*) p, lefiGeomPolygonE);
}

void
lefiGeometries::addPolygonIter(int colorMask)
{
    int                 i;
    int                 lim;
    lefiGeomPolygonIter *p = (lefiGeomPolygonIter*) lefMalloc(sizeof(lefiGeomPolygonIter));

    lim = p->numPoints = numPoints_;

    if (lim > 0) {
        p->x = (double*) lefMalloc(sizeof(double) * lim);
        p->y = (double*) lefMalloc(sizeof(double) * lim);
        for (i = 0; i < lim; i++) {
            p->x[i] = x_[i];
            p->y[i] = y_[i];
        }
    } else {
        p->x = 0;
        p->y = 0;
    }

    p->xStart = xStart_;
    p->yStart = yStart_;
    p->xStep = xStep_;
    p->yStep = yStep_;

    p->colorMask = colorMask;

    add((void*) p, lefiGeomPolygonIterE);
}

void
lefiGeometries::addVia(int          viaMask,
                       double       x,
                       double       y,
                       const char   *name)
{
    lefiGeomVia *p = (lefiGeomVia*) lefMalloc(sizeof(lefiGeomVia));
    char        *c = (char*) lefMalloc(strlen(name) + 1);

    strcpy(c, CASE(name));
    p->x = x;
    p->y = y;
    p->name = c;
    p->bottomMaskNum = viaMask % 10;
    p->cutMaskNum = viaMask / 10 % 10;
    p->topMaskNum = viaMask / 100;

    add((void*) p, lefiGeomViaE);
}

void
lefiGeometries::addViaIter(int          viaMask,
                           double       x,
                           double       y,
                           const char   *name)
{
    lefiGeomViaIter *p = (lefiGeomViaIter*) lefMalloc(sizeof(lefiGeomViaIter));
    char            *c = (char*) lefMalloc(strlen(name) + 1);

    strcpy(c, CASE(name));
    p->bottomMaskNum = viaMask % 10;
    p->cutMaskNum = viaMask / 10 % 10;
    p->topMaskNum = viaMask / 100;
    p->x = x;
    p->y = y;
    p->name = c;
    p->xStart = xStart_;
    p->yStart = yStart_;
    p->xStep = xStep_;
    p->yStep = yStep_;

    add((void*) p, lefiGeomViaIterE);
}

void
lefiGeometries::addStepPattern(double   xStart,
                               double   yStart,
                               double   xStep,
                               double   yStep)
{
    xStart_ = xStart;
    yStart_ = yStart;
    xStep_ = xStep;
    yStep_ = yStep;
}

void
lefiGeometries::startList(double    x,
                          double    y)
{
    if (!x_) {
        numPoints_ = 0;
        pointsAllocated_ = 16;
        x_ = (double*) lefMalloc(sizeof(double) * 16);
        y_ = (double*) lefMalloc(sizeof(double) * 16);
    } else {  // reset the numPoits to 0
        numPoints_ = 0;
    }
    addToList(x, y);
}

void
lefiGeometries::addToList(double    x,
                          double    y)
{
    if (numPoints_ == pointsAllocated_) {
        int     i;
        double  *nx;
        double  *ny;
        if (pointsAllocated_ == 0)
            pointsAllocated_ = 2;
        else
            pointsAllocated_ *= 2;
        nx = (double*) lefMalloc(sizeof(double) * pointsAllocated_);
        ny = (double*) lefMalloc(sizeof(double) * pointsAllocated_);
        for (i = 0; i < numPoints_; i++) {
            nx[i] = x_[i];
            ny[i] = y_[i];
        }
        lefFree((char*) (x_));
        lefFree((char*) (y_));
        x_ = nx;
        y_ = ny;
    }
    x_[numPoints_] = x;
    y_[numPoints_] = y;
    numPoints_ += 1;
}

int
lefiGeometries::numItems() const
{
    return numItems_;
}

lefiGeomEnum
lefiGeometries::itemType(int index) const
{
    char msg[160];
    if (index < 0 || index >= numItems_) {
        sprintf(msg, "ERROR (LEFPARS-1360): The index number %d given for the geometry item is invalid.\nValid index is from 0 to %d", index, numItems_);
        lefiError(0, 1360, msg);
        return lefiGeomUnknown;
    }
    return itemType_[index];
}

lefiGeomRect *
lefiGeometries::getRect(int index) const
{
    char msg[160];
    if (index < 0 || index >= numItems_) {
        sprintf(msg, "ERROR (LEFPARS-1361): The index number %d given for the geometry RECTANGLE is invalid.\nValid index is from 0 to %d", index, numItems_);
        lefiError(0, 1361, msg);
        return 0;
    }
    return (lefiGeomRect*) (items_[index]);
}

lefiGeomRectIter *
lefiGeometries::getRectIter(int index) const
{
    char msg[160];
    if (index < 0 || index >= numItems_) {
        sprintf(msg, "ERROR (LEFPARS-1362): The index number %d given for the geometry RECTANGLE ITERATE is invalid.\nValid index is from 0 to %d", index, numItems_);
        lefiError(0, 1362, msg);
        return 0;
    }
    return (lefiGeomRectIter*) (items_[index]);
}

lefiGeomPath *
lefiGeometries::getPath(int index) const
{
    char msg[160];
    if (index < 0 || index >= numItems_) {
        sprintf(msg, "ERROR (LEFPARS-1363): The index number %d given for the geometry PATH is invalid.\nValid index is from 0 to %d", index, numItems_);
        lefiError(0, 1363, msg);
        return 0;
    }
    return (lefiGeomPath*) (items_[index]);
}

lefiGeomPathIter *
lefiGeometries::getPathIter(int index) const
{
    char msg[160];
    if (index < 0 || index >= numItems_) {
        sprintf(msg, "ERROR (LEFPARS-1364): The index number %d given for the geometry PATH ITERATE is invalid.\nValid index is from 0 to %d", index, numItems_);
        lefiError(0, 1364, msg);
        return 0;
    }
    return (lefiGeomPathIter*) (items_[index]);
}

char *
lefiGeometries::getLayer(int index) const
{
    char msg[160];
    if (index < 0 || index >= numItems_) {
        sprintf(msg, "ERROR (LEFPARS-1365): The index number %d given for the geometry LAYER is invalid.\nValid index is from 0 to %d", index, numItems_);
        lefiError(0, 1365, msg);
        return 0;
    }
    return (char*) (items_[index]);
}

// 5.7
int
lefiGeometries::hasLayerExceptPgNet(int index) const
{
    char msg[160];
    if (index < 0 || index >= numItems_) {
        sprintf(msg, "ERROR (LEFPARS-1366): The index number %d given for the geometry LAYER EXCEPT PG NET is invalid.\nValid index is from 0 to %d", index, numItems_);
        lefiError(0, 1366, msg);
        return 0;
    }
    return *((int*) (items_[index]));
}

double
lefiGeometries::getLayerMinSpacing(int index) const
{
    char msg[160];
    if (index < 0 || index >= numItems_) {
        sprintf(msg, "ERROR (LEFPARS-1367): The index number %d given for the geometry LAYER MINSPACING is invalid.\nValid index is from 0 to %d", index, numItems_);
        lefiError(0, 1367, msg);
        return 0;
    }
    return *((double*) (items_[index]));
}

double
lefiGeometries::getLayerRuleWidth(int index) const
{
    char msg[160];
    if (index < 0 || index >= numItems_) {
        sprintf(msg, "ERROR (LEFPARS-1368): The index number %d given for the geometry LAYER RULE WIDTH is invalid.\nValid index is from 0 to %d", index, numItems_);
        lefiError(0, 1368, msg);
        return 0;
    }
    return *((double*) (items_[index]));
}

double
lefiGeometries::getWidth(int index) const
{
    char msg[160];
    if (index < 0 || index >= numItems_) {
        sprintf(msg, "ERROR (LEFPARS-1369): The index number %d given for the geometry WIDTH is invalid.\nValid index is from 0 to %d", index, numItems_);
        lefiError(0, 1369, msg);
        return 0;
    }
    return *((double*) (items_[index]));
}

lefiGeomPolygon *
lefiGeometries::getPolygon(int index) const
{
    char msg[160];
    if (index < 0 || index >= numItems_) {
        sprintf(msg, "ERROR (LEFPARS-1370): The index number %d given for the geometry POLYGON is invalid.\nValid index is from 0 to %d", index, numItems_);
        lefiError(0, 1370, msg);
        return 0;
    }
    return (lefiGeomPolygon*) (items_[index]);
}

lefiGeomPolygonIter *
lefiGeometries::getPolygonIter(int index) const
{
    char msg[160];
    if (index < 0 || index >= numItems_) {
        sprintf(msg, "ERROR (LEFPARS-1371): The index number %d given for the geometry POLYGON ITERATE is invalid.\nValid index is from 0 to %d", index, numItems_);
        lefiError(0, 1371, msg);
        return 0;
    }
    return (lefiGeomPolygonIter*) (items_[index]);
}

char *
lefiGeometries::getClass(int index) const
{
    char msg[160];
    if (index < 0 || index >= numItems_) {
        sprintf(msg, "ERROR (LEFPARS-1372): The index number %d given for the geometry CLASS is invalid.\nValid index is from 0 to %d", index, numItems_);
        lefiError(0, 1372, msg);
        return 0;
    }
    return (char*) (items_[index]);
}

lefiGeomVia *
lefiGeometries::getVia(int index) const
{
    char msg[160];
    if (index < 0 || index >= numItems_) {
        sprintf(msg, "ERROR (LEFPARS-1373): The index number %d given for the geometry VIA is invalid.\nValid index is from 0 to %d", index, numItems_);
        lefiError(0, 1373, msg);
        return 0;
    }
    return (lefiGeomVia*) (items_[index]);
}

lefiGeomViaIter *
lefiGeometries::getViaIter(int index) const
{
    char msg[160];
    if (index < 0 || index >= numItems_) {
        sprintf(msg, "ERROR (LEFPARS-1374): The index number %d given for the geometry VIA ITERATE is invalid.\nValid index is from 0 to %d", index, numItems_);
        lefiError(0, 1374, msg);
        return 0;
    }
    return (lefiGeomViaIter*) (items_[index]);
}

void
lefiGeometries::print(FILE *f) const
{
    int                 i;
    int                 l;
    lefiGeomRect        *rect;
    lefiGeomRectIter    *rectiter;
    lefiGeomPath        *path;
    lefiGeomPathIter    *pathiter;
    lefiGeomPolygon     *polygon;
    lefiGeomPolygonIter *polygoniter;

    for (i = 0; i < numItems_; i++) {
        switch (itemType(i)) {

        case lefiGeomLayerE:
            fprintf(f, "Layer %s\n", getLayer(i));
            break;

        case lefiGeomLayerExceptPgNetE:
            if (getLayerMinSpacing(i))
                fprintf(f, "EXCEPTPGNET \n");
            break;

        case lefiGeomLayerMinSpacingE:
            fprintf(f, "Spacing %g\n",
                    getLayerMinSpacing(i));
            break;

        case lefiGeomLayerRuleWidthE:
            fprintf(f, "DesignRuleWidth %g\n",
                    getLayerRuleWidth(i));
            break;

        case lefiGeomWidthE:
            fprintf(f, "Width %g\n", getWidth(i));
            break;

        case lefiGeomPathE:
            path = getPath(i);
            fprintf(f, "Path");

            if (path->colorMask) {
                fprintf(f, " MASK %d", path->colorMask);
            }
            for (l = 0; l < path->numPoints; l++)
                fprintf(f, " %g,%g", path->x[l], path->y[l]);
            fprintf(f, "\n");
            break;

        case lefiGeomPathIterE:
            pathiter = getPathIter(i);

            if (pathiter->colorMask) {
                fprintf(f, "MASK %d", pathiter->colorMask);
            }

            fprintf(f, "Path iter  start %g,%g  step %g,%g\n",
                    pathiter->xStart, pathiter->yStart,
                    pathiter->xStep, pathiter->yStep);

            for (l = 0; l < pathiter->numPoints; l++) {
                fprintf(f, " %g,%g", pathiter->x[l], pathiter->y[l]);
            }

            fprintf(f, "\n");
            break;

        case lefiGeomRectE:
            rect = getRect(i);

            if (rect->colorMask) {
                fprintf(f, "Rect MASK %d, %g,%g  %g,%g\n", rect->colorMask,
                        rect->xl, rect->yl,
                        rect->xh, rect->yh);
            } else {
                fprintf(f, "Rect %g,%g  %g,%g\n", rect->xl, rect->yl,
                        rect->xh, rect->yh);
            }
            break;

        case lefiGeomRectIterE:
            rectiter = getRectIter(i);

            if (rectiter->colorMask) {
                fprintf(f, "Rect MASK %d iter  start %g,%g  step %g,%g\n",
                        rectiter->colorMask,
                        rectiter->xStart, rectiter->yStart,
                        rectiter->xStep, rectiter->yStep);
            } else {
                fprintf(f, "Rect iter  start %g,%g  step %g,%g\n",
                        rectiter->xStart, rectiter->yStart,
                        rectiter->xStep, rectiter->yStep);
            }

            fprintf(f, "     %g,%g  %g,%g\n", rectiter->xl, rectiter->yl,
                    rectiter->xh, rectiter->yh);
            break;

        case lefiGeomPolygonE:
            polygon = getPolygon(i);
            fprintf(f, "Polygon");

            if (polygon->colorMask) {
                fprintf(f, " MASK %d", polygon->colorMask);
            }

            for (l = 0; l < polygon->numPoints; l++) {
                fprintf(f, " %g,%g", polygon->x[l], polygon->y[l]);
            }

            fprintf(f, "\n");
            break;

        case lefiGeomPolygonIterE:
            polygoniter = getPolygonIter(i);

            if (polygoniter->colorMask) {
                fprintf(f, "Polygon MASK %d iter  start %g,%g  step %g,%g\n",
                        polygoniter->colorMask,
                        polygoniter->xStart, polygoniter->yStart,
                        polygoniter->xStep, polygoniter->yStep);
            } else {
                fprintf(f, "Polygon iter  start %g,%g  step %g,%g\n",
                        polygoniter->xStart, polygoniter->yStart,
                        polygoniter->xStep, polygoniter->yStep);
            }

            for (l = 0; l < polygoniter->numPoints; l++) {
                fprintf(f, " %g,%g", polygoniter->x[l], polygoniter->y[l]);
            }

            fprintf(f, "\n");
            break;

        case lefiGeomViaE:
            fprintf(f, "Via \n");
            break;

        case lefiGeomViaIterE:
            fprintf(f, "Via iter \n");
            break;

        case lefiGeomClassE:
            fprintf(f, "Classtype %s\n", (char*) items_[i]);
            break;

        default:
            lefiError(0, 1375, "ERROR (LEFPARS-1375): unknown geometry type");
            fprintf(f, "Unknown geometry type %d\n",
                    (int) (itemType(i)));
            break;
        }
    }
}

// *****************************************************************************
// lefiSpacing
// *****************************************************************************

lefiSpacing::lefiSpacing()
{
    Init();
}

void
lefiSpacing::Init()
{
    name1_ = (char*) lefMalloc(16);
    name2_ = (char*) lefMalloc(16);
    name1Size_ = 16;
    name2Size_ = 16;
    distance_ = 0;
    hasStack_ = 0;
}

void
lefiSpacing::Destroy()
{
    if (name1_)
        lefFree(name1_);
    if (name2_)
        lefFree(name2_);
}

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

lefiSpacing *
lefiSpacing::clone()
{
    lefiSpacing *sp = (lefiSpacing*) lefMalloc(sizeof(lefiSpacing));
    sp->name1Size_ = strlen(name1_) + 1;
    sp->name1_ = (char*) lefMalloc(sp->name1Size_);
    strcpy(sp->name1_, name1_);
    sp->name2Size_ = strlen(name2_) + 1;
    sp->name2_ = (char*) lefMalloc(sp->name2Size_);
    strcpy(sp->name2_, name2_);
    sp->distance_ = distance_;
    sp->hasStack_ = hasStack_;
    return sp;
}

void
lefiSpacing::set(const char *name1,
                 const char *name2,
                 double     d,
                 int        hasStack)
{
    int len = strlen(name1) + 1;
    if (len > name1Size_) {
        lefFree(name1_);
        name1_ = (char*) lefMalloc(len);
        name1Size_ = len;
    }
    len = strlen(name2) + 1;
    if (len > name2Size_) {
        lefFree(name2_);
        name2_ = (char*) lefMalloc(len);
        name2Size_ = len;
    }
    strcpy(name1_, CASE(name1));
    strcpy(name2_, CASE(name2));
    distance_ = d;
    hasStack_ = hasStack;
}

const char *
lefiSpacing::name1() const
{
    return name1_;
}

const char *
lefiSpacing::name2() const
{
    return name2_;
}

double
lefiSpacing::distance() const
{
    return distance_;
}

int
lefiSpacing::hasStack() const
{
    return hasStack_;
}
void
lefiSpacing::print(FILE *f) const
{
    fprintf(f, "SPACING %s %s %g", name1(),
            name2(), distance());

    if (hasStack())
        fprintf(f, "  STACK");

    fprintf(f, "\n");
}

// *****************************************************************************
// lefiIRDrop
// *****************************************************************************

lefiIRDrop::lefiIRDrop()
{
    Init();
}

void
lefiIRDrop::Init()
{
    nameSize_ = 16;
    value1Size_ = 16;
    value2Size_ = 16;
    name_ = (char*) lefMalloc(16);
    numValues_ = 0;
    valuesAllocated_ = 2;
    value1_ = (double*) lefMalloc(sizeof(double) * 2);
    value2_ = (double*) lefMalloc(sizeof(double) * 2);
}

void
lefiIRDrop::Destroy()
{
    lefFree(name_);
    clear();
    lefFree((char*) (value1_));
    lefFree((char*) (value2_));
}

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

void
lefiIRDrop::clear()
{
    numValues_ = 0;
}

void
lefiIRDrop::setTableName(const char *name)
{
    int len = strlen(name) + 1;
    if (len > nameSize_) {
        lefFree(name_);
        name_ = (char*) lefMalloc(len);
        nameSize_ = len;
    }
    strcpy(name_, CASE(name));
    clear();
    /*
      *(value1_) = '\0';
      *(value2_) = '\0';
    */
}

void
lefiIRDrop::setValues(double    value1,
                      double    value2)
{
    if (numValues_ == valuesAllocated_) {
        int     i;
        double  *v1;
        double  *v2;
        if (valuesAllocated_ == 0) {
            valuesAllocated_ = 2;
            v1 = (double*) lefMalloc(sizeof(double) * valuesAllocated_);
            v2 = (double*) lefMalloc(sizeof(double) * valuesAllocated_);
        } else {
            valuesAllocated_ *= 2;
            v1 = (double*) lefMalloc(sizeof(double) * valuesAllocated_);
            v2 = (double*) lefMalloc(sizeof(double) * valuesAllocated_);
            for (i = 0; i < numValues_; i++) {
                v1[i] = value1_[i];
                v2[i] = value2_[i];
            }
            lefFree((char*) (value1_));
            lefFree((char*) (value2_));
        }
        value1_ = v1;
        value2_ = v2;
    }
    value1_[numValues_] = value1;
    value2_[numValues_] = value2;
    numValues_ += 1;
}

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

int
lefiIRDrop::numValues() const
{
    return numValues_;
}

double
lefiIRDrop::value1(int index) const
{
    char msg[160];
    if (index < 0 || index >= numValues_) {
        sprintf(msg, "ERROR (LEFPARS-1376): The index number %d given for the IRDROP is invalid.\nValid index is from 0 to %d", index, numValues_);
        lefiError(0, 1376, msg);
        return 0;
    }
    return value1_[index];
}

double
lefiIRDrop::value2(int index) const
{
    char msg[160];
    if (index < 0 || index >= numValues_) {
        sprintf(msg, "ERROR (LEFPARS-1376): The index number %d given for the IRDROP is invalid.\nValid index is from 0 to %d", index, numValues_);
        lefiError(0, 1376, msg);
        return 0;
    }
    return value2_[index];
}

void
lefiIRDrop::print(FILE *f) const
{
    int i;
    fprintf(f, "IRDROP %s ", name());
    for (i = 0; i < numValues(); i++) {
        fprintf(f, "%g %g ", value1(i),
                value2(i));
    }
    fprintf(f, "\n");
    fprintf(f, "END IRDrop\n");
}

// *****************************************************************************
// lefitMinFeature
// *****************************************************************************
lefiMinFeature::lefiMinFeature()
{
    Init();
}

void
lefiMinFeature::Init()
{
    // nothing to do
}

void
lefiMinFeature::Destroy()
{
    // nothing to do
}

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

void
lefiMinFeature::set(double  one,
                    double  two)
{
    one_ = one;
    two_ = two;
}

double
lefiMinFeature::one() const
{
    return one_;
}

double
lefiMinFeature::two() const
{
    return two_;
}

void
lefiMinFeature::print(FILE *f) const
{
    fprintf(f, "MINfEATURE %g %g\n", one(),
            two());
}

// *****************************************************************************
// lefiSite
// *****************************************************************************

lefiSite::lefiSite()
{
    Init();
}

void
lefiSite::Init()
{
    nameSize_ = 16;
    name_ = (char*) lefMalloc(16);
    numRowPattern_ = 0;
    rowPatternAllocated_ = 0;
    siteNames_ = 0;
    siteOrients_ = 0;
}

void
lefiSite::Destroy()
{
    int i;

    lefFree(name_);
    if (numRowPattern_) {
        for (i = 0; i < numRowPattern_; i++)
            lefFree(siteNames_[i]);
        lefFree(siteNames_);
        lefFree(siteOrients_);
        numRowPattern_ = 0;
    }
}

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

void
lefiSite::setName(const char *name)
{
    int i;
    int len = strlen(name) + 1;
    if (len > nameSize_) {
        lefFree(name_);
        name_ = (char*) lefMalloc(len);
        nameSize_ = len;
    }
    strcpy(name_, CASE(name));
    hasClass_ = 0;
    *(siteClass_) = 0;
    hasSize_ = 0;
    symmetry_ = 0;
    if (numRowPattern_) {
        for (i = 0; i < numRowPattern_; i++)
            lefFree(siteNames_[i]);
        numRowPattern_ = 0;
    }
}

void
lefiSite::setClass(const char *cls)
{
    strcpy(siteClass_, cls);
    hasClass_ = 1;
}

void
lefiSite::setSize(double    x,
                  double    y)
{
    hasSize_ = 1;
    sizeX_ = x;
    sizeY_ = y;
}

void
lefiSite::setXSymmetry()
{
    symmetry_ |= 1;
}

void
lefiSite::setYSymmetry()
{
    symmetry_ |= 2;
}

void
lefiSite::set90Symmetry()
{
    symmetry_ |= 4;
}

void
lefiSite::addRowPattern(const char  *name,
                        int         orient)
{
    if (numRowPattern_ == rowPatternAllocated_) {
        int     i;
        char    **sn;
        int     *so;

        rowPatternAllocated_ = (rowPatternAllocated_ == 0) ? 2 :
            rowPatternAllocated_ * 2;
        sn = (char**) lefMalloc(sizeof(char*) * rowPatternAllocated_);
        so = (int*) lefMalloc(sizeof(int) * rowPatternAllocated_);
        for (i = 0; i < numRowPattern_; i++) {
            sn[i] = siteNames_[i];
            so[i] = siteOrients_[i];
        }
        if (siteNames_) {
            lefFree((char*) (siteNames_));
            lefFree((char*) (siteOrients_));
        }
        siteNames_ = sn;
        siteOrients_ = so;
    }
    siteNames_[numRowPattern_] = strdup(name);
    siteOrients_[numRowPattern_] = orient;
    numRowPattern_ += 1;
}

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

int
lefiSite::hasClass() const
{
    return hasClass_;
}

const char *
lefiSite::siteClass() const
{
    return siteClass_;
}

double
lefiSite::sizeX() const
{
    return sizeX_;
}

double
lefiSite::sizeY() const
{
    return sizeY_;
}

int
lefiSite::hasSize() const
{
    return hasSize_;
}

int
lefiSite::hasXSymmetry() const
{
    return (symmetry_ & 1) ? 1 : 0;
}

int
lefiSite::hasYSymmetry() const
{
    return (symmetry_ & 2) ? 1 : 0;
}

int
lefiSite::has90Symmetry() const
{
    return (symmetry_ & 4) ? 1 : 0;
}

int
lefiSite::hasRowPattern() const
{
    return (numRowPattern_) ? 1 : 0;
}

int
lefiSite::numSites() const
{
    return (numRowPattern_);
}

char *
lefiSite::siteName(int index) const
{
    return (siteNames_[index]);
}

int
lefiSite::siteOrient(int index) const
{
    return (siteOrients_[index]);
}

char *
lefiSite::siteOrientStr(int index) const
{
    return (lefiOrientStr(siteOrients_[index]));
}

void
lefiSite::print(FILE *f) const
{
    fprintf(f, "SITE %s", name());

    if (hasClass())
        fprintf(f, " CLASS %s", siteClass());

    if (hasSize())
        fprintf(f, " SIZE %g %g", sizeX(),
                sizeY());

    if (hasXSymmetry())
        fprintf(f, " SYMMETRY X");

    if (hasYSymmetry())
        fprintf(f, " SYMMETRY Y");

    if (has90Symmetry())
        fprintf(f, " SYMMETRY R90");

    fprintf(f, "\n");
}

// *****************************************************************************
// lefiSitePattern
// *****************************************************************************

lefiSitePattern::lefiSitePattern()
{
    Init();
}

void
lefiSitePattern::Init()
{
    nameSize_ = 16;
    name_ = (char*) lefMalloc(16);
}

void
lefiSitePattern::Destroy()
{
    lefFree(name_);
}

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

void
lefiSitePattern::set(const char *name,
                     double     x,
                     double     y,
                     int        orient,
                     double     xStart,
                     double     yStart,
                     double     xStep,
                     double     yStep)
{
    int len = strlen(name) + 1;
    if (len > nameSize_) {
        lefFree(name_);
        name_ = (char*) lefMalloc(len);
        nameSize_ = len;
    }
    strcpy(name_, CASE(name));

    x_ = x;
    y_ = y;
    xStep_ = xStep;
    yStep_ = yStep;
    xStart_ = xStart;
    yStart_ = yStart;
    orient_ = orient;
}

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

int
lefiSitePattern::orient() const
{
    return orient_;
}

const char *
lefiSitePattern::orientStr() const
{
    return (lefiOrientStr(orient_));
}

double
lefiSitePattern::x() const
{
    return x_;
}

double
lefiSitePattern::y() const
{
    return y_;
}

int
lefiSitePattern::hasStepPattern() const
{
    if (xStart_ == -1 && yStart_ == -1 &&
        xStep_ == -1 && yStep_ == -1)
        return 0;
    return 1;
}

double
lefiSitePattern::xStart() const
{
    return xStart_;
}

double
lefiSitePattern::yStart() const
{
    return yStart_;
}

double
lefiSitePattern::xStep() const
{
    return xStep_;
}

double
lefiSitePattern::yStep() const
{
    return yStep_;
}

void
lefiSitePattern::print(FILE *f) const
{
    fprintf(f, "  SITE Pattern %s  %g,%g %s\n",
            name(),
            x(),
            y(),
            orientStr());
    fprintf(f, "    %g,%g step %g,%g\n",
            xStart(),
            yStart(),
            xStep(),
            yStep());
}

// *****************************************************************************
// lefiTrackPattern
// *****************************************************************************

lefiTrackPattern::lefiTrackPattern()
{
    Init();
}

void
lefiTrackPattern::Init()
{
    nameSize_ = 16;
    name_ = (char*) lefMalloc(16);
    start_ = 0;
    numTracks_ = 0;
    space_ = 0;
    numLayers_ = 0;
    layerAllocated_ = 2;
    layerNames_ = (char**) lefMalloc(sizeof(char*) * 2);
    clear();
}

void
lefiTrackPattern::Destroy()
{
    if (name_)
        lefFree(name_);
    clear();
    name_ = 0;
    start_ = 0;
    numTracks_ = 0;
    space_ = 0;
    lefFree((char*) (layerNames_));
}

void
lefiTrackPattern::clear()
{
    int i;
    for (i = 0; i < numLayers_; i++) {
        lefFree(layerNames_[i]);
    }
}

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

void
lefiTrackPattern::set(const char    *name,
                      double        start,
                      int           numTracks,
                      double        space)
{
    int len = strlen(name) + 1;
    if (len > nameSize_) {
        lefFree(name_);
        name_ = (char*) lefMalloc(len);
        nameSize_ = len;
    }
    strcpy(name_, CASE(name));

    start_ = start;
    numTracks_ = numTracks;
    space_ = space;
}

void
lefiTrackPattern::addLayer(const char *name)
{
    int len;
    if (numLayers_ == layerAllocated_) {
        int     i;
        char    **nn;

        if (layerAllocated_ == 0)
            layerAllocated_ = 2;
        else
            layerAllocated_ *= 2;
        nn = (char**) lefMalloc(sizeof(char*) * layerAllocated_);
        for (i = 0; i < numLayers_; i++)
            nn[i] = layerNames_[i];
        lefFree((char*) (layerNames_));
        layerNames_ = nn;
    }
    len = strlen(name) + 1;
    layerNames_[numLayers_] = (char*) lefMalloc(len);
    strcpy(layerNames_[numLayers_], CASE(name));
    numLayers_ += 1;
}

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

double
lefiTrackPattern::start() const
{
    return start_;
}

int
lefiTrackPattern::numTracks() const
{
    return numTracks_;
}

double
lefiTrackPattern::space() const
{
    return space_;
}

int
lefiTrackPattern::numLayers() const
{
    return numLayers_;
}

const char *
lefiTrackPattern::layerName(int index) const
{
    char msg[160];
    if (index < 0 || index >= numLayers_) {
        sprintf(msg, "ERROR (LEFPARS-1377): The index number %d given for the TRACK PATTERN  is invalid.\nValid index is from 0 to %d", index, numLayers_);
        lefiError(0, 1377, msg);
        return 0;
    }
    return layerNames_[index];
}

void
lefiTrackPattern::print(FILE *f) const
{
    int i;
    fprintf(f, "  TRACK Pattern %s  %g DO %d STEP %g\n",
            name(),
            start(),
            numTracks(),
            space());
    if (numLayers() > 0) {
        fprintf(f, "    LAYER ");
        for (i = 0; i < numLayers(); i++)
            fprintf(f, "%s ", layerName(i));
        fprintf(f, "\n");
    }
}

// *****************************************************************************
// lefiGcellPattern
// *****************************************************************************

lefiGcellPattern::lefiGcellPattern()
{
    Init();
}

void
lefiGcellPattern::Init()
{
    nameSize_ = 16;
    name_ = (char*) lefMalloc(16);
    start_ = 0;
    numCRs_ = 0;
    space_ = 0;
}

void
lefiGcellPattern::Destroy()
{
    if (name_)
        lefFree(name_);
    name_ = 0;
    start_ = 0;
    numCRs_ = 0;
    space_ = 0;
}

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

void
lefiGcellPattern::set(const char    *name,
                      double        start,
                      int           numCRs,
                      double        space)
{
    int len = strlen(name) + 1;
    if (len > nameSize_) {
        lefFree(name_);
        name_ = (char*) lefMalloc(len);
        nameSize_ = len;
    }
    strcpy(name_, CASE(name));

    start_ = start;
    numCRs_ = numCRs;
    space_ = space;
}

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

double
lefiGcellPattern::start() const
{
    return start_;
}

int
lefiGcellPattern::numCRs() const
{
    return numCRs_;
}

double
lefiGcellPattern::space() const
{
    return space_;
}

void
lefiGcellPattern::print(FILE *f) const
{
    fprintf(f, "  TRACK Pattern %s  %g DO %d STEP %g\n",
            name(),
            start(),
            numCRs(),
            space());
}

// *****************************************************************************
// lefiUseMinSpacing
// *****************************************************************************

lefiUseMinSpacing::lefiUseMinSpacing()
{
    Init();
}

void
lefiUseMinSpacing::Init()
{
    name_ = 0;
    value_ = 0;
}

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

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

void
lefiUseMinSpacing::set(const char   *name,
                       int          value)
{

    Destroy();  // lefFree previous name, if there is any
    name_ = (char*) lefMalloc(strlen(name) + 1);
    strcpy(name_, CASE(name));
    value_ = value;
}

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

int
lefiUseMinSpacing::value() const
{
    return value_;
}

void
lefiUseMinSpacing::print(FILE *f) const
{
    fprintf(f, "USEMINSPACING %s %d\n",
            name(),
            value());
}

// *****************************************************************************
// lefiMaxStackVia
// *****************************************************************************

lefiMaxStackVia::lefiMaxStackVia()
{
    bottomLayer_ = 0;
    topLayer_ = 0;
    Init();
}

void
lefiMaxStackVia::Init()
{
    value_ = 0;
    hasRange_ = 0;
    if (bottomLayer_)          // This is for C version, since C will
        lefFree(bottomLayer_);  // call this function before calling
    if (topLayer_)             // setMaxStackViaRange when more than 1 lef
        lefFree(topLayer_);     // files are parse. C++ skips this function
    bottomLayer_ = 0;
    topLayer_ = 0;
}

void
lefiMaxStackVia::Destroy()
{
    if (bottomLayer_)
        lefFree(bottomLayer_);
    if (topLayer_)
        lefFree(topLayer_);
    bottomLayer_ = 0;
    topLayer_ = 0;
    hasRange_ = 0;
    value_ = 0;
}

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

void
lefiMaxStackVia::setMaxStackVia(int value)
{
    value_ = value;
}

void
lefiMaxStackVia::setMaxStackViaRange(const char *bottomLayer,
                                     const char *topLayer)
{
    hasRange_ = 1;
    if (bottomLayer_)          // May be lefrReset is called and 
        lefFree(bottomLayer_);  // bottomLayer_ and/or topLayer_ have
    if (topLayer_)             // value malloc on them
        lefFree(topLayer_);
    bottomLayer_ = (char*) lefMalloc(strlen(bottomLayer) + 1);
    strcpy(bottomLayer_, CASE(bottomLayer));
    topLayer_ = (char*) lefMalloc(strlen(topLayer) + 1);
    strcpy(topLayer_, CASE(topLayer));
    //bottomLayer_ = strdup(bottomLayer);
    //topLayer_    = strdup(topLayer);
}

int
lefiMaxStackVia::maxStackVia() const
{
    return value_;
}

int
lefiMaxStackVia::hasMaxStackViaRange() const
{
    return hasRange_ ? 1 : 0;
}

const char *
lefiMaxStackVia::maxStackViaBottomLayer() const
{
    return bottomLayer_;
}

const char *
lefiMaxStackVia::maxStackViaTopLayer() const
{
    return topLayer_;
}

void
lefiMaxStackVia::print(FILE *f) const
{
    fprintf(f, "MAXVIASTACK %d", maxStackVia());
    if (hasMaxStackViaRange())
        fprintf(f, " RANGE %s %s", maxStackViaBottomLayer(),
                maxStackViaTopLayer());
    fprintf(f, "\n");
}
END_LEFDEF_PARSER_NAMESPACE

