#!/usr/bin/python3
# -*- coding: utf-8 -*-

#  Copyright © 2018  B. Clausius <barcc@gmx.de>
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.


import sys, os
from .json.decoder import JSONDecoder, JSONDecodeError
from .json.scanner import py_make_scanner as make_json_scanner

from . import ClassParserInterface, register_parser


class CustomJSONParser (JSONDecoder):
    class Token (object):
        def __init__(self, tag, name, line, col, endline=0, endcol=0):
            self.tag = tag
            self.name = name
            self.startline = line
            self.startcol = col
            self.endline = endline
            self.endcol = endcol
            self.children = []
    
    def __init__(self):
        from .json import decoder
        from .json import scanner
        decoder.bc_context = self
        scanner.bc_context = self
        JSONDecoder.__init__(self, parse_int=lambda s:s)
        
        self.text = None
        self.root = self.Token(None, None, 0, 0)
        self.opentags = [self.root]
        self.activekey = None
        
    def decode(self, s):
        self.text = s
        super().decode(s)
        
    def offs_to_lincol(self, offs):
        lines = self.text.count('\n', 0, offs)
        cols = offs - self.text.rfind('\n', 0, offs) - 1
        return lines+1, cols
        
    def object_start(self, end):
        if self.activekey is None:
            return
        key = str(self.activekey[0])
        line1, col1 = self.offs_to_lincol(self.activekey[1])
        token = self.Token(key, key, line1, col1)
        self.opentags[-1].children.append(token)
        self.opentags.append(token)
        self.activekey = None
        
    def object_key(self, key, start):
        self.activekey = key, start
        
    def object_end(self, end):
        token = self.opentags.pop()
        token.endline, token.endcol = self.offs_to_lincol(end)
        self.activekey = None
        
    def simple_value(self, string):
        if self.activekey is None:
            return  #XXX: ?
        key = self.activekey[0]
        self.activekey = None
        token = self.opentags[-1]
        if token.name is None or len(token.name) > 35:
            return
        if ' ' in string:
            string = repr(string)
        if type(key) is int:
            token.name = f'{token.name}  {string}'
        else:
            if ' ' in key:
                key = repr(key)
            token.name = f'{token.name}  {key}:{string}'
        if len(token.name) > 45:
            token.name = token.name[:44] + '…'
        
        
class JSONParser (ClassParserInterface):
    
    def parse(self, doc, location, model):
        parser = CustomJSONParser()
        start, end = doc.get_bounds()
        uri = location and location.get_uri()
        error_row = None
        try:
            parser.decode(doc.get_text(start, end, True))
        except JSONDecodeError as e:
            error_row = [e.msg, 'error', uri, e.lineno, e.colno]
        
        self._append_token_to_model(model, None, parser.root, uri)
        if error_row:
            model.append(None, *error_row)
        
    def _append_token_to_model(self, model, parent_iter, parent, uri):
        for token in parent.children:
            titer = model.append(parent_iter, token.name, None, uri,
                        token.startline, token.startcol, token.endline, token.endcol)
            self._append_token_to_model(model, titer, token, uri)
            
        
register_parser(JSONParser.__name__, JSONParser, ["json"], 'JSON Parser')


