#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# xwot.py - Python tools for the extended Web of Things
# Copyright (C) 2015  Alexander Rüedlinger
#
# 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/>

__author__ = 'Alexander Rüedlinger'

from helper import OutputPrinter
from xwot.compiler.frontend import visitor


class FlaskBackendBuilder(visitor.BaseVisitor):
    def __init__(self):
        visitor.BaseVisitor.__init__(self)
        self._out = OutputPrinter()

    def _create_symbol_name(self, path):
        return path.replace("/", "_").replace("-", "_").replace(".", "_")

    def before(self):
        self._out.code([
                           '#',
                           '# Generated by xwot compiler.',
                           '#',
                           '# Flask xwot application.',
                           '#',
                           '',
                           'import os',
                           'from yadp.device import Description',
                           '',
                           'from xwot.util import local_ip',
                           'from xwot.util import create_description',
                           'from xwot.util import dir_path',
                           'from xwot.util import parent_dir_path',
                           '',
                           '# base config',
                           'ip = local_ip()',
                           'port = 5000',
                           'http_addr = "http://%s:%s/" % (ip, port)',
                           'module_dir_path = dir_path(__file__)',
                           'app_dir_path = parent_dir_path(__file__)',
                           'xwot_file = os.path.join(app_dir_path, "device.xwot")',
                           '',
                           'jsonld_description_str = create_description(xwot_file=xwot_file, base=http_addr)',
                           'yadp_description = Description(content_type="application/ld+json", content=jsonld_description_str)',
                           '',
                           '',
                           'from flask import Flask',
                           'from flask.ext.twisted import Twisted',
                           '',
                           'app = Flask(__name__)',
                           'twisted = Twisted(app)',
                           ], ["xwot_app", "__init__"])

    def after(self):
        self._out.code([
                           "import %s" % node.name() for node in self._nodes
                       ], ["xwot_app", "__init__"])

        self._out.code([
                           '#',
                           '# Generated by xwot compiler.',
                           '#',
                           '# Flask xwot application.',
                           '#',
                           '',
                           'import xwot_app',
                           'from xwot_app import app',
                           '',
                           'import yadp',
                           'yadp.debug()',
                           '',
                           'from yadp import service',
                           'from yadp.device import Device',
                           '',
                           "device = Device(urn='urn:xwot:Device', location=xwot_app.http_addr, descriptions=[xwot_app.yadp_description])",
                           '',
                           'service = service()',
                           'service.register(device=device, passive=True)',
                           '',
                           "",
                           "if __name__ == '__main__':",
                           self._out.indent([
                               "app.run(host='0.0.0.0', port=xwot_app.port, debug=True)"
                           ])
                       ], ['runserver'])

    def before_resource(self, node):
        self._out.code([
                           '#',
                           '# Generated by xwot compiler.',
                           '#',
                           '# Flask xwot application.',
                           '#',
                           "# Type:       %s" % node.type(),
                           "# Resource:   %s" % node.name(),
                           "# Path:       %s" % node.fullpath(),
                           '#',
                           '',
                           'from flask import request',
                           'from xwot_app import app',
                           ''
                       ], ["xwot_app", node.name()])

    def handle_entity(self, node):
        self._out.code([
                           '#',
                           '# Generated by xwot compiler.',
                           '#',
                           '# Flask xwot application.',
                           '#',
                           "# Type:       %s" % node.type(),
                           "# Resource:   %s" % node.name(),
                           "# Path:       %s" % node.fullpath(),
                           '#',
                           '',
                           'from flask import Response',
                           'import xwot_app',
                           'from xwot_app import app',
                           '',
                           '',
                           "@app.route('/')",
                           'def home():',
                           self._out.indent([
                               'return Response(response=xwot_app.jsonld_description_str, status=200, content_type="application/ld+json")'
                           ])
                       ], ["xwot_app", node.name()])

    def handle_resource(self, node):
        for method in ['GET', 'PUT']:
            self._out.code([
                               '#',
                               "# %s '%s'" % (method.upper(), node.fullpath()),
                               '#',
                               "@app.route('%s', methods=['%s'])" % (node.fullpath(), method),
                               "def handle%s_%s():" % (self._create_symbol_name(node.fullpath()), method),
                               self._out.indent([
                                   'return "Name: %s , Hello at: %s"' % (node.name(), node.fullpath())
                               ])
                           ], ["xwot_app", node.name()])

    def handle_device_resource(self, node):
        for method in ['GET', 'PUT']:
            self._out.code([
                               '#',
                               "# %s '%s'" % (method.upper(), node.fullpath()),
                               '#',
                               "@app.route('%s', methods=['%s'])" % (node.fullpath(), method),
                               "def handle%s_%s():" % (self._create_symbol_name(node.fullpath()), method),
                               self._out.indent([
                                   'return "Name: %s , Hello at: %s"' % (node.name(), node.fullpath())
                               ])
                           ], ["xwot_app", node.name()])

    def handle_sensor_resource(self, node):
        for method in ['GET']:
            self._out.code([
                               '#',
                               "# %s '%s'" % (method.upper(), node.fullpath()),
                               '#',
                               "@app.route('%s', methods=['%s'])" % (node.fullpath(), method),
                               "def handle%s_%s():" % (self._create_symbol_name(node.fullpath()), method),
                               self._out.indent([
                                   'return "Name: %s , Hello at: %s"' % (node.name(), node.fullpath())
                               ])
                           ], ["xwot_app", node.name()])

    def handle_tag_resource(self, node):
        for method in ['GET']:
            self._out.code([
                               '#',
                               "# %s '%s'" % (method.upper(), node.fullpath()),
                               '#',
                               "@app.route('%s', methods=['%s'])" % (node.fullpath(), method),
                               "def handle%s_%s():" % (self._create_symbol_name(node.fullpath()), method),
                               self._out.indent([
                                   'return "Name: %s , Hello at: %s"' % (node.name(), node.fullpath())
                               ])
                           ], ["xwot_app", node.name()])

    def handle_context_resource(self, node):
        for method in ['GET', 'PUT']:
            self._out.code([
                               '#',
                               "# %s '%s'" % (method.upper(), node.fullpath()),
                               '#',
                               "@app.route('%s', methods=['%s'])" % (node.fullpath(), method),
                               "def handle%s_%s():" % (self._create_symbol_name(node.fullpath()), method),
                               self._out.indent([
                                   'return "Name: %s , Hello at: %s"' % (node.name(), node.fullpath())
                               ])
                           ], ["xwot_app", node.name()])

    def handle_service_resource(self, node):
        for method in ['GET', 'POST', 'PUT', 'DELETE']:
            self._out.code([
                               '#',
                               "# %s '%s'" % (method.upper(), node.fullpath()),
                               '#',
                               "@app.route('%s', methods=['%s'])" % (node.fullpath(), method),
                               "def handle%s_%s():" % (self._create_symbol_name(node.fullpath()), method),
                               self._out.indent([
                                   'return "Name: %s , Hello at: %s"' % (node.name(), node.fullpath())
                               ])
                           ], ["xwot_app", node.name()])

    def handle_actuator_resource(self, node):
        for method in ['PUT']:
            self._out.code([
                               '#',
                               "# %s '%s'" % (method.upper(), node.fullpath()),
                               '#',
                               "@app.route('%s', methods=['%s'])" % (node.fullpath(), method),
                               "def handle%s_%s():" % (self._create_symbol_name(node.fullpath()), method),
                               self._out.indent([
                                   'return "Name: %s , Hello at: %s"' % (node.name(), node.fullpath())
                               ])
                           ], ["xwot_app", node.name()])

    def handle_publisher_resource(self, node):
        for method in ['GET', 'POST']:
            self._out.code([
                               '#',
                               "# %s '%s'" % (method.upper(), node.fullpath()),
                               '#',
                               "@app.route('%s', methods=['%s'])" % (node.fullpath(), method),
                               "def handle%s_%s():" % (self._create_symbol_name(node.fullpath()), method),
                               self._out.indent([
                                   'return "Name: %s , Hello at: %s"' % (node.name(), node.fullpath())
                               ])
                           ], ["xwot_app", node.name()])

    def _runserver_tac(self):
        return """# coding: utf-8
#
# Generated by xwot compiler.
#
# Flask xwot application.
#

from twisted.application.service import Application
import xwot_app
from xwot_app import app, twisted

import yadp
from yadp import service
from yadp.device import Device

device = Device(urn='urn:xwot:Device', location=xwot_app.http_addr, descriptions=[xwot_app.yadp_description])

service = service()
service.register(device=device, passive=True)

application = Application('twisted-flask')
twisted.run(host='0.0.0.0', port=xwot_app.port, run_reactor=False)
        """

    def output(self):

        # get all created files
        files = self._out.flush()
        new_files_dic = {}

        for file_name, pycode in files.items():
            # append to each file its correct file extension
            new_files_dic[file_name + ".py"] = pycode

        # create on the fly a requirements.txt file
        requirements = "\n".join(['flask', 'Flask-Twisted', 'twisted'])
        new_files_dic['requirements.txt'] = requirements
        new_files_dic['runserver.tac'] = self._runserver_tac()

        return new_files_dic