import os
import random
import string
import subprocess
import time
import json

from django.conf import settings
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt


def generate_filename():
    filename = ''
    for x in range(10):
        filename += random.choice(string.ascii_letters)
    return filename


@csrf_exempt
def execute_programs(request):
    if request.method == 'POST':
        data = json.loads(request.body)
        try:
            language = data.get("language")
            code = data.get('code')
            if language == 'python':
                output = python_output(code)
            elif language == 'c':
                output = c_output(code)
            elif language == 'c++':
                output = cpp_output(code)
            elif language == 'java':
                output = java_output(code)
            else:
                output = 'Program language not supported.'
            response = {'status': 'Success', 'status_code': 200, 'message': output}
        except Exception as ex:
            response = {'status': 'Failure', 'status_code': 401,
                        'message': 'Data issue, Please try again.'}
    else:
        response = {'status': 'Failure', 'status_code': 405, 'message': 'Method Not Allowed.'}
    return HttpResponse(json.dumps(response), content_type='application/javascript')


def python_output(code):
    file_name = generate_filename() + '.py'
    try:
        file_name = settings.FILE_EXECUTING_PATH + file_name
        f = open(file_name, 'w')
        f.write(code)
        f.close()
        proc = subprocess.Popen(['python3', file_name], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False)
        n = 0
        while 1:
            if proc.poll() is not None:
                output = proc.stdout.read()
                break
            time.sleep(1)
            n = n + 1
            if n >= 5:
                proc.kill()
        try:
            os.remove(file_name)
        except:
            pass
    except:
        output = ''
    return str(output)
    # return str(output, encoding='UTF-8')


def java_output(code):
    output = ''
    file_name = generate_filename() + '.java'
    try:
        file_name = settings.FILE_EXECUTING_PATH + file_name
        f = open(file_name, 'w')
        f.write(code)
        f.close()
        proc = subprocess.Popen(['java', file_name], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False)
        n = 0
        while 1:
            if proc.poll() is not None:
                output = proc.stdout.read()
                break
            time.sleep(1)
            n = n + 1
            if n >= 5:
                proc.kill()
    except:
        output = ''
    finally:
        try:
            os.remove(file_name)
        except Exception as ex:
            pass

    return str(output)


def c_output(code):
    try:
        file_name = generate_filename()
        file_name = settings.FILE_EXECUTING_PATH + file_name
        f = open(file_name + ".c", 'w')
        f.write(code)
        f.close()
        compl = subprocess.Popen(['gcc', '-o', file_name, file_name + '.c'], stdout=subprocess.PIPE,
                                 stderr=subprocess.STDOUT)
        compl_output = compl.communicate()[0]
        if b'warning' in compl_output.lower():
            output = compl_output + b'\n'
            try:
                out = subprocess.Popen(file_name, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
                n = 0
                while 1:
                    if out.poll() is not None:
                        output += out.stdout.read()
                        break
                    time.sleep(1)
                    n += 1
                    if n >= 5:
                        out.kill()
            except:
                output = compl_output

        else:
            if compl_output:
                output = compl_output
            else:
                out = subprocess.Popen(file_name, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
                n1 = 0
                while 1:
                    if out.poll() is not None:
                        output = out.stdout.read()
                        break
                    time.sleep(1)
                    n1 += 1
                    if n1 >= 5:
                        out.kill()
        try:
            os.remove(file_name + '.c')
            os.remove(file_name)
            os.remove(file_name + '.exe')
        except:
            pass
    except:
        output = ''
    return str(output)


def cpp_output(code):
    try:
        file_name = generate_filename()
        file_name = settings.FILE_EXECUTING_PATH + file_name
        f = open(file_name + ".cpp", 'w')
        f.write(code)
        f.close()
        compl = subprocess.Popen(['g++', '-o', file_name, file_name + '.cpp'], stdout=subprocess.PIPE,
                                 stderr=subprocess.STDOUT)
        compl_output = compl.communicate()[0]
        if b'warning' in compl_output.lower():
            output = compl_output + b'\n'
            try:
                out = subprocess.Popen(file_name, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
                n = 0
                while 1:
                    if out.poll() is not None:
                        output += out.stdout.read()
                        break
                    time.sleep(1)
                    n += 1
                    if n >= 5:
                        out.kill()
            except:
                output = compl_output
        else:
            if compl_output:
                output = compl_output
            else:
                out = subprocess.Popen(file_name, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
                n1 = 0
                while 1:
                    if out.poll() is not None:
                        output = out.stdout.read()
                        break
                    time.sleep(1)
                    n1 += 1
                    if n1 >= 5:
                        out.kill()
        try:
            os.remove(file_name + '.cpp')
            os.remove(file_name)
            os.remove(file_name + '.exe')
        except:
            pass
    except:
        output = ''
    return str(output)
