from pathlib import Path

import numpy as np
import torch
import torchvision.utils as vutils
from addict import Dict
from PIL import Image
from torch.nn.functional import interpolate, sigmoid

from climategan.data import decode_segmap_merged_labels
from climategan.tutils import (
    all_texts_to_tensors,
    decode_bucketed_depth,
    normalize_tensor,
    write_architecture,
)
from climategan.utils import flatten_opts

class Logger:
    def __init__(self, trainer):
        self.losses = Dict()
        self.time = Dict()
        self.trainer = trainer
        self.global_step = 0
        self.epoch = 0

    def log_comet_images(self, mode, domain, minimal=False, all_only=False):
        trainer = self.trainer
        save_images = {}
        all_images = []
        n_all_ims = None
        all_legends = ["Input"]
        task_legends = {}

        if domain not in trainer.display_images[mode]:
            return

        # --------------------
        # -----  Masker  -----
        # --------------------
        n_ims = len(trainer.display_images[mode][domain])
        print(" " * 60, end="\r")
        if domain != "rf":
            for j, display_dict in enumerate(trainer.display_images[mode][domain]):

                print(f"Inferring sample {mode} {domain} {j+1}/{n_ims}", end="\r")

                x = display_dict["data"]["x"].unsqueeze(0).to(trainer.device)
                z = trainer.G.encode(x)

                s_pred = decoded_s_pred = d_pred = z_depth = None
                for k, task in enumerate(["d", "s", "m"]):

                    if (
                        task not in display_dict["data"]
                        or task not in trainer.opts.tasks
                    ):
                        continue

                    task_legend = ["Input"]
                    target = display_dict["data"][task]
                    target = target.unsqueeze(0).to(trainer.device)
                    task_saves = []

                    if task not in save_images:
                        save_images[task] = []

                    prediction = None
                    if task == "m":
                        cond = None
                        if s_pred is not None and d_pred is not None:
                            cond = trainer.G.make_m_cond(d_pred, s_pred, x)

                        prediction = trainer.G.decoders[task](z, cond, z_depth)
                    elif task == "d":
                        prediction, z_depth = trainer.G.decoders[task](z)
                    elif task == "s":
                        prediction = trainer.G.decoders[task](z, z_depth)

                    if task == "s":
                        # Log fire
                        wildfire_tens = trainer.compute_fire(x, prediction)
                        task_saves.append(wildfire_tens)
                        task_legend.append("Wildfire")
                        # Log seg output
                        s_pred = prediction.clone()
                        target = (
                            decode_segmap_merged_labels(target, domain, True)
                            .float()
                            .to(trainer.device)
                        )
                        prediction = (
                            decode_segmap_merged_labels(prediction, domain, False)
                            .float()
                            .to(trainer.device)
                        )
                        decoded_s_pred = prediction
                        task_saves.append(target)
                        task_legend.append("Target Segmentation")

                    elif task == "m":
                        prediction = sigmoid(prediction).repeat(1, 3, 1, 1)
                        task_saves.append(x * (1.0 - prediction))
                        if not minimal:
                            task_saves.append(
                                x * (1.0 - (prediction > 0.1).to(torch.int))
                            )
                            task_saves.append(
                                x * (1.0 - (prediction > 0.5).to(torch.int))
                            )

                        task_saves.append(x * (1.0 - target.repeat(1, 3, 1, 1)))
                        task_legend.append("Masked input")

                        if not minimal:
                            task_legend.append("Masked input (>0.1)")
                            task_legend.append("Masked input (>0.5)")

                        task_legend.append("Masked input (target)")
                        # dummy pixels to fool scaling and preserve mask range
                        prediction[:, :, 0, 0] = 1.0
                        prediction[:, :, -1, -1] = 0.0

                    elif task == "d":
                        # prediction is a log depth tensor
                        d_pred = prediction
                        target = normalize_tensor(target) * 255
                        if prediction.shape[1] > 1:
                            prediction = decode_bucketed_depth(
                                prediction, self.trainer.opts
                            )
                        smogged = self.trainer.compute_smog(
                            x, d=prediction, s=decoded_s_pred, use_sky_seg=False
                        )
                        prediction = normalize_tensor(prediction)
                        prediction = prediction.repeat(1, 3, 1, 1)
                        task_saves.append(smogged)
                        task_legend.append("Smogged")
                        task_saves.append(target.repeat(1, 3, 1, 1))
                        task_legend.append("Depth target")

                    task_saves.append(prediction)
                    task_legend.append(f"Predicted {task}")

                    save_images[task].append(x.cpu().detach())
                    if k == 0:
                        all_images.append(save_images[task][-1])

                    task_legends[task] = task_legend
                    if j == 0:
                        all_legends += task_legend[1:]

                    for im in task_saves:
                        save_images[task].append(im.cpu().detach())
                        all_images.append(save_images[task][-1])

                if j == 0:
                    n_all_ims = len(all_images)

            if not all_only:
                for task in save_images.keys():
                    # Write images:
                    self.upload_images(
                        image_outputs=save_images[task],
                        mode=mode,
                        domain=domain,
                        task=task,
                        im_per_row=trainer.opts.comet.im_per_row.get(task, 4),
                        rows_per_log=trainer.opts.comet.get("rows_per_log", 5),
                        legends=task_legends[task],
                    )

            if len(save_images) > 1:
                self.upload_images(
                    image_outputs=all_images,
                    mode=mode,
                    domain=domain,
                    task="all",
                    im_per_row=n_all_ims,
                    rows_per_log=trainer.opts.comet.get("rows_per_log", 5),
                    legends=all_legends,
                )
        # ---------------------
        # -----  Painter  -----
        # ---------------------
        else:
            # in the rf domain display_size may be different from fid.n_images
            limit = trainer.opts.comet.display_size
            image_outputs = []
            legends = []
            for im_set in trainer.display_images[mode][domain][:limit]:
                x = im_set["data"]["x"].unsqueeze(0).to(trainer.device)
                m = im_set["data"]["m"].unsqueeze(0).to(trainer.device)

                prediction = trainer.G.paint(m, x)

                image_outputs.append(x * (1.0 - m))
                image_outputs.append(prediction)
                image_outputs.append(x)
                image_outputs.append(prediction * m)
                if not legends:
                    legends.append("Masked Input")
                    legends.append("Painted Input")
                    legends.append("Input")
                    legends.append("Isolated Water")
            # Write images
            self.upload_images(
                image_outputs=image_outputs,
                mode=mode,
                domain=domain,
                task="painter",
                im_per_row=trainer.opts.comet.im_per_row.get("p", 4),
                rows_per_log=trainer.opts.comet.get("rows_per_log", 5),
                legends=legends,
            )

        return 0

    def log_losses(self, model_to_update="G", mode="train"):
        """Logs metrics on comet.ml

        Args:
            model_to_update (str, optional): One of "G", "D". Defaults to "G".
        """
        trainer = self.trainer
        loss_names = {"G": "gen", "D": "disc"}

        if trainer.opts.train.log_level < 1:
            return

        if trainer.exp is None:
            return

        assert model_to_update in {
            "G",
            "D",
        }, "unknown model to log losses {}".format(model_to_update)

        loss_to_update = self.losses[loss_names[model_to_update]]

        losses = loss_to_update.copy()

        if trainer.opts.train.log_level == 1:
            # Only log aggregated losses: delete other keys in losses
            for k in loss_to_update:
                if k not in {"masker", "total_loss", "painter"}:
                    del losses[k]
        # convert losses into a single-level dictionnary

        losses = flatten_opts(losses)
        trainer.exp.log_metrics(
            losses, prefix=f"{model_to_update}_{mode}", step=self.global_step
        )

    def log_learning_rates(self):
        if self.trainer.exp is None:
            return
        lrs = {}
        trainer = self.trainer
        if trainer.g_scheduler is not None:
            for name, lr in zip(
                trainer.lr_names["G"], trainer.g_scheduler.get_last_lr()
            ):
                lrs[f"lr_G_{name}"] = lr
        if trainer.d_scheduler is not None:
            for name, lr in zip(
                trainer.lr_names["D"], trainer.d_scheduler.get_last_lr()
            ):
                lrs[f"lr_D_{name}"] = lr

        trainer.exp.log_metrics(lrs, step=self.global_step)

    def log_step_time(self, time):
        """Logs step-time on comet.ml

        Args:
            step_time (float): step-time in seconds
        """
        if self.trainer.exp:
            self.trainer.exp.log_metric(
                "step-time", time - self.time.step_start, step=self.global_step
            )

    def log_epoch_time(self, time):
        """Logs step-time on comet.ml

        Args:
            step_time (float): step-time in seconds
        """
        if self.trainer.exp:
            self.trainer.exp.log_metric(
                "epoch-time", time - self.time.epoch_start, step=self.global_step
            )

    def log_comet_combined_images(self, mode, domain):

        trainer = self.trainer
        image_outputs = []
        legends = []
        im_per_row = 0
        for i, im_set in enumerate(trainer.display_images[mode][domain]):
            x = im_set["data"]["x"].unsqueeze(0).to(trainer.device)
            # m = im_set["data"]["m"].unsqueeze(0).to(trainer.device)

            m = trainer.G.mask(x=x)
            m_bin = (m > 0.5).to(m.dtype)
            prediction = trainer.G.paint(m, x)
            prediction_bin = trainer.G.paint(m_bin, x)

            image_outputs.append(x)
            legends.append("Input")
            image_outputs.append(x * (1.0 - m))
            legends.append("Soft Masked Input")
            image_outputs.append(prediction)
            legends.append("Painted")
            image_outputs.append(prediction * m)
            legends.append("Soft Masked Painted")
            image_outputs.append(x * (1.0 - m_bin))
            legends.append("Binary (0.5) Masked Input")
            image_outputs.append(prediction_bin)
            legends.append("Binary (0.5) Painted")
            image_outputs.append(prediction_bin * m_bin)
            legends.append("Binary (0.5) Masked Painted")

            if i == 0:
                im_per_row = len(image_outputs)
        # Upload images
        self.upload_images(
            image_outputs=image_outputs,
            mode=mode,
            domain=domain,
            task="combined",
            im_per_row=im_per_row or 7,
            rows_per_log=trainer.opts.comet.get("rows_per_log", 5),
            legends=legends,
        )

        return 0

    def upload_images(
        self,
        image_outputs,
        mode,
        domain,
        task,
        im_per_row=3,
        rows_per_log=5,
        legends=[],
    ):
        """
        Save output image

        Args:
            image_outputs (list(torch.Tensor)): all the images to log
            mode (str): train or val
            domain (str): current domain
            task (str): current task
            im_per_row (int, optional): umber of images to be displayed per row.
                Typically, for a given task: 3 because [input prediction, target].
                Defaults to 3.
            rows_per_log (int, optional): Number of rows (=samples) per uploaded image.
                Defaults to 5.
            comet_exp (comet_ml.Experiment, optional): experiment to use.
                Defaults to None.
        """
        trainer = self.trainer
        if trainer.exp is None:
            return
        curr_iter = self.global_step
        nb_per_log = im_per_row * rows_per_log
        n_logs = len(image_outputs) // nb_per_log + 1

        header = None
        if len(legends) == im_per_row and all(isinstance(t, str) for t in legends):
            header_width = max(im.shape[-1] for im in image_outputs)
            headers = all_texts_to_tensors(legends, width=header_width)
            header = torch.cat(headers, dim=-1)

        for logidx in range(n_logs):
            print(" " * 100, end="\r", flush=True)
            print(
                "Uploading images for {} {} {} {}/{}".format(
                    mode, domain, task, logidx + 1, n_logs
                ),
                end="...",
                flush=True,
            )
            ims = image_outputs[logidx * nb_per_log : (logidx + 1) * nb_per_log]
            if not ims:
                continue

            ims = self.upsample(ims)
            ims = torch.stack([im.squeeze() for im in ims]).squeeze()
            image_grid = vutils.make_grid(
                ims, nrow=im_per_row, normalize=True, scale_each=True, padding=0
            )

            if header is not None:
                image_grid = torch.cat(
                    [header.to(image_grid.device), image_grid], dim=1
                )

            image_grid = image_grid.permute(1, 2, 0).cpu().numpy()
            trainer.exp.log_image(
                Image.fromarray((image_grid * 255).astype(np.uint8)),
                name=f"{mode}_{domain}_{task}_{str(curr_iter)}_#{logidx}",
                step=curr_iter,
            )

    def upsample(self, ims):
        h = max(im.shape[-2] for im in ims)
        w = max(im.shape[-1] for im in ims)
        new_ims = []
        for im in ims:
            im = interpolate(im, (h, w), mode="bilinear")
            new_ims.append(im)
        return new_ims

    def padd(self, ims):
        h = max(im.shape[-2] for im in ims)
        w = max(im.shape[-1] for im in ims)
        new_ims = []
        for im in ims:
            ih = im.shape[-2]
            iw = im.shape[-1]
            if ih != h or iw != w:
                padded = torch.zeros(im.shape[-3], h, w)
                padded[
                    :, (h - ih) // 2 : (h + ih) // 2, (w - iw) // 2 : (w + iw) // 2
                ] = im
                new_ims.append(padded)
            else:
                new_ims.append(im)

        return new_ims

    def log_architecture(self):
        write_architecture(self.trainer)

        if self.trainer.exp is None:
            return

        for f in Path(self.trainer.opts.output_path).glob("archi*.txt"):
            self.trainer.exp.log_asset(str(f), overwrite=True)


import os
import sys
import argparse

class MyWC():
    def count_lines(self, data):
        print(data.count('\n'), end=' ')

    def count_words(self, data):
        print(len(data.split(None)), end=' ')

    def count_bytes(self, data):
        print(len(data.encode('utf-8')), end=' ')

    def counter(self, data, args):
        if args.l:
            self.count_lines(data)
        if args.w:
            self.count_words(data)
        if args.c:
            self.count_bytes(data)
        if args.l == args.w == args.c == False:
            self.count_lines(data)
            self.count_words(data)
            self.count_bytes(data)

    def file_open(self, path):
        with open(path) as f:
            data = f.read()
        return data

    def args_parser(self, data_input):
        parser = argparse.ArgumentParser(prog='wc.py')
        parser.add_argument('file', nargs='?', help='filename', default=sys.stdin)
        parser.add_argument('-l', action='store_true', help='print the new line counts')
        parser.add_argument('-w', action='store_true', help='print the word counts')
        parser.add_argument('-c', action='store_true', help='print the byte count')
        return parser.parse_args()

if __name__ == '__main__':
    data_input = sys.stdin
    wc = MyWC()
    args = wc.args_parser(data_input)
    filename = args.file

    if data_input.isatty():
        try:
            if os.path.isfile(filename):
                data = wc.file_open(filename)
                wc.counter(data, args)
                print('\t{}'.format(filename))
        except TypeError:
            data = sys.stdin.read()
            wc.counter(data, args)
            print('')
    else:
        data = filename.read()
        wc.counter(data, args)
        print('')


#!/usr/bin/env python
"""
A very simple OAuth2 AS
"""
import json
import logging
import re
import sys
import traceback

from authn_setup import authn_setup
from aatest import as_unicode
from cherrypy.wsgiserver.ssl_builtin import BuiltinSSLAdapter
from oic.extension.provider import Provider
from oic.extension.provider import RevocationEndpoint
from oic.extension.provider import IntrospectionEndpoint
from oic.extension.token import JWTToken
from oic.oauth2.provider import AuthorizationEndpoint
from oic.oauth2.provider import TokenEndpoint
from oic.oic.provider import RegistrationEndpoint
from oic.utils.authn.client import verify_client
from oic.utils.authz import Implicit
from oic.utils.http_util import wsgi_wrapper
from oic.utils.http_util import NotFound
from oic.utils.http_util import ServiceError
from oic.utils.keyio import keyjar_init, KeyBundle

from requests.packages import urllib3
urllib3.disable_warnings()

__author__ = 'roland'

# ============================================================================
# First define how logging is supposed to be done
# ============================================================================

LOGGER = logging.getLogger("")
LOGFILE_NAME = 'oauth2_as.log'
hdlr = logging.FileHandler(LOGFILE_NAME)
base_formatter = logging.Formatter(
    "%(asctime)s %(name)s:%(levelname)s %(message)s")

hdlr.setFormatter(base_formatter)
LOGGER.addHandler(hdlr)
LOGGER.setLevel(logging.INFO)

JWKS_FILE_NAME = "static/jwks.json"

# ============================================================================
# Endpoint functions
# ============================================================================

# noinspection PyUnusedLocal
def token(environ, start_response):
    _oas = environ["oic.oas"]

    return wsgi_wrapper(environ, start_response, _oas.token_endpoint)

# noinspection PyUnusedLocal
def authorization(environ, start_response):
    _oas = environ["oic.oas"]

    return wsgi_wrapper(environ, start_response, _oas.authorization_endpoint)

# noinspection PyUnusedLocal
def config(environ, start_response):
    _oas = environ["oic.oas"]

    return wsgi_wrapper(environ, start_response, _oas.providerinfo_endpoint)

# noinspection PyUnusedLocal
def registration(environ, start_response):
    _oas = environ["oic.oas"]

    return wsgi_wrapper(environ, start_response, _oas.registration_endpoint)

# noinspection PyUnusedLocal
def introspection(environ, start_response):
    _oas = environ["oic.oas"]

    return wsgi_wrapper(environ, start_response, _oas.introspection_endpoint)

# noinspection PyUnusedLocal
def revocation(environ, start_response):
    _oas = environ["oic.oas"]

    return wsgi_wrapper(environ, start_response, _oas.revocation_endpoint)

ENDPOINTS = [
    AuthorizationEndpoint(authorization),
    TokenEndpoint(token),
    RegistrationEndpoint(registration),
    IntrospectionEndpoint(introspection),
    RevocationEndpoint(revocation)
]

# noinspection PyUnusedLocal
def verify(environ, start_response):
    _oas = environ["oic.oas"]
    return wsgi_wrapper(environ, start_response, _oas.verify_endpoint)

# ---------------------------------------------------------------------------
# For static files

def static(environ, start_response, path):
    LOGGER.info("[static]sending: %s" % (path,))

    try:
        text = open(path).read()
        if path.endswith(".ico"):
            start_response('200 OK', [('Content-Type', "image/x-icon")])
        elif path.endswith(".html"):
            start_response('200 OK', [('Content-Type', 'text/html')])
        elif path.endswith(".json"):
            start_response('200 OK', [('Content-Type', 'application/json')])
        elif path.endswith(".txt"):
            start_response('200 OK', [('Content-Type', 'text/plain')])
        elif path.endswith(".css"):
            start_response('200 OK', [('Content-Type', 'text/css')])
        else:
            start_response('200 OK', [('Content-Type', "text/xml")])
        return [text]
    except IOError:
        resp = NotFound()
        return resp(environ, start_response)

URLS = [
    (r'^verify', verify),
    (r'.well-known/openid-configuration', config)
]

for endp in ENDPOINTS:
    URLS.append(("^%s" % endp.etype, endp))

# ============================================================================
# The main web server function
# ============================================================================

def application(environ, start_response):
    """
    The main WSGI application. Dispatch the current request to
    the functions from above and store the regular expression
    captures in the WSGI environment as  `oic.url_args` so that
    the functions from above can access the url placeholders.

    If nothing matches call the `not_found` function.

    :param environ: The HTTP application environment
    :param start_response: The application to run when the handling of the
        request is done
    :return: The response as a list of lines
    """
    global OAS

    # user = environ.get("REMOTE_USER", "")
    path = environ.get('PATH_INFO', '').lstrip('/')

    LOGGER.info("path: %s" % path)
    if path == "robots.txt":
        return static(environ, start_response, "static/robots.txt")

    environ["oic.oas"] = OAS

    if path.startswith("static/"):
        return static(environ, start_response, path)

    for regex, callback in URLS:
        match = re.search(regex, path)
        if match is not None:
            try:
                environ['oic.url_args'] = match.groups()[0]
            except IndexError:
                environ['oic.url_args'] = path

            LOGGER.debug("callback: %s" % callback)
            try:
                return callback(environ, start_response)
            except Exception as err:
                print("{}".format(err), file=sys.stderr)
                message = traceback.format_exception(*sys.exc_info())
                print(message, file=sys.stderr)
                LOGGER.exception("%s" % err)
                resp = ServiceError("%s" % err)
                return resp(environ, start_response)

    LOGGER.debug("unknown side: %s" % path)
    resp = NotFound("Couldn't find the side you asked for!")
    return resp(environ, start_response)

# ============================================================================
# Below is what's needed to start the server
# ============================================================================

START_MESG = "OAuth2 server starting listening on port:{} at {}"

if __name__ == "__main__":
    import argparse
    import shelve
    import importlib

    from cherrypy import wsgiserver

    # This is where session information is stored
    # This serve is stateful.
    from oic.utils.sdb import SessionDB

    # Parse the command arguments
    parser = argparse.ArgumentParser()
    parser.add_argument('-d', dest='debug', action='store_true')
    parser.add_argument('-p', dest='port', default=80, type=int)
    # Who it should report as being responsible for the authentication
    parser.add_argument('-A', dest='authn_as', default="")
    parser.add_argument('-c', dest='conf_path')
    parser.add_argument(dest="config")
    args = parser.parse_args()

    # Client data base
    cdb = shelve.open("client_db", writeback=True)

    # Load the configuration file, which must be a python file
    # The default; first look for it in the directory from where this program
    # is run.
    sys.path.insert(0, ".")
    # If a specific configuration directory is specified look there first
    if args.conf_path:
        sys.path.insert(0, args.conf_path)
    config = importlib.import_module(args.config)
    # Add port number information
    config.issuer = config.issuer % args.port
    config.SERVICE_URL = config.SERVICE_URL % args.port

    for cnf in config.AUTHN_METHOD.values():
        try:
            cnf["config"]["return_to"] = cnf["config"]["return_to"] % args.port
        except KeyError:
            pass

    # Initiate the authentication broker. This is the service that
    # chooses which authentication method that is to be used.

    broker = authn_setup(config)

    # dealing with authorization, this is just everything goes.
    authz = Implicit()

    try:
        capabilities = config.CAPABILITIES
    except AttributeError:
        capabilities = None

    # Initiate the Provider
    OAS = Provider(config.issuer, None, cdb, broker, authz,
                   baseurl=config.issuer, client_authn=verify_client,
                   symkey=config.SYM_KEY, hostname=config.HOST,
                   capabilities=capabilities,
                   behavior=config.BEHAVIOR)

    try:
        jwks = keyjar_init(OAS, config.keys, kid_template="op%d")
    except Exception as err:
        LOGGER.error("Key setup failed: {}".format(err))
        print("Key setup failed: {}".format(err))
        exit()
        #OAS.key_setup("static", sig={"format": "jwk", "alg": "rsa"})
    else:
        jwks_file_name = JWKS_FILE_NAME
        f = open(jwks_file_name, "w")

        for key in jwks["keys"]:
            for k in key.keys():
                key[k] = as_unicode(key[k])

        f.write(json.dumps(jwks))
        f.close()
        OAS.jwks_uri = "{}/{}".format(OAS.baseurl, jwks_file_name)

    # Initiate the SessionDB
    _token = JWTToken('T', OAS.keyjar, {'code': 3600, 'token': 900},
                      iss=config.issuer, sign_alg= 'RS256')
    _refresh_token = JWTToken('R', OAS.keyjar, {'': 86400}, iss=config.issuer,
                              sign_alg='RS256')
    OAS.sdb = SessionDB(config.SERVICE_URL, token_factory=_token,
                        refresh_token_factory=_refresh_token)

    # set some parameters
    try:
        OAS.cookie_ttl = config.COOKIETTL
    except AttributeError:
        pass

    try:
        OAS.cookie_name = config.COOKIENAME
    except AttributeError:
        pass

    if args.debug:
        LOGGER.setLevel(logging.DEBUG)
        OAS.debug = True

    if args.authn_as:
        OAS.authn_as = args.authn_as

    OAS.endpoints = ENDPOINTS

    if args.port == 80:
        OAS.baseurl = config.baseurl
    else:
        if config.baseurl.endswith("/"):
            config.baseurl = config.baseurl[:-1]
        OAS.baseurl = "%s:%d" % (config.baseurl, args.port)

    if not OAS.baseurl.endswith("/"):
        OAS.baseurl += "/"

    # load extra keys
    try:
        extern = config.TRUSTED_REGISTRATION_ENTITIES
    except AttributeError:
        pass
    else:
        for ent in extern:
            iss = ent['iss']
            kb = KeyBundle()
            kb.imp_jwks = json.load(open(ent['jwks']))
            kb.do_keys(kb.imp_jwks['keys'])
            OAS.keyjar.add_kb(iss, kb)

    LOGGER.debug("URLS: '%s" % (URLS,))

    # Initiate the web server
    SRV = wsgiserver.CherryPyWSGIServer(('0.0.0.0', args.port), application)
    https = ""
    if config.SERVICE_URL.startswith("https"):
        https = " using HTTPS"
        # SRV.ssl_adapter = ssl_pyopenssl.pyOpenSSLAdapter(
        #     config.SERVER_CERT, config.SERVER_KEY, config.CERT_CHAIN)
        SRV.ssl_adapter = BuiltinSSLAdapter(config.SERVER_CERT,
                                            config.SERVER_KEY,
                                            config.CERT_CHAIN)

    _info = START_MESG.format(args.port, config.HOST)
    if https:
        _info += https
    LOGGER.info(_info)
    print(_info)
    try:
        SRV.start()
    except KeyboardInterrupt:
        SRV.stop()


from inspect import isgenerator
import json
from uuid import UUID

from fluiddb.cache.cache import BaseCache, CacheResult
from fluiddb.cache.factory import CachingAPIFactory
from fluiddb.data.user import User, Role
from fluiddb.model.user import getUser, UserAPI

def cachingGetUser(username):
    """Get a L{User} for a given username.

    The L{User}s will be fetched from the cache, otherwise it will be fetched
    directly from the database. Cache misses will be added to the cache. See
    L{fluiddb.model.user.getUser}.

    @param username: The username of the user.
    @return: A L{User} instance corresponding to the given username.
    """
    cache = UserCache()
    cachedResult = cache.get(username)
    if cachedResult.results is not None:
        return cachedResult.results
    else:
        user = getUser(username)
        if user is not None:
            cache.save(user)
        return user

class CachingUserAPI(object):
    """The public API to secure L{User}-related functionality.

    @param user: The L{User} to perform operations on behalf of.
    """

    def __init__(self):
        self._api = UserAPI(factory=CachingAPIFactory())

    def create(self, values, createPrivateNamespace=None):
        """See L{UserAPI.create}."""
        return self._api.create(values, createPrivateNamespace)

    def delete(self, usernames):
        """See L{UserAPI.delete}."""
        if isgenerator(usernames):
            usernames = list(usernames)
        cache = UserCache()
        for username in usernames:
            cache.clear(username)
        return self._api.delete(usernames)

    def get(self, usernames):
        """See L{UserAPI.get}."""
        return self._api.get(usernames)

    def set(self, values):
        """See L{UserAPI.set}."""
        cache = UserCache()
        for username, password, fullname, email, role in values:
            cache.clear(username)
        return self._api.set(values)

class UserCache(BaseCache):
    """Provides caching functions for the L{getUser} function."""

    keyPrefix = u'user:'

    def get(self, username):
        """Get a L{User} object from the cache.

        @param username: The username of the L{User} as C{unicode}.
        @return: A L{CacheResult} object with the L{User} in the L{results}
            field if it's found or the username in the C{uncachedValues}
            field if it's not found.
        """
        result = self.getValues([username])
        if result is None or result == [None]:
            return CacheResult(None, username)

        userdict = json.loads(result[0])

        user = User(username=userdict['username'],
                    passwordHash=str(userdict['passwordHash']),
                    fullname=userdict['fullname'],
                    email=userdict['email'],
                    role=Role.fromID(userdict['role']))
        user.id = userdict['id']
        user.objectID = UUID(userdict['objectID'])

        return CacheResult(user, None)

    def save(self, user):
        """Store a L{User} in the cache.

        @param user: A L{User} object to save in the cache.
        """
        userdict = {'id': user.id,
                    'objectID': str(user.objectID),
                    'username': user.username,
                    'passwordHash': user.passwordHash,
                    'fullname': user.fullname,
                    'email': user.email,
                    'role': user.role.id}

        self.setValues({user.username: json.dumps(userdict)})

    def clear(self, username):
        """Delete a L{User} from the cache.

        @param username: The username of the L{User} as C{unicode}.
        """
        self.deleteValues([username])


import modules.pumpingsystem as ps
import numpy as np

schedule = np.array([[70, 70, 70],
                     [75, 75, 75]])

pump_system = ps.PumpSystem('D1')
pump_system.add_level(ps.PumpingLevel('0', 1000000, 0, 15, 0, schedule, 0, 20))

pump_system.perform_simulation('1-factor', save=True)


from flask import Flask, request
from flask_restful import Resource, Api, reqparse
from flask_jwt import JWT, jwt_required
from security import authenticate, identity

app = Flask(__name__)
app.secret_key = "evgen"
api = Api(app)

jwt = JWT(app, authenticate, identity)

items = [
    {
        "name":"MyItem",
        "price":150.99
    }
]

class Items(Resource):
    parser = reqparse.RequestParser()
    parser.add_argument('price',
            type=float,
            required=True,
            help="This field cannot be left blank!"
        )

    @jwt_required()
    def get(self, name):
        item = next(filter(lambda x : x['name'] == name, items), None)
        if item:
            return item, 200
        return {"message":"Item not found"}, 404

    def post(self, name):
        if next(filter(lambda x : x['name'] == name, items), None):
            return {"message" : "This item is already  here"}, 400
        data = Item.parser.parse_args()
        item = {"name":data['name'], "price":data['price']}
        items.append(item)
        return item, 201

    def delete(self, name):
        global items
        items = list(filter(lambda x: x['name'] != name, items), None)
        return {"message":"Item deleted"}, 200

    def put(self, name):
        data = Item.parser.parse_args()
        #data = request.get_json()
        item = next(filter(lambda x : x['name'] == name, items), None)
        if item is None:
            item = {'name': name, 'price' :data['price']}
            items.append(item)
            return item, 201
        else:
            item.update(data)
        return item

class ItemList(Resource):
    @jwt_required()
    def get(self):
        return {"items" : items} , 200

api.add_resource(Items, '/item/<string:name>')
api.add_resource(ItemList, '/items')
app.run(port = 8080, debug = True)


import traceback
import inspect
import json
import simplejson

import importlib.util
import sys
import random

try:
	arg=json.loads(simplejson.dumps(args[0], use_decimal=True))
	DEBUG = plpy.execute('SELECT is_debug()')[0]['is_debug']
	assert isinstance(arg, dict),'Проверь формат JSON'
	assert 'parts' in arg,'Нужен параметр parts'
	assert 'previous_lay' in arg,'Нужен параметр previous_lay'
	assert 'pallet_length_x' in arg,'Нужен параметр pallet_length_x'
	assert 'pallet_length_y' in arg,'Нужен параметр pallet_length_y'
	assert 'part_indent' in arg,'Нужен параметр part_indent'

	def level_generator(start: int, max_: int) -> int:
		"""
		Генератор уровней
		:param start: начало отсчета
		:param max_: максимальный уровень
		:return: уровень
		"""
		while True:
				if start >= max_:
						start = 0
				yield start
				start += 1
	def sort_thickness_parts(parts_l: dict) -> dict:
		"""
		Сортировка по толщине
		:param parts_l: список деталей
		:return: детали сгруппированные по толщине
		"""
		parts_ = dict()
		for part_ in parts_l:
				parts_[part_['part_thickness_z']]=list()
				parts_[part_['part_thickness_z']].append(part_)
		return dict(parts_)

	sys.path.append('/home/kipia/opc_BHX')
	from py3dbp import Bin, Item, Packer, Painter

	parts, previous_lay, pallet_w, pallet_h, indent = (arg['parts'], arg['previous_lay'], arg['pallet_length_x'], arg['pallet_length_y'], arg['part_indent'])
	pallet_s = pallet_w * pallet_h  # площадь палеты
	sort_parts = sort_thickness_parts(parts)
	max_percent = 0  # наилучший результат заполнения
	result_parts = None  # список деталей при наилучшем заполнении
	# ищем лучший результат
	for thickness in sort_parts:
		# формируем паллету по толщине деталей
		pallet = Bin(partno='Bin', WHD=(pallet_w, pallet_h, thickness), max_weight=28080, corner=1, put_type=1)
		for i in range(len(parts)):
			# меняем приоритет деталей
			level = level_generator(i, len(sort_parts[thickness]))
			item_list = []
			for part in parts:
				item_list.append(Item(partno=part['part_id'],
									  name='part',
									  typeof='cube',
									  WHD=(part['part_length_x'] + indent,
										   part['part_length_y'] + indent,
										   part['part_thickness_z']),
									  level=next(level),
									  weight=1,
									  loadbear=0,
									  updown=False,
									  color="#" + ''.join([random.choice('0123456789ABCDEF') for j in range(6)])))
			packer = Packer()
			packer.addBin(pallet)
			for item in item_list:
				packer.addItem(item)
			# пакуем
			packer.pack(
				bigger_first=False,
				fix_point=True,
				binding=[('server', 'cabint')]
			)
			b = packer.bins[0]
			S = 0   # общая площадь занимаемая деталями
			layer_parts = []  # детали 0 слоя
			for item in b.items:
				if item.name != 'corner' and item.position[2] == 0:
					S += (item.width * item.height)
					item.center = (item.position[0] + int(item.width / 2), item.position[1] + int(item.height / 2))
					layer_parts.append({'part_pos_x': int(item.center[0]),
                                        'part_pos_y': int(item.center[1]),
                                        'part_id': item.partno,
                                        'part_angle_a': 0 if item.rotation_type == 0 else 90})
			percent = int((S / pallet_s) * 100)  # процент заполнения слоя
			if percent > max_percent:
				max_percent = percent
				result_parts = layer_parts.copy()
	res = {
		"filling": max_percent,
		"parts": result_parts
	}
	return res
except Exception as e:
	traceback_info=traceback.format_exc().splitlines()[1].split(', ')
	source=traceback_info[1]+' '+'_'.join(traceback_info[2].split('_')[slice(4,-1)])
	err_arg = [traceback_info[1]+': '+str(e),simplejson.dumps(args,ensure_ascii=False,use_decimal=True)]
	res = plpy.execute(plpy.prepare(f'SELECT write_error_log($1,$2)', ['text','text']), err_arg)
	return dict(source=source,error=str(e),args=arg)


import matplotlib.pyplot as plt
import numpy as np
from numpy.testing import assert_allclose

from compart.marks import Ellipse

def test_points_on_circumference():
    radius = 2
    n_points = 100
    circ = Ellipse(center=np.zeros(2), width=radius, height=radius)

    points = circ.gen_points(n=n_points, fuzz=0)

    assert points.shape == (n_points, 2, 2)
    assert_allclose(np.sum(points ** 2, axis=2), radius ** 2)

def test_plot_works():
    circ = Ellipse(center=np.zeros(2), width=1, height=1)
    fig, ax = plt.subplots()
    circ.plot(ax=ax, color="orange")


from typing import Dict, NamedTuple
from enum import Enum

import sip
from PyQt5.QtWidgets import QDialogButtonBox, QScrollArea

from ..widget import SEToolsWidget

class AnalysisSection(Enum):

    """Groupings of analysis tabs"""

    Analysis = 1
    Components = 2
    General = 3
    Labeling = 4
    Other = 5
    Rules = 6

TAB_REGISTRY: Dict[str, type] = {}

class TabRegistry(sip.wrappertype):

    """
    Analysis tab registry metaclass.  This registers tabs to be used both for
    populating the content of the "choose analysis" dialog and also for
    saving tab/workspace info.
    """

    def __new__(cls, *args, **kwargs):
        classdef = super().__new__(cls, *args, **kwargs)

        clsname = args[0]
        attributedict = args[2]
        if clsname != "AnalysisTab":
            assert "section" in attributedict, "Class {} is missing the section value, " \
                "this is an setools bug".format(clsname)

            assert "tab_title" in attributedict, "Class {} is missing the tab_title value, " \
                "this is an setools bug".format(clsname)

            assert "mlsonly" in attributedict, "Class {} is missing the mlsonly value, " \
                "this is an setools bug".format(clsname)

            # ensure there is no duplication of class name or title
            for existing_tabname, existing_class in TAB_REGISTRY.items():
                if existing_tabname == clsname:
                    raise TypeError("Analysis tab {} conflicts with registered tab {}, "
                                    "this is an setools bug".format(clsname, existing_tabname))

                if existing_class.tab_title == attributedict["tab_title"]:
                    raise TypeError("Analysis tab {}'s title \"{}\" conflicts with registered tab "
                                    "{}, this is an setools bug.".
                                    format(clsname, attributedict["tab_title"], existing_tabname))

            TAB_REGISTRY[clsname] = classdef

        return classdef

# pylint: disable=invalid-metaclass
class AnalysisTab(SEToolsWidget, QScrollArea, metaclass=TabRegistry):

    """Base class for Apol analysis tabs."""

    # A QButtonBox which has an Apply button
    # for running the analysis.
    buttonBox = None

    # The set of tab fields that are in error
    errors = None

    # Normal and error palettes to use
    orig_palette = None
    error_palette = None

    #
    # Tab error state
    #
    def set_criteria_error(self, field, error):
        """Set the specified widget to an error state."""
        field.setToolTip("Error: {0}".format(error))
        field.setPalette(self.error_palette)
        self.errors.add(field)
        self._check_query()

    def clear_criteria_error(self, field, tooltip):
        """Clear the specified widget's error state."""
        field.setToolTip(tooltip)
        field.setPalette(self.orig_palette)
        self.errors.discard(field)
        self._check_query()

    def _check_query(self):
        button = self.buttonBox.button(QDialogButtonBox.StandardButton.Apply)
        enabled = not self.errors
        button.setEnabled(enabled)
        button.setToolTip("Run the analysis." if enabled else "There are errors in the tab.")

    #
    # Save/Load tab
    #
    def save(self):
        raise NotImplementedError

    def load(self, settings):
        raise NotImplementedError

    #
    # Results runner
    #
    def run(self, button):
        raise NotImplementedError

    def update_complete(self, count):
        raise NotImplementedError


import math
import traci
import json

class SumoObject(object):

    def __init__(self, SumoID):
        self.ID = str(SumoID)  # VehicleID
        try:

            self.height = traci.vehicle.getHeight(self.ID)

            self.ObjType = traci.vehicle.getTypeID(self.ID)
            self.Route = traci.vehicle.getRouteID(self.ID)
            self.Edge = traci.vehicle.getRoadID(self.ID)
            self.Length = traci.vehicle.getLength(self.ID)
            self.Width = traci.vehicle.getWidth(self.ID)

            self.__CalculateSizeClass() #Vehicle size category
            if traci.vehicle.getSignals(self.ID) & 8 == 8: #Bitmask - 8 for brake light
                self.StBrakePedal = True
            else:
                self.StBrakePedal = False

            tmp_pos = traci.vehicle.getPosition(self.ID)  # position: x,y
            self.PosX_FrontBumper = tmp_pos[0] # X position (front bumper, meters)
            self.PosY_FrontBumper = tmp_pos[1] # Y position (front bumper, meters)
            self.Velocity = traci.vehicle.getSpeed(self.ID)
            self.Heading = traci.vehicle.getAngle(self.ID)
            self.Color = traci.vehicle.getColor(self.ID)

            self.__CalculateCenter() #self.PosX_Center, self.PosY_Center (center, meters)

            self.vehicleClass = traci.vehicle.getVehicleClass(self.ID)

        except:
            print("Error creating container for SUMO vehicle: ", self.ID)

    def UpdateVehicle(self):

        if traci.vehicle.getSignals(self.ID) & 8 == 8: #Bitmask - 8 for brake light
            self.StBrakePedal = True
        else:
            self.StBrakePedal = False

        tmp_pos = traci.vehicle.getPosition(self.ID)  # position: x,y
        self.PosX_FrontBumper = tmp_pos[0]  # X position (front bumper, meters)
        self.PosY_FrontBumper = tmp_pos[1]  # Y position (front bumper, meters)
        self.Velocity = traci.vehicle.getSpeed(self.ID)
        self.Heading = traci.vehicle.getAngle(self.ID)
        self.Edge = traci.vehicle.getRoadID(self.ID)

        self.__CalculateCenter()  # self.PosX_Center, self.PosY_Center (center, meters)

    def ReinsertVehicle(self):

        LaneIndex = 1  # dummy
        KeepRouteMode = 1  # KeepRoute: 2 = Free move.

        try:
            traci.vehicle.add(self.ID, self.Route)  # Try to put it back
        except:
            pass #If already there, do nothing
        try:
            traci.vehicle.moveToXY(self.ID, self.Edge, LaneIndex, self.PosX_FrontBumper, self.PosY_FrontBumper, self.Heading, KeepRouteMode)
            traci.vehicle.setSpeed(self.ID, self.Velocity)
        except:
            print("Error reinserting SUMO vehicle: ", self.ID)

    #Transforms SUMO X-Y coordinate system to GPS
    def __TransformGPS(self, PosX, PosY):
        Lon, Lat = traci.simulation.convertGeo(PosX, PosY)
        return Lon, Lat

    # Transforms front bumper position to center
    def __CalculateCenter(self):
        self.PosX_Center = self.PosX_FrontBumper - (math.sin(math.radians(self.Heading)) * (self.Length / 2))
        self.PosY_Center = self.PosY_FrontBumper - (math.cos(math.radians(self.Heading)) * (self.Length / 2))

    # Defines vehicle category based on its size
    def __CalculateSizeClass(self):

        if self.Length < 1:
            self.SizeClass = 1 #pedestrian (workaround)
        elif  self.Length < 4:
            self.SizeClass = 11 #Small car
        elif self.Length < 5:
            self.SizeClass = 12 #Medium car
        else:
            self.SizeClass = 13 #Large car

    def updateFromUnity(self, data):
        self.PosX_Center = data["position"][0]
        self.PosY_Center = data["position"][1]
        self.Heading = data["heading"]

        self.calculateBumper()

    def calculateBumper(self):
        self.PosX_FrontBumper = self.PosX_Center + (math.sin(math.radians(self.Heading)) * (self.Length / 2))
        self.PosY_FrontBumper = self.PosY_Center + (math.cos(math.radians(self.Heading)) * (self.Length / 2))

    def jsonDeleteData(self):
        data = {}

        data["vehicleId"] = self.ID

        return json.dumps(data)

    def jsonInitData(self):
        data = {}

        data["vehicleId"] = self.ID
        data["sizeClass"] = self.SizeClass
        data["vehicleClass"] = self.vehicleClass
        data["colorHex"] = '#%02x%02x%02x' % self.Color[0:3]
        data["length"] = self.Length
        data["width"] = self.Width
        data["height"] = self.height

        return json.dumps(data)

    def jsonUpdateData(self):
        data = {}

        data["vehicleId"] = self.ID
        data["speed"] = self.Velocity
        data["heading"] = self.Heading
        data["position"] = [self.PosX_Center, self.PosY_Center]
        data["brake"] = self.StBrakePedal
        data["currentEdge"] = self.Edge

        return json.dumps(data)


"""Test the entire low-resolution correction process at low-resolution.

Compare mass
fractions corrected by IsoCor to theoretical isotopologues distributions
(with algebraic equations provided in the code for manual check).
"""

import numpy as np
import pytest
import isocor as hrcor

# Tests the entire correction process at low resolution
# (here pXY represents natural abundance of isotope X of element Y)
@pytest.mark.parametrize("data", [{"formula": "C2H2",
                                   "tracer": "13C",
                                   "v_expected": "[1., 0., 0.]",
                                   "v_measured": "[p1H * p1H, p1H * p2H * 2, p2H * p2H]",
                                   "correct_NA_tracer": False,
                                   "tracer_purity": [0.0, 1.0]},
                                  {"formula": "C2H2P10",
                                   "tracer": "13C",
                                   "v_expected": "[0.7, 0.2, 0.1]",
                                   "v_measured": "[0.7*p1H * p1H, 0.7*p1H * p2H * 2+0.2*p1H * p1H, 0.7*p2H * p2H+0.2*p1H * p2H * 2+0.1*p1H * p1H]",
                                   "correct_NA_tracer": False,
                                   "tracer_purity": [0.0, 1.0]},
                                  {"formula": "OH2",
                                   "tracer": "18O",
                                   "v_expected": "[0.6, 0.4]",
                                   "v_measured": "[0.6*p1H**2, 0.6*p2H**2+0.4*p1H**2]",
                                   "correct_NA_tracer": False,
                                   "tracer_purity": [0.0, 0.0, 1.0]},
                                  {"formula": "OH2",
                                   "tracer": "17O",
                                   "v_expected": "[0.6, 0.4]",
                                   "v_measured": "[0.6*p1H**2, 0.6*p1H*p2H*2+0.4*p1H**2]",
                                   "correct_NA_tracer": False,
                                   "tracer_purity": [0.0, 1.0, 0.0]},
                                  {"formula": "C2H2P10",
                                   "tracer": "13C",
                                   "v_expected": "[0.7, 0.2, 0.1]",
                                   "v_measured": "[0.7*p1H*p1H*p12C**2, 0.7*p1H*p2H*2*p12C**2 + 0.7*p1H*p1H*p12C*p13C*2 + 0.2*p1H*p1H*p12C, 0.7*p2H*p2H*p12C**2 + 0.7*p1H*p2H*2*p12C*p13C*2 + 0.7*p1H*p1H*p13C**2 +0.2*p1H*p1H*p13C + 0.2*p1H*p2H*2*p12C + 0.1*p1H*p1H]",
                                   "correct_NA_tracer": True,
                                   "tracer_purity": [0.0, 1.0]},
                                  {"formula": "C2H2P10",
                                   "tracer": "13C",
                                   "v_expected": "[0.7, 0.2, 0.1]",
                                   "v_measured": "[0.7*p1H**2 + 0.2*p1H**2*pur12C + 0.1*p1H**2*pur12C**2, 0.7*p1H*p2H*2 + 0.2*p1H**2*pur13C + 0.2*p1H*p2H*2*pur12C + 0.1*p1H**2*pur12C*pur13C*2 + 0.1*p1H*p2H*2*pur12C**2, 0.7*p2H**2 + 0.2*p1H*p2H*2*pur13C + 0.2*p2H**2*pur12C + 0.1*p1H**2*pur13C**2 + 0.1*p1H*p2H*2*pur12C*pur13C*2 + 0.1*p2H**2*pur12C**2]",
                                   "correct_NA_tracer": False,
                                   "tracer_purity": [0.3, 0.7]}])
def test_low_res_correction(data, data_iso, usr_tolerance):
    """Correction of non-tracer elements depending on resolution and formula.

    Measured values should be corrected for the incorporation of natural isotopes of
    non-tracers elements if the resolution was not high enough to distinguish them.
    The resolution depends on m/z ratio and thus the formula of the metabolite.
    The higher the mass, the higher the resolution should be used to distinguish all
    isotopomers and avoid to need correction.
    """
    formula = data["formula"]
    # Observed abundance of each isotopomers given the natural abundance
    # of the H isotopes
    p1H = data_iso["H"]["abundance"][0]
    p2H = data_iso["H"]["abundance"][1]
    p12C = data_iso["C"]["abundance"][0]
    p13C = data_iso["C"]["abundance"][1]
    pur12C = data["tracer_purity"][0]
    pur13C = data["tracer_purity"][1]
    v_measured = eval(data["v_measured"])
    # Expected correction
    v_expected = eval(data["v_expected"])
    # Perform correction
    metabolite = hrcor.LowResMetaboliteCorrector(formula, data["tracer"],
                                                 data_isotopes=data_iso,
                                                 correct_NA_tracer=data["correct_NA_tracer"],
                                                 derivative_formula=None,
                                                 tracer_purity=data["tracer_purity"])
    _, v_corrected, _, _ = metabolite.correct(v_measured)
    # Compare corrected vs. expected data
    np.testing.assert_allclose(v_corrected, v_expected, rtol=1e-7)


# based on
# https://stackoverflow.com/questions/27863832/calling-python-2-script-from-python-3
# https://github.com/pytest-dev/execnet/issues/26
#
# This is used to call python functions with another python version
#
# Use in the following way for example
#   bridge = Bridge(version="2.7", module="my_module", path="../path/to/source")
#   my_function = bridge.connect("my_function")
#   result = my_function(call,with,parameters,as,usual)
#
# Construction a bridge at first and then calling the .connect(str) function is done this
# way to be able to connect more then one function from a given module easily.
# keyworded argumetnts are not supported yet

import execnet
import sys
import os

class BridgeConnection:
    def __init__(self, version, module, function_name, path=None):
        self.version = version
        self.module = module
        self.function_name = function_name
        self.path = path

    def __call__(self, *args):
        gw = execnet.makegateway("popen//python=python%s" % self.version)

        script = """
                        import sys

                        outchan = channel.gateway.newchannel()
                        sys.stdout = outchan.makefile("w")
                        channel.send(outchan)
                        errchan = channel.gateway.newchannel()
                        sys.stderr = errchan.makefile("w")
                        channel.send(errchan)
                        """
        if self.path is not None:
            script += """
                        sys.path.append('%s')
                        """ % (os.path.abspath(self.path))
        script += """
                        from %s import %s as the_function

                        result = the_function(*channel.receive())

                        channel.send(result)

                        sys.stdout = sys.__stdout__
                        sys.stderr = sys.__stderr__
                        try:
                            sys.stdout.flush()
                            sys.stdout.close()
                        except:
                            pass
                        try:
                            sys.stderr.flush()
                            sys.stderr.close()
                        except:
                            pass

                        outchan.close()
                        errchan.close()
                        """ % (self.module, self.function_name)

        channel = gw.remote_exec(script)
        outchan = channel.receive()
        errchan = channel.receive()
        outchan.setcallback(lambda data: sys.stdout.write(str(data)))
        errchan.setcallback(lambda data: sys.stderr.write(str(data)))
        channel.send(args)
        result = channel.receive()
        # wait for proper shutdown
        # https://bitbucket.org/hpk42/execnet/issues/26/redirecting-stdout-stderr-in-the-remote
        outchan.waitclose()
        errchan.waitclose()
        return result

class Bridge:
    def __init__(self, version, module, path=None):
        self.version = version
        self.module = module
        self.path = path

    def __getattr__(self, item):
        return BridgeConnection(self.version, self.module, item, self.path)


# Tensorflow Version: 1.5.0

import os
import sys
import argparse
import csv
from random import Random

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

from utils import *
from visualization import *

np.random.seed(12345)
tf.set_random_seed(12345)

parser = argparse.ArgumentParser()
parser.add_argument("--model_dir", help="Direcotry where the model weights are stored.", type=str)
parser.add_argument("--iteration", help="Model iteration to use.", type=int, default=30000)
parser.add_argument("--generate", help="Generate new images", action='store_true')
parser.add_argument("--evaluate", help="Evaluate accuracy on the test set", action='store_true')
parser.add_argument("--sample", help="Sample from the test set", action='store_true')
parser.add_argument("--reconstruct", help="Sample from the test set and reconstruct with the Encoder and Generator",
                    action='store_true')
args = parser.parse_args()

model_dir = args.model_dir+"/iteration.ckpt-"+str(args.iteration)

assert os.path.exists(model_dir+".meta"), "There exists no weight file \"iteration.ckpt-"+str(args.iteration) + "\" in {}". \
        format(args.model_dir)

def read_encodings(path):
    with open(path+"/encodings.txt") as f:
        encodings = map(int, f.read().strip().split(','))

    return encodings

def read_hyperparameters(path):
    reader = csv.reader(open(path+"/hyperparameters"+args.model_dir[-20:]+".csv", "rb"))
    dict = {}
    for row in reader:
        k, v = row
        dict[k] = v

    return dict

hp_dict = read_hyperparameters(args.model_dir)

activations = {"elu" : tf.nn.elu, "relu": tf.nn.relu, "lrelu": tf.nn.leaky_relu}

g_activation = activations[hp_dict["g_activation"]]
e_activation = activations[hp_dict["e_activation"]]
d_activation = activations[hp_dict["d_activation"]]

Z_DIM = int(hp_dict["num_z"])
DISC_VARS = [10]
num_disc_vars = 0
for cla in DISC_VARS:
    num_disc_vars += cla
CONT_VARS = 2
C_DIM = num_disc_vars + CONT_VARS

mnist = input_data.read_data_sets('../../MNIST_data', one_hot=True)

truncated_normal = tf.truncated_normal_initializer(stddev=0.02)
random_normal = tf.random_normal_initializer(mean=0.0, stddev=0.01)

X = tf.placeholder(tf.float32, shape=[None, 28, 28, 1], name="X")
Y = tf.placeholder(tf.float32, shape=[None, 10], name="Y")
z = tf.placeholder(tf.float32, shape=[None, Z_DIM], name="z")
c = tf.placeholder(tf.float32, shape=[None, C_DIM], name="c")
phase = tf.placeholder(tf.bool, name='phase')

def sample_img_idxs(num_samples):
    # sample num_samples images of each class from the MNIST test set
    py_rng = Random()
    idxs = np.arange(len(mnist.test.images))
    classes_idxs = [idxs[np.argmax(mnist.test.labels, axis=1) == y] for y in range(10)]
    sampled_idxs = [py_rng.sample(class_idxs, num_samples) for class_idxs in classes_idxs]
    sampled_idxs = np.asarray(sampled_idxs).flatten()
    return sampled_idxs

def conv2d_bn_act(inputs, filters, kernel_size, kernel_init, activation, strides,
                  noise=False, noise_std=0.5, padding="VALID"):
    """
    Shortcut for a module of convolutional layer, batch normalization and possibly adding of Gaussian noise.
    :param inputs: input data
    :param filters: number of convolutional filters
    :param kernel_size: size of filters
    :param kernel_init: weight initialization
    :param activation: activation function (applied after batch normalization)
    :param strides: strides of the convolutional filters
    :param noise: whether to add gaussian noise to the output
    :param noise_std: stadnard deviation of added noise
    :param padding: padding in the conv layer
    :return: output data after applying the conv layer, batch norm, activation function and possibly Gaussian noise
    """
    _tmp = tf.layers.conv2d(inputs=inputs, filters=filters, kernel_size=kernel_size,
                            kernel_initializer=kernel_init, activation=None, strides=strides, padding=padding)
    _tmp = tf.contrib.layers.batch_norm(_tmp, center=True, scale=True, is_training=phase)
    _tmp = activation(_tmp)
    if noise:
        _tmp = gaussian_noise_layer(_tmp, noise_std, phase)

    return _tmp

def deconv2d_bn_act(inputs, filters, kernel_size, kernel_init, activation, strides, padding="SAME"):
    """
        Shortcut for a module of transposed convolutional layer, batch normalization.
        :param inputs: input data
        :param filters: number of convolutional filters
        :param kernel_size: size of filters
        :param kernel_init: weight initialization
        :param activation: activation function (applied after batch normalization)
        :param strides: strides of the convolutional filters
        :param padding: padding in the conv layer
        :return: output data after applying the transposed conv layer, batch norm, and activation function
        """
    _tmp = tf.layers.conv2d_transpose(inputs=inputs, filters=filters, kernel_size=kernel_size,
                            kernel_initializer=kernel_init, activation=None, strides=strides, padding=padding)
    _tmp = tf.contrib.layers.batch_norm(_tmp, center=True, scale=True, is_training=phase)
    _tmp = activation(_tmp)

    return _tmp

def dense_bn_act(inputs, units, activation, kernel_init, noise=False, noise_std=0.5):
    """
        Shortcut for a module of dense layer, batch normalization and possibly adding of Gaussian noise.
        :param inputs: input data
        :param units: number of units
        :param activation: activation function (applied after batch normalization)
        :param kernel_init: weight initialization
        :return: output data after applying the dense layer, batch norm, activation function and possibly Gaussian noise
        """
    _tmp = tf.layers.dense(inputs=inputs, units=units, activation=None, kernel_initializer=kernel_init)
    _tmp = tf.contrib.layers.batch_norm(_tmp, center=True, scale=True, is_training=phase)
    _tmp = activation(_tmp)
    if noise:
        _tmp = gaussian_noise_layer(_tmp, noise_std, phase)

    return _tmp

# Discriminator
def discriminate(img_input, noise_input):
    with tf.variable_scope("d_net", reuse=tf.AUTO_REUSE):
        # image discriminator
        d_x_conv_0 = conv2d_bn_act(inputs=img_input, filters=64, kernel_size=3, kernel_init=he_init,
                                   activation=d_activation, strides=2, noise=True, noise_std=0.3)

        d_x_conv_1 = conv2d_bn_act(inputs=d_x_conv_0, filters=128, kernel_size=3, kernel_init=he_init,
                                   activation=d_activation, strides=2, noise=True)

        shp = [int(s) for s in d_x_conv_1.shape[1:]]
        d_x_conv_1 = tf.reshape(d_x_conv_1, [-1, shp[0] * shp[1] * shp[2]])

        d_x_dense = dense_bn_act(inputs=d_x_conv_1, units=512, activation=d_activation, kernel_init=he_init,
                                 noise=True)

        # noise discriminator
        noise_input = tf.reshape(noise_input, (-1, 1, 1, Z_DIM+C_DIM))
        d_z_conv_0 = conv2d_bn_act(inputs=noise_input, filters=64, kernel_size=1, kernel_init=he_init,
                                   activation=d_activation, strides=1, noise=True, noise_std=0.3)

        d_z_conv_1 = conv2d_bn_act(inputs=d_z_conv_0, filters=128, kernel_size=1, kernel_init=he_init,
                                   activation=d_activation, strides=1, noise=True)
        shp = [int(s) for s in d_z_conv_1.shape[1:]]
        d_z_conv_1 = tf.reshape(d_z_conv_1, [-1, shp[0] * shp[1] * shp[2]])

        d_z_dense = dense_bn_act(inputs=d_z_conv_1, units=512, activation=d_activation, kernel_init=he_init,
                                 noise=True)

        # final discriminator
        inp = tf.concat((d_x_dense, d_z_dense), axis=1)
        d_final_dense = dense_bn_act(inputs=inp, units=1024, activation=d_activation, kernel_init=he_init,
                                 noise=True)

        # final prediction whether input is real or generated
        d_final_pred = tf.layers.dense(inputs=d_final_dense, units=1, activation=tf.nn.sigmoid,
                                       kernel_initializer=he_init)
        return d_final_pred

# Encoder + Mutual Information
def encode(image_input):
    with tf.variable_scope("e_net", reuse=tf.AUTO_REUSE):
        e_conv_0 = conv2d_bn_act(inputs=image_input, filters=32, kernel_size=3, kernel_init=he_init,
                                   activation=e_activation, strides=1)

        e_conv_1 = conv2d_bn_act(inputs=e_conv_0, filters=64, kernel_size=3, kernel_init=he_init,
                                 activation=e_activation, strides=2)

        e_conv_2 = conv2d_bn_act(inputs=e_conv_1, filters=128, kernel_size=3, kernel_init=he_init,
                                 activation=e_activation, strides=2)

        shp = [int(s) for s in e_conv_2.shape[1:]]
        e_conv_2 = tf.reshape(e_conv_2, [-1, shp[0] * shp[1] * shp[2]])

        e_dense_0 = dense_bn_act(inputs=e_conv_2, units=1024, activation=e_activation, kernel_init=he_init)

        # prediction for z, i.e. the noise part of the representation
        e_dense_z = tf.layers.dense(inputs=e_dense_0, units=Z_DIM, activation=tf.nn.tanh, kernel_initializer=he_init)

        # prediction for categorical variables of c
        e_dense_c_disc = []
        for idx, classes in enumerate(DISC_VARS):
            e_dense_c_disc.append(tf.layers.dense(inputs=e_dense_0, units=classes, activation=tf.nn.softmax,
                                                  kernel_initializer=he_init, name="e_dense_c_disc_" + str(idx)))
        e_dense_c_disc_concat = tf.concat(e_dense_c_disc, axis=1)

        # prediction for continuous variables of c
        e_dense_c_cont = tf.layers.dense(inputs=e_dense_0, units=CONT_VARS, activation=None,
                                         kernel_initializer=he_init, name="e_dense_c_cont")

        return tf.concat([e_dense_z, e_dense_c_disc_concat, e_dense_c_cont], axis=1)

# Generator
def generate(noise_input):
    with tf.variable_scope("g_net", reuse=tf.AUTO_REUSE):
        g_dense_0 = dense_bn_act(inputs=noise_input, units=3136, activation=g_activation, kernel_init=truncated_normal)
        g_dense_0 = tf.reshape(g_dense_0, [-1, 7, 7, 64])

        g_conv_0 = deconv2d_bn_act(inputs=g_dense_0, filters=128, kernel_size=4, kernel_init=truncated_normal,
                                   activation=g_activation, strides=2)

        g_conv_1 = deconv2d_bn_act(inputs=g_conv_0, filters=64, kernel_size=4, kernel_init=truncated_normal,
                                   activation=g_activation, strides=1)

        g_conv_out = tf.layers.conv2d_transpose(inputs=g_conv_1, filters=1, kernel_size=4, activation=tf.nn.sigmoid,
                                                padding='SAME', strides=2,
                                                kernel_initializer=truncated_normal)
        return g_conv_out

### don't train a classifier, just use c_disc directly as label
def test_set_accuracy(keys, encodings, z_test=args.model_dir + "/z_representations_test.npy"):
    z_representations_test = np.load(z_test)
    mappings = dict(zip(encodings, keys))
    predictions = []
    for idx in range(z_representations_test.shape[0]):
        predictions.append(mappings[np.argmax(z_representations_test[idx, Z_DIM:Z_DIM + num_disc_vars])])
    predictions = np.asarray(predictions)

    Y_mb = mnist.test.labels
    mnist_labels = np.argmax(Y_mb, axis=1)

    correct_predictions = np.equal(predictions, mnist_labels)
    acc = np.mean(correct_predictions)

    print("Accuracy: {}".format(acc))

### save z representations, i.e. encodings of images
def sample_z_reps(train=False):
    repr = encode(X)
    saver = tf.train.Saver()
    sess = tf.Session()
    saver.restore(sess, model_dir)

    if train and not os.path.exists(args.model_dir + "/z_representations_train.npy"):
        z_representations = []
        # save train representations
        for idx in range(55):
            X_mb, _ = mnist.train.next_batch(1000, shuffle=False)
            X_mb = np.reshape(X_mb, [-1, 28, 28, 1])

            z_rep = sess.run(repr, feed_dict={X: X_mb, phase: 0})
            z_rep = np.asarray(z_rep)
            z_representations.append(z_rep)

        z_representations = np.asarray(z_representations)
        with open(args.model_dir + "/z_representations_train.npy", "wb") as f:
            np.save(f, z_representations)

    # save test representations
    if not os.path.exists(args.model_dir + "/z_representations_test.npy"):
        z_representations = []
        for idx in range(10):
            # X_mb, _ = mnist.test.next_batch(1000, shuffle=False)
            X_mb = mnist.test.images[idx * 1000:idx * 1000 + 1000]
            X_mb = np.reshape(X_mb, [-1, 28, 28, 1])

            z_rep = sess.run(repr, feed_dict={X: X_mb, phase: 0})
            z_rep = np.asarray(z_rep)
            z_representations.append(z_rep)

        z_representations = np.asarray(z_representations)
        z_representations = np.reshape(z_representations, (10000, Z_DIM + C_DIM))
        with open(args.model_dir + "/z_representations_test.npy", "wb") as f:
            np.save(f, z_representations)

### sample images with low / high values of continuous variables
def sample_continuous(keys, encodings, z_test=args.model_dir+"/z_representations_test.npy"):
    if not os.path.exists(args.model_dir + "/samples"):
        os.makedirs(args.model_dir + "/samples")
    z_representations_test = np.load(z_test)

    mappings = dict(zip(encodings, keys))

    num_imgs = 30
    max_c1 = np.zeros((10,num_imgs))
    max_c1_idx = np.zeros((10,num_imgs))
    min_c1 = np.ones((10,num_imgs))
    min_c1_idx = np.zeros((10,num_imgs))
    max_c2 = np.zeros((10,num_imgs))
    max_c2_idx = np.zeros((10,num_imgs))
    min_c2 = np.ones((10,num_imgs))
    min_c2_idx = np.zeros((10,num_imgs))
    for idx, rep in enumerate(z_representations_test):
        label = mappings[np.argmax(rep[Z_DIM:Z_DIM+num_disc_vars])]
        act = max(rep[Z_DIM:Z_DIM+num_disc_vars])
        c1 = rep[-2]
        c2 = rep[-1]
        if act > 0.996:
            if c1 > min(max_c1[label]):
                _ = get_min_idx(min(max_c1[label]), max_c1[label])
                max_c1[label, _] = c1
                max_c1_idx[label, _] = idx
            if c1 < max(min_c1[label]):
                _ = get_max_idx(max(min_c1[label]), min_c1[label])
                min_c1[label, _] = c1
                min_c1_idx[label, _] = idx
            if c2 > min(max_c2[label]):
                _ = get_min_idx(min(max_c2[label]), max_c2[label])
                max_c2[label, _] = c2
                max_c2_idx[label, _] = idx
            if c2 < max(min_c2[label]):
                _ = get_max_idx(max(min_c2[label]), min_c2[label])
                min_c2[label, _] = c2
                min_c2_idx[label, _] = idx

    from matplotlib import pyplot as plt
    import matplotlib.gridspec as gridspec
    plt.tick_params(
        axis='x',          # changes apply to the x-axis
        which='both',      # both major and minor ticks are affected
        bottom='off',      # ticks along the bottom edge are off
        top='off',         # ticks along the top edge are off
        labelbottom='off')
    plt.tick_params(
        axis='y',          # changes apply to the x-axis
        which='both',      # both major and minor ticks are affected
        bottom='off',      # ticks along the bottom edge are off
        top='off',         # ticks along the top edge are off
        labelbottom='off')

    imgs = mnist.test.images
    def create_image(min_idx, max_idx, name):
        fig = plt.figure(figsize=(num_imgs*0.28, 5.6))
        gs1 = gridspec.GridSpec(20, num_imgs, wspace=0.0, hspace=0.0)

        for idx in range(20):
            for idx2 in range(num_imgs):
                if idx % 2 == 0:
                    id = int(min_idx[idx/2, idx2])
                else:
                    id = int(max_idx[idx/2, idx2])
                img = imgs[id]
                ax = plt.subplot(gs1[idx*30+idx2])
                ax.imshow(np.reshape(img, [28, 28]), cmap='Greys_r')
                ax.set_xticks([])
                ax.set_yticks([])
        fig.tight_layout(pad=0)
        fig.savefig(args.model_dir + "/samples/sample_cont_"+str(name)+".png")

    create_image(min_c1_idx, max_c1_idx, "c1")
    create_image(min_c2_idx, max_c2_idx, "c2")

### sample images from discrete variables
def sample_discrete(keys, encodings, z_test=args.model_dir+"/z_representations_test.npy"):
    if not os.path.exists(args.model_dir + "/samples"):
        os.makedirs(args.model_dir + "/samples")
    z_representations_test = np.load(z_test)

    mappings = dict(zip(encodings, keys))

    num_imgs = 60
    disc_idx = np.zeros((10, num_imgs))

    for idx in range(10):
        for idx2 in range(num_imgs):
            _ = np.random.randint(0, 10000)
            rep = z_representations_test[_, Z_DIM:Z_DIM+num_disc_vars]
            label = mappings[np.argmax(rep)]
            while (not label == idx) or (_ in disc_idx[label]):
                _ = np.random.randint(0, 10000)
                rep = z_representations_test[_, Z_DIM:Z_DIM + num_disc_vars]
                label = mappings[np.argmax(rep)]
            disc_idx[label, idx2] = _

    from matplotlib import pyplot as plt
    import matplotlib.gridspec as gridspec

    plt.tick_params(
        axis='x',          # changes apply to the x-axis
        which='both',      # both major and minor ticks are affected
        bottom='off',      # ticks along the bottom edge are off
        top='off',         # ticks along the top edge are off
        labelbottom='off')
    plt.tick_params(
        axis='y',          # changes apply to the x-axis
        which='both',      # both major and minor ticks are affected
        bottom='off',      # ticks along the bottom edge are off
        top='off',         # ticks along the top edge are off
        labelbottom='off')

    imgs = mnist.test.images

    def create_image():
        fig = plt.figure(figsize=(0.28*30, 0.28*20))
        gs1 = gridspec.GridSpec(20, 30, wspace=0.0, hspace=0.0)
        for idx1 in range(10):
            for idx2 in range(60):
                id = int(disc_idx[idx1, idx2])
                img = imgs[id]
                ax = plt.subplot(gs1[idx1*60+idx2])
                ax.imshow(np.reshape(img, [28, 28]), cmap='Greys_r')
                ax.set_xticks([])
                ax.set_yticks([])
        fig.tight_layout(pad=0)
        fig.savefig(args.model_dir + "/samples/samples_categorical.png")

    create_image()

### encode image with E, then decode with G and compare
def reconstruct():
    if not os.path.exists(args.model_dir + "/samples"):
        os.makedirs(args.model_dir + "/samples")

    encoding = encode(X)
    reconstruction = generate(encoding)

    saver = tf.train.Saver()
    sess = tf.Session()
    saver.restore(sess, model_dir)

    # sample 20 images of each class from the MNIST test set
    sampled_idxs = sample_img_idxs(20)

    imgs = mnist.test.images[sampled_idxs]
    imgs = np.reshape(imgs, (-1, 28, 28, 1))
    imgs_recon = sess.run(reconstruction, feed_dict={X: imgs, phase: 0})

    from matplotlib import pyplot as plt
    import matplotlib.gridspec as gridspec

    plt.tick_params(
        axis='x',  # changes apply to the x-axis
        which='both',  # both major and minor ticks are affected
        bottom='off',  # ticks along the bottom edge are off
        top='off',  # ticks along the top edge are off
        labelbottom='off')
    plt.tick_params(
        axis='y',  # changes apply to the x-axis
        which='both',  # both major and minor ticks are affected
        bottom='off',  # ticks along the bottom edge are off
        top='off',  # ticks along the top edge are off
        labelbottom='off')

    def create_image():
        fig = plt.figure(figsize=(0.28 * 20, 0.28 * 20))
        gs1 = gridspec.GridSpec(20, 20, wspace=0.0, hspace=0.0)
        for idx1 in range(0, 20):
            for idx2 in range(0, 20, 2):
                ax = plt.subplot(gs1[idx1 * 20 + idx2])
                ax.imshow(np.reshape(imgs[idx1 * 10 + idx2/2], [28, 28]), cmap='Greys_r')
                ax.set_xticks([])
                ax.set_yticks([])
                ax = plt.subplot(gs1[idx1 * 20 + idx2+1])
                ax.imshow(np.reshape(imgs_recon[idx1 * 10 + idx2/2], [28, 28]), cmap='Greys_r')
                ax.set_xticks([])
                ax.set_yticks([])
        fig.tight_layout(pad=0)
        fig.savefig(args.model_dir + "/samples/samples_reconstruction.png")

    create_image()

def generate_new_samples():
    if not os.path.exists(args.model_dir + "/samples"):
        os.makedirs(args.model_dir + "/samples")

    z_tmp = sample_z_fixed(128, Z_DIM)
    c_tmp = sample_c_cat(128)
    _gen_imgs = generate(tf.concat((z, c), axis=1))

    saver = tf.train.Saver()
    sess = tf.Session()
    saver.restore(sess, model_dir)

    gen_imgs= sess.run(_gen_imgs, feed_dict={z: z_tmp[:100], c: c_tmp[:100], phase: 0})

    from matplotlib import pyplot as plt
    import matplotlib.gridspec as gridspec

    plt.tick_params(
        axis='x',  # changes apply to the x-axis
        which='both',  # both major and minor ticks are affected
        bottom='off',  # ticks along the bottom edge are off
        top='off',  # ticks along the top edge are off
        labelbottom='off')
    plt.tick_params(
        axis='y',  # changes apply to the x-axis
        which='both',  # both major and minor ticks are affected
        bottom='off',  # ticks along the bottom edge are off
        top='off',  # ticks along the top edge are off
        labelbottom='off')

    def create_image_categorical():
        fig = plt.figure(figsize=(0.28*10, 0.28*10))
        gs1 = gridspec.GridSpec(10, 10, wspace=0.0, hspace=0.0)
        for idx1 in range(10):
            for idx2 in range(10):
                img = gen_imgs[idx1*10+idx2]
                ax = plt.subplot(gs1[idx1*10+idx2])
                ax.imshow(np.reshape(img, [28, 28]), cmap='Greys_r')
                ax.set_xticks([])
                ax.set_yticks([])
        fig.tight_layout(pad=0)
        fig.savefig(args.model_dir + "/samples/generated_imgs_categorical.png")

    create_image_categorical()

if args.generate:
    generate_new_samples()
elif args.evaluate:
    assert os.path.exists(args.model_dir + '/encodings.txt'), "There exists no file \"encodings.txt\" in {}". \
        format(args.model_dir)
    sample_z_reps()
    keys = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    encodings = read_encodings(args.model_dir)
    test_set_accuracy(keys, encodings)
elif args.sample:
    sample_z_reps()
    keys = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    encodings = read_encodings(args.model_dir)
    sample_discrete(keys, encodings)
    sample_continuous(keys, encodings)
elif args.reconstruct:
    reconstruct()
else:
    print("No valid option chosen. Choose either \"--generate\", \"--evaluate\", \"--sample\" or \"--reconstruct\".")
    print("Use \"--help\" for an overview of the command line arguments.")


import xml.etree.ElementTree as ET

file_name = "./map.osm"

tree = ET.parse(file_name)
root = tree.getroot()
file_name = file_name.replace('.xml', '.txt')
f=open(file_name, "w")
for node in root.iter('node'):
    ident = node.attrib['id']
    lat = node.attrib['lat']
    lon = node.attrib['lon']
    f.write("{} {} {}\n".format(ident,lat,lon))
f.close()


from flask import render_template, flash, redirect, url_for, request
from flask_login import current_user, login_required
from app import db
from datetime import datetime
from .models import *
from .forms import *
from app.stock.models import Company
from app.account_manage.models import User,Admin
from app.balance import balance_bp

#股权列表
@balance_bp.route('/allstockown')
@login_required
def allStockOwn():
    page = int(request.args.get('page', 1))             #当前页
    per_page = int(request.args.get('per_page', 5))     #每页条数
    paginate2 = StockOwn.query.filter(StockOwn.user_id==current_user.user_id).order_by(StockOwn.company_id.asc()).paginate(page, per_page, error_out = False)
    stock_own_list = paginate2.items
    #加上公司名称和股价
    stockown_with_info = []
    for stockown in stock_own_list:
        new_stockown = {}
        new_stockown['company_id'] = stockown.company_id
        company = Company.query.filter(Company.company_id == stockown.company_id).first()
        new_stockown['company_name'] = company.company_name
        new_stockown['price'] = company.price
        new_stockown['amount']=stockown.amount
        stockown_with_info.append(new_stockown)
    return render_template("allstockown.html",
                           title='股权列表',
                           stock_own_list = stockown_with_info,
                           pagination = paginate2)

#充值
@balance_bp.route('/charge', methods = ['GET','POST'])
@login_required
def charge():
    form = ChargeForm()
    if form.validate_on_submit():
        #点击充值
        if form.submit.data:
            amount = form.amount.data
            if amount<=0:
                flash('金额错误')
            else:
                user=User.query.filter(User.user_id==current_user.user_id).first()
                user.balance+=amount
                #db.session.add(notice)
                #获取自增的Post_ID
                #db.session.flush()
                #notice_id = notice.Notice_ID
                db.session.commit()
                flash('充值成功')
                #跳转到账户页面
                return redirect(url_for('account.myinfo',info_action='checkdetail'))
        #点击取消
        else:
            flash('充值已取消')
            #跳转到账户页面
            return redirect(url_for('account.myinfo',info_action='checkdetail'))
    return render_template("charge.html",
                           title='充值',
                           form = form)


import argparse
import logging
import sys
from pathlib import Path

from maple_test.utils import ALL, BASE_DIR, OS_SEP
from maple_test.utils import complete_path, read_config, get_config_value, is_relative

TEST_CONFIG = {}
LOGGER = None
LOG_CONFIG = {}

def parse_args():
    parser = argparse.ArgumentParser()
    test_framework_parser = parser.add_argument_group("Test FrameWork arguments")
    test_framework_parser.add_argument(
        "--cfg",
        default=Path(BASE_DIR / "maple_test.cfg"),
        type=complete_path,
        help="Test framework configuration file",
    )
    test_framework_parser.add_argument(
        "-j",
        type=bigger_than_one_integer,
        metavar="<mum>",
        dest="processes",
        default=1,
        help="Run <num> cases in parallel",
    )
    test_framework_parser.add_argument(
        "--retry",
        metavar="<num>",
        default=0,
        type=bigger_than_one_integer,
        help="Re-run unsuccessful test cases",
    )
    test_framework_parser.add_argument(
        "--output",
        metavar="<file>",
        type=complete_path,
        help="Store test result at <file>",
    )
    test_framework_parser.add_argument(
        "--xml_output",
        metavar="<file>",
        type=complete_path,
        help="Store test result as xunit xml format at <file>",
    )
    test_framework_parser.add_argument(
        "--json_output",
        metavar="<file>",
        type=complete_path,
        help="Store test result as josn format at <file>",
    )
    test_framework_parser.add_argument(
        "--debug", action="store_true", help="keep test temp file"
    )
    test_framework_parser.add_argument(
        "--fail_exit",
        action="store_true",
        help="Execute test framework with a non-zero exit code if any tests fail",
    )
    test_framework_parser.add_argument(
        "-p",
        type=str,
        dest="print_type",
        action="append",
        default=[],
        choices=ALL[:],
        help="Print test cases with specified results, "
        "-pPASS -pFAIL, to print all test case that failed or passed， "
        "UNRESOLVED test case results are not displayed by default.",
    )
    test_framework_parser.add_argument(
        "--progress",
        choices=["silent", "normal", "no_flush_progress"],
        default="normal",
        help="set progress type, silent: Don't show progress, "
        "normal: one line progress bar, update per second,"
        "no_flush_progress: print test progress per 10 seconds",
    )

    test_suite_parser = parser.add_argument_group("Test Suite arguments")
    test_suite_parser.add_argument(
        "test_paths", nargs="*", type=complete_path, help="Test suite path",
    )
    test_suite_parser.add_argument(
        "--test_cfg",
        metavar="<TEST_CFG_FILE>",
        type=complete_path,
        help="test suite config file, "
        "needed when run a single case or with --test_list",
    )
    test_suite_parser.add_argument(
        "--test_list",
        metavar="<TEST_LIST_FILE>",
        type=complete_path,
        default=None,
        help="testlist path for filter test cases",
    )
    test_suite_parser.add_argument(
        "-c",
        "--config_set",
        action="append",
        dest="user_config_set",
        default=[],
        metavar="config set path",
        help="Run a test set with the specified config set path",
        type=complete_path,
    )
    test_suite_parser.add_argument(
        "-C",
        "--config",
        dest="user_config",
        metavar="key=value",
        help="Add 'key' = 'val' to the user defined configs",
        type=str,
        action=StoreDictKeyPair,
        default={},
    )
    test_suite_parser.add_argument(
        "-E",
        "--env",
        dest="user_env",
        metavar="key=value",
        help="Add 'key' = 'val' to the user defined environment variable",
        action=StoreDictKeyPair,
        default={},
    )

    running_parser = parser.add_argument_group("Running arguments")
    running_parser.add_argument(
        "--temp_dir",
        metavar="<TEMP_DIR_PATH>",
        type=complete_path,
        default=None,
        help="Location for test execute. ",
    )
    running_parser.add_argument(
        "--timeout", type=float, dest="timeout", default=600, help="test case timeout"
    )

    log_parser = parser.add_argument_group("Log arguments")
    log_parser.add_argument(
        "--log_dir",
        metavar="<LOG_DIR_FILE_PATH>",
        type=complete_path,
        default=None,
        help="Where to store test log",
    )
    log_parser.add_argument(
        "--log_level",
        "-l",
        type=get_level_name,
        default=None,
        help="set log level from: CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET",
    )
    log_parser.add_argument(
        "--verbose", action="store_true", help="enable verbose output"
    )
    log_parser.add_argument(
        "--fail-verbose",
        dest="fail_verbose",
        action="store_true",
        help="enable not pass testcase verbose output",
    )

    args = parser.parse_args()

    test_framework_config = {
        "cfg": args.cfg,
        "processes": args.processes,
        "retry": args.retry,
        "output": args.output,
        "xml_output": args.xml_output,
        "json_output": args.json_output,
        "debug": args.debug,
        "fail_exit": args.fail_exit,
        "print_type": args.print_type,
        "progress": args.progress,
        "fail_verbose": args.fail_verbose,
    }

    test_suite_config = {
        "test_paths": args.test_paths or None,
        "test_cfg": args.test_cfg,
        "cli_running_config": {
            "test_list": args.test_list,
            "user_config_set": args.user_config_set,
            "user_config": args.user_config,
            "user_env": args.user_env,
        },
    }

    running_config = {
        "temp_dir": args.temp_dir,
        "timeout": args.timeout,
    }

    log_config = {
        "dir": args.log_dir,
        "level": args.log_level,
        "verbose": args.verbose,
    }

    return test_framework_config, test_suite_config, running_config, log_config

def parser_maple_test_config_file(maple_test_cfg_file):
    raw_config = read_config(maple_test_cfg_file)
    test_paths = get_config_value(raw_config, "test-home", "dir")
    if test_paths:
        test_paths = test_paths.replace("\n", "").split(":")
    else:
        test_paths = []
    test_suite_config = {
        "test_paths": [complete_path(BASE_DIR / path) for path in test_paths if path],
    }
    log_config = {
        "dir": complete_path(
            BASE_DIR / Path(get_config_value(raw_config, "logging", "name"))
        ),
        "level": get_level_name(get_config_value(raw_config, "logging", "level")),
    }

    running_config = {
        "temp_dir": complete_path(
            BASE_DIR / Path(get_config_value(raw_config, "running", "temp_dir"))
        ),
    }

    return test_suite_config, running_config, log_config

def init_config():
    global TEST_CONFIG
    (
        TEST_CONFIG,
        cli_test_suite_config,
        cli_running_config,
        cli_log_config,
    ) = parse_args()

    (
        file_test_suite_config,
        file_running_config,
        file_log_config,
    ) = parser_maple_test_config_file(TEST_CONFIG.get("cfg"))

    cli_test_paths = cli_test_suite_config.get("test_paths") or []
    file_test_paths = file_test_suite_config.get("test_paths") or []

    for path1 in cli_test_paths:
        for path2 in file_test_paths:
            if is_relative(path1, path2):
                user_test_cfg = cli_test_suite_config.get("test_cfg")
                if not user_test_cfg:
                    cli_test_suite_config["test_cfg"] = complete_path(
                        path2 / "test.cfg"
                    )

    test_suite_config = merge_config(cli_test_suite_config, file_test_suite_config)
    running_config = merge_config(cli_running_config, file_running_config)
    log_config = merge_config(cli_log_config, file_log_config)

    if log_config.get("dir") is None:
        log_dir = complete_path(Path("./maple_test_log"))
        print(
            "No log dir find in cfg file and cli args, will create lod gir at: {}".format(
                log_dir
            )
        )
        log_config["dir"] = log_dir

    global LOGGER
    maple_test_log_config = log_config.copy()
    maple_test_log_config["verbose"] = True
    maple_test_log_config["level"] = min(20, maple_test_log_config.get("level"))
    stream_fmt = logging.Formatter("%(message)s")
    log_dir = maple_test_log_config.get("dir")
    if not log_dir.exists():
        log_dir.mkdir(parents=True, exist_ok=True)
    LOGGER = construct_logger(
        maple_test_log_config,
        "Maple_Test",
        stream_fmt=stream_fmt,
        stream_level=min(20, maple_test_log_config.get("level")),
    )
    LOGGER.info("Test log saved to {}".format(log_dir))
    running_config["log_config"] = log_config.copy()

    return test_suite_config, running_config, log_config

def merge_config(cli_config, maple_test_config):
    config = {}
    config.update(maple_test_config)
    for key, value in cli_config.items():
        if value is not None:
            config[key] = value
    return config

def get_val(key):
    global TEST_CONFIG
    return TEST_CONFIG.get(key)

class StoreDictKeyPair(argparse.Action):
    def __init__(self, option_strings, dest, nargs=None, **kwargs):
        self._nargs = nargs
        super().__init__(option_strings, dest, nargs=nargs, **kwargs)

    def __call__(self, parser, namespace, value, option_string=None):
        my_dict = getattr(namespace, self.dest)
        k = value.strip().split("=")[0].strip()
        v = "=".join(value.strip().split("=")[1:]).strip()
        my_dict[k] = v
        setattr(namespace, self.dest, my_dict)

def construct_logger(
    log_config,
    name,
    stream_fmt=None,
    file_fmt=None,
    stream_level=None,
    file_level=logging.DEBUG,
):
    name = str(name)
    log_dir = str(log_config["dir"])
    level = log_config["level"]
    verbose = log_config["verbose"]
    formatter = logging.Formatter(
        "%(asctime)s %(levelname)s %(name)s %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
    )
    if stream_fmt is None:
        stream_fmt = formatter
    if file_fmt is None:
        file_fmt = formatter
    logger = logging.getLogger(name)
    if logger.handlers:
        return logger
    logger.setLevel(logging.DEBUG)

    handler1 = logging.StreamHandler()
    handler1.setFormatter(stream_fmt)
    if not verbose:
        level = logging.WARNING
    else:
        level = logging.DEBUG
    if stream_level:
        level = stream_level
    handler1.setLevel(level)
    logger.addHandler(handler1)

    log_path = "{}{}{}.log".format(log_dir, OS_SEP, name)
    handler2 = logging.FileHandler(filename=log_path, mode="w")
    handler2.setLevel(file_level)
    handler2.setFormatter(file_fmt)
    logger.addHandler(handler2)

    logger.debug("Log file at: {}".format(log_path))
    return logger

def get_level_name(name: str):
    name = name.upper()
    return logging.getLevelName(name)

def bigger_than_one_integer(num):
    inum = int(num)
    if inum < 1:
        raise argparse.ArgumentTypeError("{} is not bigger than one".format(num))
    return inum


import json
import time

def grapfdata():
    # define a function to process the original json data to make it simplified in order to improve reaction speed.

    # load the json file
    try:
        bd_json = open('static/BikesData.json')
    except IOError:
        print("file dublin.json not found")
    else:
        print('successfully open file dublin.json ')
    finally:
        gdata = json.load(bd_json)
        bd_json.close()
    stations = {}

    # deploy the empty dictionary 'stations', and use the station name as keys.
    for i in gdata:
        if i["name"] not in stations:
            stations[i["name"]] = {}

    for m in stations:
        # ab: available bikes, abs: available bike stands
        # ab_time_usage: available bikes at different times, abs_time_usage: available bike stands at different times.
        weekday_data = {
            "Mon": {'ab': 0, 'abs': 0, 'ab_time_usage': {}, 'abs_time_usage': {}},
            "Tue": {'ab': 0, 'abs': 0, 'ab_time_usage': {}, 'abs_time_usage': {}},
            "Wed": {'ab': 0, 'abs': 0, 'ab_time_usage': {}, 'abs_time_usage': {}},
            "Thu": {'ab': 0, 'abs': 0, 'ab_time_usage': {}, 'abs_time_usage': {}},
            "Fri": {'ab': 0, 'abs': 0, 'ab_time_usage': {}, 'abs_time_usage': {}},
            "Sat": {'ab': 0, 'abs': 0, 'ab_time_usage': {}, 'abs_time_usage': {}},
            "Sun": {'ab': 0, 'abs': 0, 'ab_time_usage': {}, 'abs_time_usage': {}},
        }
        count = {}  # used to count how many values are added, will be used for average value calculation.
        count_h = {}
        # print(count_h)
        for j in weekday_data.keys():
            count[j] = 0
            count_h[j] = {}
            for i in range(0, 24):
                weekday_data[j]['ab_time_usage'][str(i)] = 0
                weekday_data[j]['abs_time_usage'][str(i)] = 0
        for i in count_h:
            for j in range(0, 24):
                count_h[i][str(j)] = 0

        for i in gdata:
            if i['name'] == m:
                for j in weekday_data.keys():
                    if j in i['DayOfWeek']:
                        weekday_data[j]['ab'] += i['available_bikes'] #sum the available bikes to get average data
                        weekday_data[j]['abs'] += i['available_bike_stands']
                        count[j] += 1

                        t = str((time.localtime(i['last_update']/1000)).tm_hour)
                        weekday_data[j]['ab_time_usage'][t] += i['available_bikes']
                        weekday_data[j]['abs_time_usage'][t] += i['available_bike_stands']
                        count_h[j][t] += 1
        for k in weekday_data.keys():
            weekday_data[k]['ab'] = round(weekday_data[k]['ab']/count[k])
            weekday_data[k]['abs'] = round(weekday_data[k]['abs']/count[k])
            for hour in weekday_data[k]['ab_time_usage']:
                weekday_data[k]['ab_time_usage'][hour] = round(weekday_data[k]['ab_time_usage'][hour]/count_h[k][hour])
            for hour in weekday_data[k]['abs_time_usage']:
                weekday_data[k]['abs_time_usage'][hour] = round(weekday_data[k]['abs_time_usage'][hour]/count_h[k][hour])
        stations[m] = weekday_data

    f = open("./static/processedBikeData.json", 'w')
    json.dump(stations, f)
    f.close()

grapfdata()


import nltk
from nltk.translate.bleu_score import sentence_bleu
from nltk.translate.bleu_score import SmoothingFunction

nltk.download('punkt')
nltk.download('stopwords')

def compute_code_bleu(reference_code, candidate_code):
    """
    Compute the CodeBLEU score.

    :param candidate_code: The generated code as a list of tokens.
    :param reference_code: The reference code as a list of tokens.
    :return: The CodeBLEU score.
    """
    # We use the smoothing function to avoid division by zero
    candidate_code = candidate_code.split()
    reference_code = reference_code.split()
    smoothing = SmoothingFunction().method1

    return sentence_bleu([reference_code], candidate_code, smoothing_function=smoothing)

if __name__ == '__main__':
    # Use the function
    candidate_code = 'LaptopParts::Keyboard hasA\nValue layout: String = \"QWERTY\",\nValue backlight: Boolean = true,\nValue language: String = \"English-US\".'.split()
    reference_code = 'LaptopParts::Keyboard hasA\nValue layout: String = \"QWERTY\",\nValue backlight: Boolean = true,\nValue language: String = \"English-US\".'.split()

    score = compute_code_bleu(candidate_code, reference_code)
    print(f"CodeBLEU score: {score}")