#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai

from __future__ import (unicode_literals, division, absolute_import, print_function)

import json
import re

from .python_transition import (IS_PYTHON2)


__license__ = 'GPL v3'
__copyright__ = '2012-2025, John Howell <jhowell@acm.org>'


def js_value(log, js, prefix, fix_keys=False):
    # find right place in script for needed value
    # treat spaces as optional white space and * as matching arbitrary text for match

    #log.info('load: %s' % js)

    search_re = re.escape(' %s ' % prefix).replace(r'\*', r'.+?').replace(r'\ ', r'\s*')

    m = re.search(search_re, js)
    if not m:
        log.info('re: ' + search_re)
        log.info('script: ' + js)
        raise ValueError('Missing "%s" in script' % prefix)

    start_pos = i = m.end()
    start_char = js[start_pos]

    if start_char == '[':       # list
        end_chars = ']'
    elif start_char == '{':     # dict
        end_chars = '}'
    elif start_char == '(':     # function args
        end_chars = ')'
    else:                       # simple value
        i -= 1
        start_char = None
        end_chars = ';,'

    # simple scan for terminator. Ignores braces in strings. and handles nesting
    level = 1
    in_string = False
    string_term = None
    esc_str = False

    while (level > 0):
        i += 1

        if i >= len(js):
            raise ValueError('Missing terminator')

        #log.info('ch="%s" end_chars="%s" level=%d in_string=%s'%(js[i], end_chars, level, in_string))

        if not in_string:
            if js[i] == '"' or js[i] == "'":
                in_string = True
                esc_str = False
                string_term = js[i]
                js = js[:i] + '"' + js[i+1:]   # fix string for json

            elif js[i] == start_char:
                level += 1

            elif js[i] in end_chars:
                level -= 1

        elif esc_str:
            esc_str = False

        elif js[i] == '\\':
            esc_str = True

        elif js[i] == string_term:
            in_string = False
            js = js[:i] + '"' + js[i+1:]   # fix string for json

    if js[i] in ';,':
        i -= 1  # don't include terminator

    if start_char == '(':
        json_text = "[" + js[start_pos+1:i] + "]"   # convert to list
    else:
        json_text = js[start_pos:i+1]

    while True:
        #log.info('loading: %s' % json_text)

        try:
            json_data = json.loads(json_text)

        except Exception as e:
            #log.info("Exception %s: %s" % (type(e).__name__, str(e)))

            if fix_keys and isinstance(e, ValueError if IS_PYTHON2 else json.JSONDecodeError) and 'Expecting property name' in str(e):
                # ValueError: Expecting property name: line 1 column 110143 (char 110142)
                # ValueError: Expecting property name enclosed in double quotes: line 1 column 110143 (char 110142)

                if IS_PYTHON2:
                    r = str(e).split()
                    i = int(r[-1][:-1])
                else:
                    i = e.pos

                #self.log.info('from:' + json_text[i:][:40])

                have_key = re.match(r'^([a-zA-Z0-9]+) *:', json_text[i:][:40])
                if have_key:
                    len_key = len(have_key.group(1))
                    json_text = json_text[0:i] + '"' + json_text[i:][:len_key] + '"' + json_text[i+len_key:]
                    #self.log.info('to:  ' + json_text[i:][:20])
                    continue

            log.info('loading: %s' % json_text)
            raise

        break

    #log.info('loaded: %s' % str(json_data))

    return json_data
