#ifdef WIN
#pragma warning (disable: 4786) // disable warning for STL maps
#endif /* WIN */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "dpuser.h"
#include "functions.h"
#include "procedures.h"
#include "dpuser_utils.h"
#include "dpuserType.h"
#include <fits.h>
#include <dpstring.h>

std::string currentLine;
int currentColumn;

void yyerror(const char *s) {
    std::string location = "   ";
    for (int i = 1; i < currentColumn; i++) location += '-';
    location += '^';
    dp_output("%s in the following line:\n   %s\n%s\n", s, currentLine.c_str(), location.c_str());
}

//
// create variable
//
void protect(void *pntr) {
    int i, j;

    // see if symbol already exists
    for (i = 0; i < nprotected; i++) {
        if (protectedpntrs[i]) {
            if (protectedpntrs[i] == pntr) {
                return;
            }
        }
    }

    // find free node
    for (i = 0; i < nprotected; i++) {
        if (protectedpntrs[i] == NULL) {
            protectedpntrs[i] = pntr;
            return;
        }
    }

    // expand table
    nprotected += 100;
    protectedpntrs = (void **)realloc(protectedpntrs, nprotected * sizeof(void *));
    for (j = i; j < nprotected; j++) {
        protectedpntrs[j] = NULL;
    }
    protectedpntrs[i] = pntr;
}

void unprotect(void *pntr) {
    for (int i = 0; i < nprotected; i++) {
        if (protectedpntrs[i]) {
            if (protectedpntrs[i] == pntr) {
                protectedpntrs[i] = NULL;
                return;
            }
        }
    }
}

void unprotect() {
    for (int i = 0; i < nprotected; i++) {
        protectedpntrs[i] = NULL;
    }
}

//
// Garbage Collector:
//
// Set all pointers to NULL on variables with not matching type
//
void consolidateVariables() {
    for (auto var:dpuser_vars) {
        if (var.second.svalue) {
            if (var.second.type != typeStr) {
                var.second.svalue = NULL;
            }
        } else if (var.second.type == typeStr) {
            var.second.type = typeUnknown;
        }

        if (var.second.arrvalue) {
            if (var.second.type != typeStrarr) {
                var.second.arrvalue = NULL;
            }
        } else if (var.second.type == typeStrarr) {
            var.second.type = typeUnknown;
        }

        if (var.second.cvalue) {
            if (var.second.type != typeCom) {
                var.second.cvalue = NULL;
            }
        } else if (var.second.type == typeCom) {
            var.second.type = typeUnknown;
        }

        if (var.second.fvalue) {
            if (var.second.type != typeFits) {
                var.second.fvalue = NULL;
            }
        } else if (var.second.type == typeFits) {
            var.second.type = typeUnknown;
        }

        if (var.second.dparrvalue) {
            if (var.second.type != typeDpArr) {
                var.second.dparrvalue = NULL;
            }
        } else if (var.second.type == typeDpArr) {
            var.second.type = typeUnknown;
        }
    }
}

//
// Deletes all allocated objects which are not stored in local variables
//
void freePointerlist() {
//    consolidateVariables();

    for (long i = 0; i < nListOfdpStringArrays; i++) {
        if (listOfdpStringArrays[i]) {
            if (isVariable(listOfdpStringArrays[i]) == 0) {
                DeleteStringArray(listOfdpStringArrays[i]);
            }
        }
    }
    for (long i = 0; i < nListOfOComplex; i++) {
        if (listOfOComplex[i]) {
            if (isVariable(listOfOComplex[i]) == 0) {
                DeleteComplex(listOfOComplex[i]);
            }
        }
    }
    for (long i = 0; i < nListOfFits; i++) {
        if (listOfFits[i]) {
            if (isVariable(listOfFits[i]) == 0) {
                DeleteFits(listOfFits[i]);
            }
        }
    }
    for (long i = 0; i < nListOfDpLists; i++) {
        if (listOfDpLists[i]) {
            if (isVariable(listOfDpLists[i]) == 0) {
                DeleteDpList(listOfDpLists[i]);
            }
        }
    }
}
