# -*- coding: utf-8 -*-
"""Module for sample JSON generation from JSON schema

.. module:: datagen.jsongen
   :platform: Unix
   :synopsis: Module for sample JSON generation from JSON schema
.. moduleauthor:: Petr Rašek <bowman@hydratk.org>

"""

"""
Events:
-------
jsongen_before_import_spec
jsongen_after_import_spec
jsongen_before_write
jsongen_after_write

"""

from hydratk.core.masterhead import MasterHead
from hydratk.core import event
from simplejson import loads, dumps
from os import path


class JSONGen(object):
    """Class JSONGen
    """

    _mh = None
    _path = None
    _schema = None

    def __init__(self):
        """Class constructor

        Called when object is initialized

        Args:
           none              

        """

        self._mh = MasterHead.get_head()

    @property
    def path(self):
        """ path property getter """

        return self._path

    @property
    def schema(self):
        """ schema property getter """

        return self._schema

    def import_schema(self, filename):
        """Method imports schema

        Args:
            filename (str): filename

        Returns:
            bool: result

        Raises:
            event: jsongen_before_import_spec
            event: jsongen_after_import_spec     

        """

        try:

            self._mh.demsg('htk_on_debug_info', self._mh._trn.msg(
                'datagen_jsongen_import_spec', filename), self._mh.fromhere())
            ev = event.Event('jsongen_before_import_spec', filename)
            if (self._mh.fire_event(ev) > 0):
                filename = ev.argv(0)

            if (ev.will_run_default()):
                if (path.exists(filename)):
                    self._path = path.dirname(path.abspath(filename))
                    with open(filename, 'r') as f:
                        self._schema = loads(f.read())
                else:
                    raise ValueError('File {0} not found'.format(filename))

            self._mh.demsg('htk_on_debug_info', self._mh._trn.msg(
                'datagen_jsongen_spec_imported'), self._mh.fromhere())
            ev = event.Event('jsongen_after_import_spec')
            self._mh.fire_event(ev)

            return True

        except (Exception, ValueError) as ex:
            self._mh.demsg(
                'htk_on_error', 'error: {0}'.format(ex), self._mh.fromhere())
            return False

    def tojson(self, outfile=None):
        """Method creates sample json file

        Args:
            outfile (str): output filename, default sample.json

        Returns:
            bool: result

        Raises:
            error: ValueError    
            event: jsongen_before_write
            event: jsongen_after_write 

        """

        try:

            if (self._schema == None):
                raise ValueError('Schema is not imported yet')

            self._mh.demsg('htk_on_debug_info', self._mh._trn.msg(
                'datagen_jsongen_write_sample'), self._mh.fromhere())
            ev = event.Event('jsongen_before_write', outfile)
            if (self._mh.fire_event(ev) > 0):
                outfile = ev.argv(0)

            if (ev.will_run_default()):
                doc = self._tojson_rec()
                outfile = 'sample.json' if (outfile == None) else outfile
                with open(outfile, 'w') as f:
                    f.write(dumps(doc, indent=4))

            self._mh.demsg('htk_on_debug_info', self._mh._trn.msg(
                'datagen_jsongen_sample_written', outfile), self._mh.fromhere())
            ev = event.Event('jsongen_after_write')
            self._mh.fire_event(ev)

            return True

        except Exception as ex:
            self._mh.demsg(
                'htk_on_error', 'error: {0}'.format(ex), self._mh.fromhere())
            return False

    def _tojson_rec(self, schema=None):
        """Method creates sample json document

        It is used in recursive traversal

        Args:
            schema (json): json schema object

        Returns:
            str: sample json

        Raises:
            error: ValueError     

        """

        if (self._schema == None):
            raise ValueError('Schema is not imported yet')

        if (schema == None):
            schema = self._schema

        if (schema['type'] == 'object'):
            doc = {}
            for key, subelem in schema['properties'].items():

                if ('$ref' in subelem):
                    subelem = self._import_ref_schema(subelem['$ref'])

                if (subelem['type'] == 'array'):
                    doc[key] = []
                    doc[key].append(self._tojson_rec(subelem['items']))
                elif (subelem['type'] == 'object'):
                    doc[key] = self._tojson_rec(subelem)
                else:
                    doc[key] = '?'

        elif (schema['type'] == 'array'):
            doc = []
            doc.append(self._tojson_rec(schema['items']))
        else:
            doc = '?'

        return doc

    def _import_ref_schema(self, uri):
        """Method imports referenced schema    

        local schema is required, http is not supported

        Args:
           uri (str): file uri, absolute path or filename

        Returns:
            json: json schema

        Raises:
            error: ValueError     

        """

        filename = uri if (not 'file://' in uri) else uri[7:]
        if (not '/' in filename and self._path != None):
            filename = path.join(self._path, filename)

        if (path.exists(filename)):
            with open(filename, 'r') as f:
                ref_schema = loads(f.read())

            return ref_schema
        else:
            raise ValueError('File {0} not found'.format(filename))
