#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  json.py
#
#  Copyright 2018 Jelle Smet <development@smetj.net>
#
#  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, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#  MA 02110-1301, USA.
#
#


from wishbone.error import ProtocolError
from wishbone.protocol import Decode
from json import loads
from io import StringIO
import os


class JSON(Decode):

    '''
    Decode a JSON string into a Python object.

    Parameters:

        - charset(str)('utf-8)
            |  The charset to use when decoding.

        - delimiter(str)(None)
            |  The dilimiter to use in a stream of Python docs.
            |  None expects the complete payload to be 1 json document.

        - buffer_size(int)(4096)
            |  The maximum number of bytes allowed to buffer.

    '''

    def __init__(self, charset='utf-8', delimiter=None, buffer_size=4096):

        self.charset = charset
        if isinstance(delimiter, bytes):
            self.delimiter = delimiter.decode(charset, 'strict')
        else:
            self.delimiter = delimiter
        self.buffer_size = buffer_size
        self.buffer = StringIO()

    def getBufferSize(self):

        cur_pos = self.buffer.tell()
        self.buffer.seek(0, os.SEEK_END)
        size = self.buffer.tell()
        self.buffer.seek(cur_pos)
        return size

    def handleBytes(self, data):

        for item in self.handler(data.decode(self.charset, "strict")):
            yield self.handler(item)

    def handleDict(self, data):

        return data

    def handleGenerator(self, data):

        for chunk in data:
            for item in self.handler(chunk):
                yield item

    def handleReadLinesMethod(self, data):

        for chunk in data.readlines():
            for item in self.handler(chunk):
                yield item

    def handleString(self, data):

        self.buffer.write(data)
        self.buffer.seek(0)

        if self.delimiter is not None and self.delimiter in self.buffer.getvalue():
            for item in self.buffer.getvalue().split(self.delimiter):
                if item == "":
                    next
                else:
                    try:
                        yield loads(item)
                    except Exception as err:
                        raise ProtocolError(err)
            self.buffer.truncate(0)
        else:
            self.buffer.seek(0, 2)

    def flush(self):

        if len(self.buffer.getvalue()) == 0:
            return
            yield
        else:
            try:
                yield loads(
                    self.buffer.getvalue()
                )
            except Exception as err:
                raise ProtocolError(err)
            else:
                self.resetBuffer()

    def resetBuffer(self):

        self.buffer = StringIO()

