#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dpstring.h>
#include <dpstringlist.h>
#include "dpuser.h"
#include "dpuser_utils.h"
#include <fits.h>

#ifdef WIN
#pragma warning (disable: 4996) // disable warning for deprecated POSIX name
#endif

#ifdef DPQT
#include <qtdpuser.h>
#include <QFitsGlobal.h>
#endif

char *readlinebuffer;
char *bbuf;

int include_stack_ptr = 0;
extern int scriptlock;
#define MAX_INCLUDE_DEPTH 10
FILE* include_stack[MAX_INCLUDE_DEPTH];
extern int parseError;
extern char* yytext;
extern std::string currentLine;
extern int currentColumn;
bool idlmode = false;
bool pythonmode = false;

// tweak the input such that the parser can savely go through
char *tweakInput(char *buf) {
    int i, l, p;
    char *result, *pp;
    dpString inp;

    p = 1;
    l = strlen(buf);
    for (i = 0; i < l; i++) if (buf[i] == '}') p++;
    result = (char *)malloc((l + p + 1) * sizeof(char));
    strcpy(result, buf);
    for (i = 0; i < l; i++) if (result[i] == '\n') result[i] = ' ';

/* delete trailing blanks */
    while ((l > 0) && ((result[l - 1] == ' ') || (result[l - 1] == '\t'))) {
        l--;
        result[l] = (char)0;
    }

/* Insert a ';' before each '}', if necessary */
    pp = result;
    while ((pp = strchr(pp, '}')) != NULL) {
        if (pp != result) {
// is this within a string?
            dpString test;
            int i;
            for (i = 0; result + i < pp; i++) test += result[i];
            if (!(test.contains('"') % 2) && !(test.contains('\'') % 2)) {
                p = -1;
                while ((pp + p >= result) && ((pp[p] == ' ') || (pp[p] == '\t'))) p--;
                if ((pp + p >= result) && (pp[p] != '}') && (pp[p] != ';')) {
                    for (i = l; i >= pp-result; i--) result[i + 1] = result[i];
                    pp[0] = ';';
                }
            }
        }
        pp++;
        if (pp[0] == (char)0) break;
    }

/* Insert a ';' at the end if necessary */
    l = strlen(result);
    if ((l > 0) && (result[l - 1] != '}') && (result[l - 1] != '{') && (result[l - 1] != ';')) {
        result[l] = ';';
        result[l + 1] = (char)0;
    }

/* replace @script; by run "script";
   only do this if at the beginning of a line (excluding whitespaces) */
    inp = result;
        inp = inp.stripWhiteSpace();
        if (inp[0] == '@') {
            i = 0;
            p = -1;
            inp.replace(i, 1, "run \"");
            p = inp.find(';', i);
            inp.replace(p, 1, "\";");
        }

    if (p != -1) {
        result = (char *)realloc(result, inp.length() * sizeof(char) + 1);
        strcpy(result, inp.c_str());
    }

    return result;
}

int getInput(char *buf, int max_size) {
	int n, length, s;
	char *bbuf;
    dpString pythoninput;
    bool pythonscript = false;

	if (parseError && include_stack_ptr) {
		dp_output("parse error executing script.\n");
		while (include_stack_ptr) {
			fclose(include_stack[include_stack_ptr]);
			include_stack_ptr--;
			rl_instream = include_stack[include_stack_ptr];
		}
	}
	if (ScriptInterrupt && include_stack_ptr) {
		while (include_stack_ptr) {
			fclose(include_stack[include_stack_ptr]);
			include_stack_ptr--;
			rl_instream = include_stack[include_stack_ptr];
		}
		dp_output("script aborted.\n");
	}
	if (ScriptInterrupt || parseError) script.clear();
	ScriptInterrupt = 0;
	s = 0;
	if (script.count() > 0) {
		scriptlock = 1;
		dpString line;
		s = 1;
		line = script.first();
		script.remove(script.begin());
        if (idlmode) {
            while (line.right(1) == "$") {
                line.remove(line.length()-1, 1);
                line += " ";
                line += script.first();
                script.remove(script.begin());
            }
        } else {
            while (line.right(1) == "\\") {
                line.remove(line.length()-1, 1);
                line += " ";
                line += script.first();
                script.remove(script.begin());
            }
        }
        if (idlmode) {
            line = line.stripWhiteSpace();
            if (line.left(3) == "pro") {
                line.remove(0, 3);
                line = "procedure" + line + " {";
                script.insert(script.begin(), "cnotation");
            } else if (line.left(8) == "function") {
                line += " {";
                script.insert(script.begin(), "cnotation");
            }
            line.replace(";", "//");
            line.replace("!DPI", "pi()");
        }
        readlinebuffer = strdup(line.c_str());

        if (dpdebuglevel) {
            dp_output("%s\n", readlinebuffer);
        }
    } else if (include_stack_ptr) {
		readlinebuffer = readline("");
    } else if (pythonmode) {
        readlinebuffer = readline(">>> ");
    } else {
        readlinebuffer = readline("DPUSER> ");
    }
    if (script.count() == 0) idlmode = false;

	if (readlinebuffer != NULL) {
        if ((strlen(readlinebuffer) > 0) &&
            (!include_stack_ptr) &&
            (strcmp(readlinebuffer, "exit") != 0) &&
            (strcmp(readlinebuffer, "quit") != 0) &&
            (strcmp(readlinebuffer, "bye") != 0) &&
            (s == 0))
        {
            add_history(readlinebuffer);
        }
        if (pythonmode) {
            dpString line = readlinebuffer;
            if (pythonscript == false && line.left(3) == "def" && line.right(1) == ":") {
                pythonscript = true;
#ifdef DPQT
                dpuser_widget->prompt->setText("    ...");
#endif
                while (pythonscript) {
                    pythoninput += line;
                    dpString _tmp = line;
                    _tmp.strtrim(1);
                    if (_tmp.left(6) == "return") {
                        pythonscript = false;
#ifdef DPQT
                        dpuser_widget->prompt->setText("    >>>");
#endif
                    } else {
                        pythoninput += "\\n";
                        free(readlinebuffer);
                        readlinebuffer = readline("... ");
                        line = readlinebuffer;
                    }
                }
            } else {
                pythoninput = line;
            }
            snprintf(buf, max_size, "python \"%s\";\n", pythoninput.c_str());
            pythoninput = "";
            length = strlen(buf);
        } else {
            bbuf = tweakInput(readlinebuffer);
            if (dpdebuglevel) {
                dp_output("%s\n", bbuf);
            }

            for (n = 0; n < (int)strlen(bbuf); n++) {
                buf[n] = bbuf[n];
            }
            buf[n++] = '\n';
            buf[n+1] = 0;
            length = n;
            free(bbuf);
        }
        currentLine = readlinebuffer;
        currentColumn = 0;
		free(readlinebuffer);
	} else {
		buf[0] = 'E';
		buf[1] = 'O';
		buf[2] = 'F';
		buf[3] = '\n';
		buf[4] = 0;
		length = 4;
	}

	return length;
}
