import numpy as np
from collections import OrderedDict

from sandbox.ignasi.policies.new_policy.utils import *
from sandbox_maml.rocky.tf.spaces.box import Box as BoxMAML
from sandbox.rocky.tf.spaces.box import Box

from rllab_maml.core.serializable import Serializable
from sandbox_maml.rocky.tf.policies.base import StochasticPolicy
from sandbox_maml.rocky.tf.distributions.diagonal_gaussian import \
    DiagonalGaussian  # This is just a util class. No params.
from rllab_maml.misc.overrides import overrides
from rllab.misc import logger
from rllab_maml.misc.tensor_utils import flatten_tensors, unflatten_tensors
from sandbox_maml.rocky.tf.misc import tensor_utils
from sandbox.ours.core.utils import make_dense_layer_with_bias_transform, forward_dense_bias_transform, \
    make_dense_layer
import time
import tensorflow as tf
from sandbox_maml.rocky.tf.misc.xavier_init import xavier_initializer
from sandbox_maml.rocky.tf.core.utils import make_input, make_param_layer, forward_param_layer, forward_dense_layer
load_params = True

class BaseMLPPolicy(StochasticPolicy, Serializable):
    def __init__(
            self,
            name,
            env_spec,
            hidden_sizes=(32, 32),
            learn_std=True,
            init_std=1.0,
            adaptive_std=False,
            bias_transform=False,
            std_share_network=False,
            std_hidden_sizes=(32, 32),
            min_std=1e-6,
            std_hidden_nonlinearity=tf.nn.tanh,
            hidden_nonlinearity=tf.nn.tanh,
            output_nonlinearity=tf.identity,
            mean_network=None,
            std_network=None,
            std_parametrization='exp',
    ):
        """
        :param env_spec:
        :param hidden_sizes: list of sizes for the fully-connected hidden layers
        :param learn_std: Is std trainable
        :param init_std: Initial std
        :param adaptive_std: boolean indicating whether std shall be a trainable variable
        :param bias_transform: boolean indicating whether bias transformation shall be added to the MLP
        :param std_share_network:
        :param std_hidden_sizes: list of sizes for the fully-connected layers for std
        :param min_std: whether to make sure that the std is at least some threshold value, to avoid numerical issues
        :param std_hidden_nonlinearity:
        :param hidden_nonlinearity: nonlinearity used for each hidden layer
        :param output_nonlinearity: nonlinearity for the output layer
        :param mean_network: custom network for the output mean
        :param std_network: custom network for the output log std
        :param std_parametrization: how the std should be parametrized. There are a few options:
            - exp: the logarithm of the std will be stored, and applied a exponential transformation
            - softplus: the std will be computed as log(1+exp(x))
        :param grad_step_size: (float) the step size taken in the learner's gradient update
        :param trainable_step_size: boolean indicating whether the inner grad_step_size shall be trainable
        :param stop_grad: whether or not to stop the gradient through the gradient.
        :param: parameter_space_noise: (boolean) whether parameter space noise shall be used when sampling from the policy
        """
        Serializable.quick_init(self, locals())
        assert isinstance(env_spec.action_space, Box) or isinstance(env_spec.action_space, BoxMAML)

        obs_dim = env_spec.observation_space.flat_dim
        self.action_dim = env_spec.action_space.flat_dim
        self.n_hidden = len(hidden_sizes)
        self.hidden_nonlinearity = hidden_nonlinearity
        self.output_nonlinearity = output_nonlinearity
        self.input_shape = (None, obs_dim,)
        self.name = name

        with tf.variable_scope(self.name):

            # create network
            if mean_network is None:
                self.all_params = create_MLP(  # TODO: this should not be a method of the policy! --> helper
                    name="mean_network",
                    input_shape=self.input_shape,
                    output_dim=self.action_dim,
                    hidden_sizes=hidden_sizes,
                    bias_transform=bias_transform,
                )
                self.input_tensor, _ = forward_MLP('mean_network', self.input_shape, self.n_hidden,
                                                   self.hidden_nonlinearity, self.output_nonlinearity,
                                                   self.all_params, reuse=None,  # Need to run this for batch norm
                                                   bias_transform=bias_transform,)

                forward_mean = lambda x, params, is_train: forward_MLP('mean_network', self.input_shape, self.n_hidden,
                                                                       self.hidden_nonlinearity,
                                                                       self.output_nonlinearity,
                                                                       params,
                                                                       input_tensor=x, is_training=is_train,
                                                                       bias_transform=bias_transform)[1]
            else:
                raise NotImplementedError('Not supported.')

            if std_network is not None:
                raise NotImplementedError('Not supported.')
            else:
                if adaptive_std:
                    raise NotImplementedError('Not supported.')
                else:
                    if std_parametrization == 'exp':
                        init_std_param = np.log(init_std)
                    elif std_parametrization == 'softplus':
                        init_std_param = np.log(np.exp(init_std) - 1)
                    else:
                        raise NotImplementedError
                    self.all_params['std_param'] = make_param_layer(
                        num_units=self.action_dim,
                        param=tf.constant_initializer(init_std_param),
                        name="output_std_param",
                        trainable=learn_std,
                    )
                    forward_std = lambda x, params: forward_param_layer(x, params['std_param'])

                # unify forward mean and forward std into a single function
                self._forward = lambda obs, params, is_train: (
                    forward_mean(obs, params, is_train), forward_std(obs, params))

                self.std_parametrization = std_parametrization

                if std_parametrization == 'exp':
                    min_std_param = np.log(min_std)
                elif std_parametrization == 'softplus':
                    min_std_param = np.log(np.exp(min_std) - 1)
                else:
                    raise NotImplementedError

                self.min_std_param = min_std_param

                self._dist = DiagonalGaussian(self.action_dim)

                self._cached_params = {}

                super(BaseMLPPolicy, self).__init__(env_spec)

                dist_info_sym = self.dist_info_sym(self.input_tensor, dict(), is_training=False)
                mean_var = dist_info_sym["mean"]
                log_std_var = dist_info_sym["log_std"]

                # pre-update policy
                self._cur_f_dist = tensor_utils.compile_function(
                    inputs=[self.input_tensor],
                    outputs=[mean_var, log_std_var],
                )

    @property
    def vectorized(self):
        return True

    @property
    def distribution(self):
        return self._dist

    def get_variable_values(self, tensor_dict):
        sess = tf.get_default_session()
        result = sess.run(tensor_dict)
        return result

    def assign_params(self, tensor_dict, param_values):
        if 'assign_placeholders' not in dir(self):
            # make computation graph, if it doesn't exist; then cache it for future use.
            self.assign_placeholders = {}
            self.assign_ops = {}
            for key in tensor_dict.keys():
                self.assign_placeholders[key] = tf.placeholder(tf.float32)
                self.assign_ops[key] = tf.assign(tensor_dict[key], self.assign_placeholders[key])

        feed_dict = {self.assign_placeholders[key]: param_values[key] for key in tensor_dict.keys()}
        sess = tf.get_default_session()
        sess.run(self.assign_ops, feed_dict)

    def dist_info_sym(self, obs_var, state_info_vars=None, all_params=None, is_training=True):
        # This function constructs the tf graph, only called during beginning of meta-training
        # obs_var - observation tensor
        # mean_var - tensor for policy mean
        # std_param_var - tensor for policy std before output
        return_params = True
        if all_params is None:
            return_params = False
            all_params = self.all_params

        mean_var, std_param_var = self._forward(obs_var, all_params, is_training)
        if self.min_std_param is not None:
            std_param_var = tf.maximum(std_param_var, self.min_std_param)
        if self.std_parametrization == 'exp':
            log_std_var = std_param_var
        elif self.std_parametrization == 'softplus':
            log_std_var = tf.log(tf.log(1. + tf.exp(std_param_var)))
        else:
            raise NotImplementedError
        if return_params:
            return dict(mean=mean_var, log_std=log_std_var), all_params
        else:
            return dict(mean=mean_var, log_std=log_std_var)

    @overrides
    def get_action(self, observation, idx=None):
        # this function takes a numpy array observations and outputs randomly sampled actions.
        # idx: index corresponding to the task/updated policy.
        flat_obs = self.observation_space.flatten(observation)
        f_dist = self._cur_f_dist
        mean, log_std = [x[0] for x in f_dist([flat_obs])]
        rnd = np.random.normal(size=mean.shape)
        action = rnd * np.exp(log_std) + mean
        return action, dict(mean=mean, log_std=log_std)

    def get_actions(self, observations):
        # this function takes a numpy array observations and outputs sampled actions.
        # Assumes that there is one observation per post-update policy distr

        flat_obs = self.observation_space.flatten_n(observations)
        result = self._cur_f_dist(flat_obs)

        if len(result) == 2:
            # NOTE - this code assumes that there aren't 2 meta tasks in a batch
            means, log_stds = result
        else:
            means = np.array([res[0] for res in result])[:, 0, :]
            log_stds = np.array([res[1] for res in result])[:, 0, :]

        rnd = np.random.normal(size=means.shape)
        actions = rnd * np.exp(log_stds) + means
        return actions, dict(mean=means, log_std=log_stds)

    def get_params_internal(self, all_params=False, **tags):
        if tags.get('trainable', False):
            params = tf.trainable_variables(scope=self.name)
        else:
            params = tf.global_variables(scope=self.name)

        # params = [p for p in params if p.name.startswith('mean_network') or p.name.startswith('output_std_param')]
        params = [p for p in params if 'Adam' not in p.name]

        return params

    def get_params(self, all_params=False, **tags):
        """
        Get the list of parameters (symbolically), filtered by the provided tags.
        Some common tags include 'regularizable' and 'trainable'
        """
        tag_tuple = tuple(sorted(list(tags.items()), key=lambda x: x[0]))
        if tag_tuple not in self._cached_params:
            self._cached_params[tag_tuple] = self.get_params_internal(all_params, **tags)
        return self._cached_params[tag_tuple]

    def get_param_values(self, all_params=False, **tags):
        params = self.get_params(all_params, **tags)
        param_values = tf.get_default_session().run(params)
        return flatten_tensors(param_values)

    def log_diagnostics(self, paths, prefix=''):
        log_stds = np.vstack([path["agent_infos"]["log_std"] for path in paths])
        logger.record_tabular(prefix + 'AveragePolicyStd', np.mean(np.exp(log_stds)))

    #### code largely not used after here except when resuming/loading a policy. ####
    def get_reparam_action_sym(self, obs_var, action_var, old_dist_info_vars):
        """
        Given observations, old actions, and distribution of old actions, return a symbolically reparameterized
        representation of the actions in terms of the policy parameters
        :param obs_var:
        :param action_var:
        :param old_dist_info_vars:
        :return:
        """
        # Not used
        new_dist_info_vars = self.dist_info_sym(obs_var, action_var)
        new_mean_var, new_log_std_var = new_dist_info_vars["mean"], new_dist_info_vars["log_std"]
        old_mean_var, old_log_std_var = old_dist_info_vars["mean"], old_dist_info_vars["log_std"]
        epsilon_var = (action_var - old_mean_var) / (tf.exp(old_log_std_var) + 1e-8)
        new_action_var = new_mean_var + epsilon_var * tf.exp(new_log_std_var)
        return new_action_var

    def get_param_dtypes(self, all_params=False, **tags):
        tag_tuple = tuple(sorted(list(tags.items()), key=lambda x: x[0]))
        if tag_tuple not in self._cached_param_dtypes:
            params = self.get_params(all_params, **tags)
            param_values = tf.get_default_session().run(params)
            self._cached_param_dtypes[tag_tuple] = [val.dtype for val in param_values]
        return self._cached_param_dtypes[tag_tuple]

    def get_param_shapes(self, all_params=False, **tags):
        tag_tuple = tuple(sorted(list(tags.items()), key=lambda x: x[0]))
        if tag_tuple not in self._cached_param_shapes:
            params = self.get_params(all_params, **tags)
            param_values = tf.get_default_session().run(params)
            self._cached_param_shapes[tag_tuple] = [val.shape for val in param_values]
        return self._cached_param_shapes[tag_tuple]

    def set_param_values(self, flattened_params, all_params=False, **tags):
        debug = tags.pop("debug", False)
        param_values = unflatten_tensors(
            flattened_params, self.get_param_shapes(all_params, **tags))
        ops = []
        feed_dict = dict()
        for param, dtype, value in zip(
                self.get_params(all_params, **tags),
                self.get_param_dtypes(all_params, **tags),
                param_values):
            if param not in self._cached_assign_ops:
                assign_placeholder = tf.placeholder(dtype=param.dtype.base_dtype)
                assign_op = tf.assign(param, assign_placeholder)
                self._cached_assign_ops[param] = assign_op
                self._cached_assign_placeholders[param] = assign_placeholder
            ops.append(self._cached_assign_ops[param])
            feed_dict[self._cached_assign_placeholders[param]] = value.astype(dtype)
            if debug:
                print("setting value of %s" % param.name)
        tf.get_default_session().run(ops, feed_dict=feed_dict)

    def set_std(self, new_std=None):
        std_params = {"std_param": self.all_params["std_param"]}
        if new_std is None:
            new_std = np.zeros(std_params["std_param"].shape)
        new_std = {"std_param": new_std}
        self.assign_params(std_params, new_std)

    def flat_to_params(self, flattened_params, all_params=False, **tags):
        return unflatten_tensors(flattened_params, self.get_param_shapes(all_params, **tags))

    def __getstate__(self):
        d = Serializable.__getstate__(self)
        global load_params
        if load_params:
            d["params"] = self.get_param_values(all_params=True)
        return d

    def __setstate__(self, d):
        Serializable.__setstate__(self, d)
        global load_params
        if load_params:
            tf.get_default_session().run(tf.variables_initializer(self.get_params(all_params=True)))
            self.set_param_values(d["params"], all_params=True)


# 이미지 인식 후 자동 저장하는 기능

import pyautogui
import schedule
import time

def job():
    try:
        location = pyautogui.locateCenterOnScreen('save_img.png',confidence=0.8)  # 정확도를 80%로 지정한다
        print(location)
        time.sleep(0.5)
        x,y = location
        pyautogui.doubleClick(x,y)
        print("저장하기 버튼을 눌렀습니다.")

    except:
        print("프로그램 창이 비활성화 중입니다")

schedule.every(5).seconds.do(job)

while 1:
        schedule.run_pending()
        time.sleep(1)


import numpy as np

from ...utils.misc import sigma

class LossFunction:
    def negative_gradient(self, y, y_pred):
        pass

    def update_terminal_regions(self, tree, X, y, y_pred, residual, learning_rate=0.1):
        terminal_regions = tree.apply(X)

        for leaf in np.unique(terminal_regions):
            mask = np.where(terminal_regions == leaf)[0]
            self.update_terminal_region(tree.nodes[leaf], X[mask], y[mask], y_pred[mask], residual[mask])

        y_pred += learning_rate * tree.predict(X)

    def update_terminal_region(self, leaf, X, y, y_pred, residual):
        pass

class BinomialDeviance(LossFunction):
    def negative_gradient(self, y, y_pred):
        '''
        y_pred here is logit. Corresponding probability is given by \sigma(y_pred)
        '''
        return y - sigma(y_pred)

    def update_terminal_region(self, leaf, X, y, y_pred, residual):
        '''
        Step given by Newton-Raphson: -grad(L(y, y_pred), y_pred)/grad^2(L(y, y_pred), y_pred)
        -grad(.) is residual
        grad^2(.) is \nabla\sigma = \sigma(1 - \sigma), \sigma = y - residual
        '''
        numerator = np.sum(residual)
        _sigma = y - residual
        denominator = np.sum(_sigma * (1 - _sigma))

        if abs(denominator) < 1e-150:
            leaf.rule.mean = 0.0
        else:
            leaf.rule.mean = numerator / denominator

class LeastSquaresError(LossFunction):
    '''
    L = 1 / 2 * ||y - y_||^2
    '''

    def negative_gradient(self, y, y_pred):
        return y - y_pred

    def update_terminal_regions(self, tree, X, y, y_pred, residual, learning_rate=0.1):
        y_pred += learning_rate * tree.predict(X)

class ObliviousBinomialDeviance:
    def __init__(self, leaf_weight, k):
        leaf_weighters = {
            'root': lambda n: np.sqrt(n / (n + k)),
            'log': lambda n: np.log(1 + n / (n + k)),
            'frac': lambda n: n / (1 + n + np.sqrt(n)),
        }
        self.leaf_weight = leaf_weighters[leaf_weight]

    def negative_gradient(self, y, y_pred):
        return y - sigma(y_pred)

    def update_terminal_regions(self, tree, X, y, y_pred, residual, learning_rate=0.1):
        terminal_regions = tree.apply(X)

        for leaf in np.unique(terminal_regions):
            # mask = np.where(terminal_regions == leaf)[0]
            mask = terminal_regions == leaf
            l_res = residual[mask]
            l_y = y[mask]
            numerator = np.sum(l_res)
            _sigma = l_y - l_res
            denominator = np.sum(_sigma * (1 - _sigma))

            if abs(denominator) < 1e-150:
                tree.leaf_values[leaf] = 0.0
            else:
                tree.leaf_values[leaf] = numerator / denominator * self.leaf_weight(np.sum(mask))

        y_pred += learning_rate * tree.predict(X)


from __future__ import absolute_import
from __future__ import unicode_literals
from django.conf import settings
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User, Group
from django.contrib.auth import login
import requests
from django.http import HttpResponse, JsonResponse
from apps.accounts.models import UserProfile
from apps.fhir.bluebutton.models import Crosswalk
from apps.fhir.bluebutton.utils import get_resourcerouter, FhirServerAuth
import urllib.request as req
import random
from .models import AnonUserState
import logging
from django.shortcuts import render
from django.views.decorators.cache import never_cache

__author__ = "Alan Viars"

logger = logging.getLogger('hhs_server.%s' % __name__)

@never_cache
def callback(request):
    token_endpoint = getattr(
        settings, 'SLS_TOKEN_ENDPOINT', 'https://test.accounts.cms.gov/v1/oauth/token')
    redirect_uri = getattr(settings, 'SLS_REDIRECT_URI',
                           'http://localhost:8000/mymedicare/sls-callback')
    userinfo_endpoint = getattr(
        settings, 'SLS_USERINFO_ENDPOINT', 'https://test.accounts.cms.gov/v1/oauth/userinfo')
    verify_ssl = getattr(settings, 'SLS_VERIFY_SSL', False)
    code = request.GET.get('code')
    state = request.GET.get('state')
    try:
        aus = AnonUserState.objects.get(state=state)
    except AnonUserState.DoesNotExist:
        return JsonResponse({"error": "your OAuth2 client application must supply a state code."},
                            status=400)
    next_uri = aus.next_uri
    token_dict = {
        "grant_type": "authorization_code",
        "code": code,
        "redirect_uri": redirect_uri}
    logger.debug("token_endpoint %s" % (token_endpoint))
    logger.debug("redirect_uri %s" % (redirect_uri))
    # Call SLS token API
    r = requests.post(token_endpoint, json=token_dict, verify=verify_ssl)
    token_response = {}
    if r.status_code != 200:
        logger.error("Token request response error %s" % (r.status_code))
        return HttpResponse("Error: HTTP %s from the token response." % (r.status_code), status=r.status_code)
    token_response = r.json()
    # Create the Bearer
    bt = "Bearer %s" % (token_response['access_token'])
    # build a headers dict with Authorization
    headers = {"Authorization": bt}
    # Call SLS userinfo: ",
    # Authorization Bearer token in header.
    r = requests.get(userinfo_endpoint, headers=headers, verify=verify_ssl)
    # print("Status", r.status_code)
    if r.status_code != 200:
        logger.error("User info request response error %s" % (r.status_code))
        return HttpResponse("Error: HTTP %s response from userinfo request." % (r.status_code), status=r.status_code)
    # Get the userinfo response object
    user_info = r.json()
    try:
        user = User.objects.get(username=user_info['sub'][9:36])
        if not user.first_name:
            user.first_name = user_info['given_name']
        if not user.last_name:
            user.last_name = user_info['family_name']
        if not user.email:
            user.email = user_info['email']
        user.save()
    except User.DoesNotExist:
        # Create a new user. Note that we can set password
        # to anything, because it won't be checked.
        user = User(username=user_info['sub'][9:36], password='',
                    first_name=user_info['given_name'],
                    last_name=user_info['family_name'],
                    email=user_info['email'])
        user.save()
    up, created = UserProfile.objects.get_or_create(
        user=user, user_type='BEN')
    group = Group.objects.get(name='BlueButton')
    user.groups.add(group)
    # Log in the user
    user.backend = 'django.contrib.auth.backends.ModelBackend'
    login(request, user)
    # Determine patient_id
    fhir_source = get_resourcerouter()
    cx, g_o_c = Crosswalk.objects.get_or_create(
        user=user, fhir_source=fhir_source)
    hicn = user_info.get('hicn', "")
    cx.user_id_hash = hicn
    cx.save()
    auth_state = FhirServerAuth(None)
    certs = (auth_state['cert_file'], auth_state['key_file'])

    # URL for patient ID.
    url = fhir_source.fhir_url + \
        "Patient/?identifier=http%3A%2F%2Fbluebutton.cms.hhs.gov%2Fidentifier%23hicnHash%7C" + \
        cx.user_id_hash + \
        "&_format=json"
    response = requests.get(url, cert=certs, verify=False)

    if 'entry' in response.json():
        identifiers = response.json()['entry'][0]['resource']['identifier']
        fhir_id = ""
        for i in identifiers:
            if i['system'] == 'http://bluebutton.cms.hhs.gov/identifier#bene_id':
                fhir_id = i['value']
            if fhir_id:
                cx.fhir_id = fhir_id
                cx.save()
    # Get first and last naem from FHIR if not in OIDC Userinfo response.
    if user_info['given_name'] == "" or user_info['family_name'] == "":
        if 'entry' in response.json():
            if 'name' in response.json()['entry'][0]['resource']:
                names = response.json()['entry'][0]['resource']['name']
                first_name = ""
                last_name = ""
                for n in names:
                    if n['use'] == 'usual':
                        last_name = n['family']
                        first_name = n['given'][0]
                    if last_name or first_name:
                        user.first_name = first_name
                        user.last_name = last_name
                        user.save()

    # Delete the AUS since its not longer needed or valid:
    aus.delete()
    return HttpResponseRedirect(next_uri)

def generate_nonce(length=26):
    """Generate pseudo-random number."""
    return ''.join([str(random.randint(0, 9)) for i in range(length)])

@never_cache
def mymedicare_login(request):
    redirect = getattr(settings, 'MEDICARE_REDIRECT_URI',
                       'http://localhost:8000/mymedicare/sls-callback')
    mymedicare_login_url = getattr(settings, 'MEDICARE_LOGIN_URI',
                                   'https://impl1.account.mymedicare.gov/?scope=openid%20profile&client_id=bluebutton')
    redirect = req.pathname2url(redirect)
    state = generate_nonce()
    state = req.pathname2url(state)
    request.session['state'] = state
    mymedicare_login_url = "%s&state=%s&redirect_uri=%s" % (
        mymedicare_login_url, state, redirect)
    next_uri = request.GET.get('next', "")
    if request.user.is_authenticated():
        return HttpResponseRedirect(next_uri)
    AnonUserState.objects.create(state=state, next_uri=next_uri)
    if 'apps.testclient' in settings.INSTALLED_APPS:
        return HttpResponseRedirect(reverse('mymedicare-choose-login'))
    return HttpResponseRedirect(mymedicare_login_url)

@never_cache
def mymedicare_choose_login(request):
    mymedicare_login_uri = getattr(settings, 'MEDICARE_LOGIN_URI',
                                   'https://impl1.account.mymedicare.gov/?scope=openid%20profile&client_id=bluebutton')
    redirect = getattr(settings, 'MEDICARE_REDIRECT_URI',
                       'http://localhost:8000/mymedicare/sls-callback')
    redirect = req.pathname2url(redirect)
    aus = AnonUserState.objects.get(state=request.session['state'])
    mymedicare_login_uri = "%s&state=%s&redirect_uri=%s" % (
        mymedicare_login_uri, aus.state, redirect)
    context = {'next_uri': aus.next_uri,
               'mymedicare_login_uri': mymedicare_login_uri}
    return render(request, 'design_system/login.html', context)


from game.item import Item

class PlateLegs(Item):
    def __init__(self):
        super().__init__()
        self.name = 'Plate Legs'
        self.slot = 5
        self.type = 'Legs'
        self.slot_name = 'legs'
        self.defense = {'physical': 5}
        self.price = 800
        self.require = {'level': 6}

plate_legs = PlateLegs()


from os import path, mkdir
import glob
import DatasetStructure as ds
import datetime
import Settings as st
import shutil

def remove_dots_in_filenames(old_filename):
    filename_without_ext = path.splitext(old_filename)[0]
    filename_without_ext = filename_without_ext.replace('.', '_')
    return filename_without_ext + st.file_format

def copyfiles(src_path, dest_path):
    now = datetime.datetime.now()
    print('[{0}] starting to copy {1}...'.format(now, dest_path))
    src_full_path = path.join(st.src_root, src_path)
    if not path.exists(src_full_path):
        print('Folder {0} was not found. Number of classes may need reconsideration.'.format(src_full_path))
    dest_full_path = path.join(st.imbalanced_dataset_root, dest_path)
    if not path.exists(dest_full_path):
        mkdir(dest_full_path)

    scr_samples_path = glob.glob(path.join(src_full_path, st.mask))
    for src_sample_path in scr_samples_path:
        if path.isfile(src_sample_path):
            # exclude dots in file names
            old_filename = path.basename(src_sample_path)
            new_filename = remove_dots_in_filenames(old_filename)
            shutil.copy(src_sample_path, path.join(dest_full_path, new_filename))
    now = datetime.datetime.now()
    print('[{2}] copied {0} samples in {1}'.format(len(scr_samples_path), dest_path, now))

if not path.exists(st.imbalanced_dataset_root):
    mkdir(st.imbalanced_dataset_root)

# region DO2
do2_src_path = 'scr\\1_outer\\0\\'  # ДО2 без дефектов
do2_src_path_cracked_pad = 'scr\\1_outer\\4\\'  # ДО2 с трещиной в подкладке
do2_src_path_turned_pad = 'scr\\1_outer\\5\\'  # ДО2 с разворотом подкладки
do2_src_path_missing_crutch = 'scr\\1_outer\\6\\'  # ДО2 без костыля
do2_src_path_pulled_out_crutch = 'scr\\1_outer\\7\\'  # ДО2 с наддернутым костылем

copyfiles(do2_src_path, ds.do2_path)
if ds.include_defected_and_missing:
    copyfiles(do2_src_path_cracked_pad, ds.do2_path_cracked_pad)
    copyfiles(do2_src_path_turned_pad, ds.do2_path_turned_pad)
    copyfiles(do2_src_path_missing_crutch, ds.do2_path_missing_crutch)
    copyfiles(do2_src_path_pulled_out_crutch, ds.do2_path_pulled_out_crutch)
# endregion

# region DO3
do3_src_path = 'scr\\1_inner\\0\\'  # ДО3 без дефектов
do3_src_path_cracked_pad = 'scr\\1_inner\\4\\'  # ДО3 с трещиной в подкладке
do3_src_path_turned_pad = 'scr\\1_inner\\5\\'  # ДО3 с разворотом подкладки
do3_src_path_missing_crutch = 'scr\\1_inner\\6\\'  # ДО3 без костыля
do3_src_path_pulled_out_crutch = 'scr\\1_inner\\7\\'  # ДО3 с наддернутым костылем

copyfiles(do3_src_path, ds.do3_path)
if ds.include_defected_and_missing:
    copyfiles(do3_src_path_cracked_pad, ds.do3_path_cracked_pad)
    copyfiles(do3_src_path_turned_pad, ds.do3_path_turned_pad)
    copyfiles(do3_src_path_missing_crutch, ds.do3_path_missing_crutch)
    copyfiles(do3_src_path_pulled_out_crutch, ds.do3_path_pulled_out_crutch)
# endregion

# region KB
kb_src_path = 'scr\\5\\0'  # КБ без дефектов
kb_src_path_cracked_pad = 'scr\\5\\4\\'  # КБ с трещиной в подкладке
kb_src_path_turned_pad = 'scr\\5\\5\\'  # КБ с разворотом подкладки
kb_src_path_missing_bolt = 'scr\\5\\8\\'  # КБ без болта
kb_src_path_missing_nut = 'scr\\5\\9\\'  # КБ без гайки
kb_src_path_missing_cleat = 'scr\\5\\11\\'  # КБ без клеммы
kb_src_path_broken_cleat = 'scr\\5\\12\\'  # КБ с изломом клеммы

copyfiles(kb_src_path, ds.kb_path)
if ds.include_defected_and_missing:
    copyfiles(kb_src_path_cracked_pad, ds.kb_path_cracked_pad)
    copyfiles(kb_src_path_turned_pad, ds.kb_path_turned_pad)
    copyfiles(kb_src_path_missing_bolt, ds.kb_path_missing_bolt)
    copyfiles(kb_src_path_missing_nut, ds.kb_path_missing_nut)
    copyfiles(kb_src_path_missing_cleat, ds.kb_path_missing_cleat)
    copyfiles(kb_src_path_broken_cleat, ds.kb_path_broken_cleat)
# endregion

# region KB OP105
kbop105_src_path = 'scr\\6\\0'  # КБ ОП105 без дефектов
kbop105_src_path_cracked_pad = 'scr\\6\\4\\'  # КБ ОП105 с трещиной в подкладке
kbop105_src_path_turned_pad = 'scr\\6\\5\\'  # КБ ОП105 с разворотом подкладки
kbop105_src_path_missing_bolt = 'scr\\6\\8\\'  # КБ ОП105 без болта
kbop105_src_path_missing_nut = 'scr\\6\\9\\'  # КБ ОП105 без гайки
kbop105_src_path_missing_cleat = 'scr\\6\\11\\'  # КБ ОП105 без клеммы
kbop105_src_path_broken_cleat = 'scr\\6\\12\\'  # КБ ОП105 с изломом клеммы

copyfiles(kbop105_src_path, ds.kbop105_path)
if ds.include_defected_and_missing:
    copyfiles(kbop105_src_path_cracked_pad, ds.kbop105_path_cracked_pad)
    copyfiles(kbop105_src_path_turned_pad, ds.kbop105_path_turned_pad)
    copyfiles(kbop105_src_path_missing_bolt, ds.kbop105_path_missing_bolt)
    copyfiles(kbop105_src_path_missing_nut, ds.kbop105_path_missing_nut)
    copyfiles(kbop105_src_path_missing_cleat, ds.kbop105_path_missing_cleat)
    copyfiles(kbop105_src_path_broken_cleat, ds.kbop105_path_broken_cleat)
# endregion

# region JBR
jbr_src_path = 'scr\\10\\0'  # ЖБР без дефектов
jbr_src_path_cracked_pad = 'scr\\10\\4\\'  # ЖБР с трещиной в подкладке
jbr_src_path_turned_pad = 'scr\\10\\5\\'  # ЖБР с разворотом подкладки
jbr_src_path_missing_bolt = 'scr\\10\\8\\'  # ЖБР без болта
jbr_src_path_missing_nut = 'scr\\10\\9\\'  # ЖБР без гайки
jbr_src_path_missing_cleat = 'scr\\10\\11\\'  # ЖБР без клеммы
jbr_src_path_broken_cleat = 'scr\\10\\12\\'  # ЖБР с изломом клеммы

copyfiles(jbr_src_path, ds.jbr_path)
if ds.include_defected_and_missing:
    copyfiles(jbr_src_path_cracked_pad, ds.jbr_path_cracked_pad)
    copyfiles(jbr_src_path_turned_pad, ds.jbr_path_turned_pad)
    copyfiles(jbr_src_path_missing_bolt, ds.jbr_path_missing_bolt)
    copyfiles(jbr_src_path_missing_nut, ds.jbr_path_missing_nut)
    copyfiles(jbr_src_path_missing_cleat, ds.jbr_path_missing_cleat)
    copyfiles(jbr_src_path_broken_cleat, ds.jbr_path_broken_cleat)
# endregion

# region ARS
ars_src_path = 'scr\\18\\0'  # АРС без дефектов
ars_src_path_cracked_pad = 'scr\\18\\4\\'  # АРС с трещиной в подкладке
ars_src_path_turned_pad = 'scr\\18\\5\\'  # АРС с разворотом подкладки
ars_src_path_missing_bolt = 'scr\\18\\8\\'  # АРС без болта
ars_src_path_missing_nut = 'scr\\18\\9\\'  # АРС без гайки
ars_src_path_missing_cleat = 'scr\\18\\11\\'  # АРС без клеммы
ars_src_path_broken_cleat = 'scr\\18\\12\\'  # АРС с изломом клеммы

copyfiles(ars_src_path, ds.ars_path)
if ds.include_defected_and_missing:
    copyfiles(ars_src_path_cracked_pad, ds.ars_path_cracked_pad)
    copyfiles(ars_src_path_turned_pad, ds.ars_path_turned_pad)
    copyfiles(ars_src_path_missing_bolt, ds.ars_path_missing_bolt)
    copyfiles(ars_src_path_missing_nut, ds.ars_path_missing_nut)
    copyfiles(ars_src_path_missing_cleat, ds.ars_path_missing_cleat)
    copyfiles(ars_src_path_broken_cleat, ds.ars_path_broken_cleat)
# endregion

# region fakes and missing
do2_missing_src_path = 'scr\\1_outer\\2\\2\\'  # ДО2 отсутствующий
do3_missing_src_path = 'scr\\1_inner\\3\\2\\'  # ДО3 отсутствующий
kb_missing_src_path = 'scr\\5\\2\\'  # КБ отсутствующий
kbop105_missing_src_path = 'scr\\6\\2\\'  # КБ ОП105 отсутствующий
jbr_missing_src_path = 'scr\\10\\2\\'  # ЖБР
ars_missing_src_path = 'scr\\18\\2\\'  # АРС отсутствующий

fake_src_path = 'scr\\fake\\'

if ds.include_defected_and_missing:
    copyfiles(do2_missing_src_path, ds.missing_path)
    copyfiles(do3_missing_src_path, ds.missing_path)
    copyfiles(kb_missing_src_path, ds.missing_path)
    copyfiles(kbop105_missing_src_path, ds.missing_path)
    copyfiles(jbr_missing_src_path, ds.missing_path)
    copyfiles(ars_missing_src_path, ds.missing_path)

if ds.include_fakes:
    copyfiles(fake_src_path, ds.fake_path)
# endregion


import os

import librosa
import numpy as np

from audio.conversion import ms_to_samples, magnitude_to_decibel, normalize_decibel
from audio.features import linear_scale_spectrogram, mel_scale_spectrogram
from audio.io import load_wav
from datasets.dataset_helper import DatasetHelper
from datasets.statistics import collect_decibel_statistics, collect_duration_statistics
from tacotron.params.model import model_params

class CMUDatasetHelper(DatasetHelper):
    """
    Dataset loading helper for the CMU_ARCTIC dataset.
    """
    # Mel. scale spectrogram reference dB over the entire dataset.
    mel_mag_ref_db = 9.33

    # Mel. scale spectrogram maximum dB over the entire dataset.
    mel_mag_max_db = 100.0

    # Linear scale spectrogram reference dB over the entire dataset.
    linear_ref_db = 36.50

    # Linear scale spectrogram maximum dB over the entire dataset.
    linear_mag_max_db = 100.0

    # Raw waveform silence reference signal dB.
    raw_silence_db = None

    def __init__(self, dataset_folder, char_dict, fill_dict):
        super().__init__(dataset_folder, char_dict, fill_dict)

        self._abbreviations = {
            '.': ''
        }

    def load(self, max_samples=None, min_len=None, max_len=None, listing_file_name='train.txt'):
        data_file = os.path.join(self._dataset_folder, listing_file_name)
        wav_folder = os.path.join(self._dataset_folder, 'wav')

        file_paths = []
        sentences = []
        with open(data_file, 'r') as listing_file:
            # Iterate the metadata file.
            for line in listing_file:
                file_id, normalized_sentence = line.split(' ', maxsplit=1)

                # Remove new line characters.
                normalized_sentence = normalized_sentence.strip()

                # Extract the transcription.
                # We do not want the sentence to contain any non ascii characters.
                sentence = self.utf8_to_ascii(normalized_sentence)

                # Skip sentences in case they do not meet the length requirements.
                sentence_len = len(sentence)
                if min_len is not None:
                    if sentence_len < min_len:
                        continue

                # Skip sentences in case they do not meet the length requirements.
                if max_len is not None:
                    if sentence_len > max_len:
                        continue

                sentences.append(sentence)

                # Get the audio file path.
                file_path = '{}.wav'.format(os.path.join(wav_folder, file_id))
                file_paths.append(file_path)

                if max_samples is not None:
                    if len(sentences) == max_samples:
                        break

        # Normalize sentences, convert the characters to dictionary ids and determine their lengths.
        id_sentences, sentence_lengths = self.process_sentences(sentences)

        # for k, v in self._char2idx_dict.items():
        #     print("'{}': {},".format(k, v))

        return id_sentences, sentence_lengths, file_paths

    @staticmethod
    def load_audio(file_path):
        # Window length in audio samples.
        win_len = ms_to_samples(model_params.win_len, model_params.sampling_rate)
        # Window hop in audio samples.
        hop_len = ms_to_samples(model_params.win_hop, model_params.sampling_rate)

        # Load the actual audio file.
        wav, sr = load_wav(file_path.decode())

        # TODO: Determine a better silence reference level for the CMU_ARCTIC dataset (See: #9).
        # Remove silence at the beginning and end of the wav so the network does not have to learn
        # some random initial silence delay after which it is allowed to speak.
        wav, _ = librosa.effects.trim(wav)

        # Calculate the linear scale spectrogram.
        # Note the spectrogram shape is transposed to be (T_spec, 1 + n_fft // 2) so dense layers
        # for example are applied to each frame automatically.
        linear_spec = linear_scale_spectrogram(wav, model_params.n_fft, hop_len, win_len).T

        # Calculate the Mel. scale spectrogram.
        # Note the spectrogram shape is transposed to be (T_spec, n_mels) so dense layers for
        # example are applied to each frame automatically.
        mel_spec = mel_scale_spectrogram(wav, model_params.n_fft, sr, model_params.n_mels,
                                         model_params.mel_fmin, model_params.mel_fmax, hop_len,
                                         win_len, 1).T

        # Convert the linear spectrogram into decibel representation.
        linear_mag = np.abs(linear_spec)
        linear_mag_db = magnitude_to_decibel(linear_mag)
        linear_mag_db = normalize_decibel(linear_mag_db,
                                          CMUDatasetHelper.linear_ref_db,
                                          CMUDatasetHelper.linear_mag_max_db)
        # => linear_mag_db.shape = (T_spec, 1 + n_fft // 2)

        # Convert the mel spectrogram into decibel representation.
        mel_mag = np.abs(mel_spec)
        mel_mag_db = magnitude_to_decibel(mel_mag)
        mel_mag_db = normalize_decibel(mel_mag_db,
                                       CMUDatasetHelper.mel_mag_ref_db,
                                       CMUDatasetHelper.mel_mag_max_db)
        # => mel_mag_db.shape = (T_spec, n_mels)

        # Tacotron reduction factor.
        if model_params.reduction > 1:
            mel_mag_db, linear_mag_db = DatasetHelper.apply_reduction_padding(mel_mag_db,
                                                                              linear_mag_db,
                                                                              model_params.reduction)

        return np.array(mel_mag_db).astype(np.float32), \
               np.array(linear_mag_db).astype(np.float32)

if __name__ == '__main__':
    init_char_dict = {
        'pad': 0,  # padding
        'eos': 1,  # end of sequence
        'a': 2, 'u': 3, 't': 4, 'h': 5, 'o': 6, 'r': 7, ' ': 8, 'f': 9, 'e': 10, 'd': 11, 'n': 12,
        'g': 13, 'i': 14, 'l': 15, ',': 16, 'p': 17, 's': 18, 'c': 19, 'm': 20, 'z': 21, 'w': 22,
        'v': 23, 'k': 24, 'b': 25, "'": 26, 'y': 27, 'j': 28, 'q': 29, 'x': 30, '-': 31, ';': 32
    }

    dataset = CMUDatasetHelper(dataset_folder='/thesis/datasets/cmu_us_slt_arctic',
                               char_dict=init_char_dict,
                               fill_dict=False)

    ids, lens, paths = dataset.load()

    # dataset.pre_compute_features(paths)

    # Print a small sample from the dataset.
    # for p, s, l in zip(paths[:10], ids[:10], lens[:10]):
    #     print(p, np.fromstring(s, dtype=np.int32)[:10], l)

    # Collect and print the duration statistics for all the files.
    # collect_duration_statistics("CMU US SLT Arctic", paths)


import torch.nn as nn
import math

class NeuralNet(nn.Module):
    def __init__(self, input_shape: int, layer_size: list, post_layers: list):
        super(NeuralNet, self).__init__()
        layers = []
        first = False
        last_layer = 0
        for x, y in zip(layer_size, post_layers):
            if x == layer_size[0] and first is False:
                layers.append(nn.Linear(input_shape, x))
                last_layer = x
                first = True
            else:
                layers.append(nn.Linear(last_layer, x))
                last_layer = x
            if type(y) == list:
                for item in y:
                    layers.append(item)
            else:
                layers.append(y)
        self.fc = nn.Sequential(*layers)
        self.fc = self.fc.apply(self.init_weights)

    @staticmethod
    def init_weights(m):
        if type(m) == nn.Linear:
            n = m.in_features
            y = 1 / math.sqrt(n)
            m.weight.data.uniform_(-y, y)
            m.bias.data.fill_(0)

    def forward(self, x):
        return self.fc(x)


import csv

with open('generic.csv',mode='r') as generic:
 reader = csv.reader(generic)
 for rows in reader:
  name = rows[0]
#   print(name)
  name= name.replace(" ", "_")
  name = name+".md"
  print(name)
  f= open(name,"w+")
  f.close()


from math import gcd
import random
from oving3 import crypto_utils as cu

# --------- Superclass Cipher ----------
class Cipher:

    def __init__(self):
        self.alphabet_size = 95
        self.legal_alphabet = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
        #self.legal_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        #self.alphabet_size = 26

    def encode(self,text,key):
        return NotImplementedError

    def decode(self,text,key):
        return NotImplementedError

    def verify(self, decodedText,encodedText):
        return decodedText == self.decode(encodedText) and encodedText == self.encode(decodedText)

    def generate_keys(self, key):
        return NotImplementedError

#--------Sublclass Caesar-------------

class Caesar(Cipher):

    def __init__(self):
        super().__init__()

    #fra orginal tekst til kodet tekst
    def encode(self,text,key):
        self.encoded_str = ""

        for character in text:
            index = self.legal_alphabet.index(character)
            self.encoded_str += self.legal_alphabet[(index + key) % self.alphabet_size]

        return self.encoded_str

    #fra kodet tekst til orginal tekst
    def decode(self,text, key):
        self.decoded_str = ""

        for character in text:
            index = self.legal_alphabet.index(character)
            self.decoded_str += self.legal_alphabet[(index - key) % self.alphabet_size]
        return self.decoded_str

#--------Subclass Multiplikasjons-cipher--------

class Multiplication(Cipher):

    def __init__(self):
        super().__init__()

    def encode(self, text, key):
        self.encoded_str = ""

        for character in text:
            index = self.legal_alphabet.index(character)
            self.encoded_str += self.legal_alphabet[(index * key)%self.alphabet_size]

        return self.encoded_str

    def decode(self,text,key):
        self.decoded_str = ""

        #modular_inverse returnerer modulo-inversen, a = nøkkel, m= lengden av alfabetet
        #OBS: En nøkkel n virker bare bare dersom den har en modulo-invers

        for character in text:
            index = self.legal_alphabet.index(character)
            new_key = cu.modular_inverse(key,self.alphabet_size)

            self.decoded_str += self.legal_alphabet[(index * new_key) % self.alphabet_size]

        return self.decoded_str

# Genererer motsatt nøkkel, slik at den krypterte meldingen kan dekrypteres
    def generate_keys(self, key):
        return cu.modular_inverse(key,self.alphabet_size)

#---------Subclqss Affline cipher---------

#Kombinasjon av multiplikasjons-cipher og Caesar-cipher

#bruker tuple av to heltall som nøkkel n = (n1,n2) der
# n1: brukes til mullt - cipher
# n2: brukes til caesar - cipher
# Først skal text krypteres med multiplicative, derretter krypteres med Caesar

class Affline(Cipher):

    def __init__(self):
        super().__init__()

    def encode(self,text, keys):
        mult = Multiplication()
        encodedByMult = mult.encode(text,keys[0])

        caesar = Caesar()
        encodedByCaesar = caesar.encode(encodedByMult,keys[1])

        return encodedByCaesar

    def decode(self,text,keys):

        caesar = Caesar()
        decodedByCaesar = caesar.decode(text,keys[1])

        mult = Multiplication()
        decodedByMult = mult.decode(decodedByCaesar,keys[0])

        return decodedByMult

class Unbreakable(Cipher):

    # key er her secret word / et helt ord
    def __init__(self):
        super().__init__()

    def encode(self,text, keyword):
        i = 0
        encoded_str = ""

        if len(keyword) == 0:
            return""

        # Finner indeks i i nøkkelordet (tallverdi) + tallverdien til meldingen mod alfabetstrl
        for character in text:
            index = (self.legal_alphabet.index(keyword[i % len(keyword)]) + self.legal_alphabet.index(character)) % self.alphabet_size
            encoded_str += self.legal_alphabet[index]
            i +=1

        return encoded_str

    def decode(self,text, keyword):
        inverted_keyword = self.generate_inverted_key(keyword)
        decoded_str =""
        i=0

        for character in text:
            index = (self.legal_alphabet.index(inverted_keyword[i % len(inverted_keyword)]) + self.legal_alphabet.index(character)) % self.alphabet_size
            decoded_str += self.legal_alphabet[index]
            i+=1
        return decoded_str

    #Motsatt nøkkel for dekrypteringen
    def generate_inverted_key(self,key):
        inverted_key = ""
        for char in key:
            inverted_key += self.legal_alphabet[(self.alphabet_size - self.legal_alphabet.index(char)) % self.alphabet_size]
        return inverted_key

#----------Subclass RSA------------

class RSA(Cipher):

    def __init__(self):
        super().__init__()

    def encode(self,text,key):
        n,public_key = key
        blocks = cu.blocks_from_text(text,2)

        return [pow(t,public_key,n) for t in blocks] # encodet tekst

    def decode(self,text,key): #key er (n,d)      tekst er tall
        decoded_num = [pow(int(t), int(key[1]), int(key[0])) for t in text]
        decoded_str = cu.text_from_blocks(decoded_num,2)
        return decoded_str

#---------Superclass Person -----------
class Person:

    def __init__(self,key, cipher):
        self.key = key
        self.cipher = cipher

    def setKey(self,key):
        self.key = key

    def get_key(self):
        return self.key

    def operate_cipher(self,text): #Initialisere i sub-klassr
        return NotImplementedError

#----------Subclass SENDER---------

class Sender(Person):
    def __init__(self, key, cipher):
        super().__init__(key, cipher)

    def operate_cipher(self,text):
        #Genererer encodet tekst med egen cipher og nøkkel
        self.encoded_str = self.cipher.encode(text,self.key)
        return self.encoded_str

    # Hvis cipher er RSA
    def send_cipher(self,reciever,text):

        if isinstance(self.cipher,RSA):
            reciever.generate_keys()
            self.key = reciever.senderKey()

        reciever.recieve_cipher(self.operate_cipher(text))

    def test_print(self):
        return self.encoded_str

#-----------Subclass RECIEVER--------

class Receiver(Person):

    def __init__(self,key,cipher):
        super().__init__(key,cipher)

    def operate_cipher(self,text):
        self.encoded_str = text
        self.decoded_str = self.cipher.decode(text,self.key)
        return self.decoded_str

    def recieve_cipher(self,text):
        self.operate_cipher(text)

    def senderKey(self):
        return self.sender_key

    def generate_keys(self):
        p = cu.generate_random_prime(8)
        q = p
        _gcd = 0

        while q == p or _gcd != 1:
            q = cu.generate_random_prime(8)
            p = cu.generate_random_prime(8)
            phi = (p - 1) * (q - 1)
            e = random.randint(3, phi-1)
            _gcd = gcd(e, phi)
            print("p: ", p, "q: ", q, "gcd: ", _gcd)

        n = p * q
        d = cu.modular_inverse(e, phi)

        self.sender_key = (n,e)
        self.key = (n,d)

    def test_print(self):
        return self.decoded_str

#----------Subclass HACKER--------------
#Skal hacke alle cipher bortsett fra RSA
class Hacker(Person):

    def __init__(self, cipher):
        self.cipher = cipher
        self.createWords()

        #lager ordliste med ord fra fil (alle mulige ord som brukes)
    def createWords(self):
        self.words = [line.rstrip('n') for line in open('english_words.txt')]

    #finner alle mulige nøkler
    def find_possible_keys(self):
        #Sjekker hvilke nøkler som skal testes - basert på  cipher
        #teller antall treff i ordboken

        #Når den skal hacke: Vil for hver nøkkel telle hvor mange trekk det er i ordlisten
        # --> returnerer nøkkel med flest treff
        if isinstance(self.cipher, Caesar) or isinstance(self.cipher,Multiplication):
            self.match = [0] * self.cipher.alphabet_size
            return [j for j in range(self.cipher.alphabet_size)]

        elif isinstance(self.cipher,Affline):
            self.match = [0] * (self.cipher.alphabet_size)**2
            return [(k,l) for k in range(0,self.cipher.alphabet_size) for l in range(0,self.cipher.alphabet_size)]

        elif isinstance(self.cipher,Unbreakable):
            self.match = [0] * len(self.words)
            return self.words

        #liste med alle nøkler
        #Vil gå igjennom for hver nøkkel - dekode med teksten og den nøkkelen (for alle mulige nøkler)
        #for hvert ord den får der, vil den plusse på en for hvert treff i ordlisten
        # best_key = flest treff
        #returnerer teksten med den beste nøkkelen

    def decode_text(self,text):

        possible_keys = self.find_possible_keys()

        for key in possible_keys:
            decoded_str = self.cipher.decode(text,key)

            for word in decoded_str.split():
                if self.words.__contains__(word):
                    self.match[possible_keys.index(key)] += 1
                    if self.match[possible_keys.index(key)] ==1:
                        print("possible key",key)

        best_key = possible_keys[self.match.index(max(self.match))]

        print(best_key)

        return self.cipher.decode(text,best_key)

def main():
    text = "dette er en tekst som skal kodes"

    print("Opprinnelig tektst:",text, '\n')

    caesar = Caesar()
    mult = Multiplication()
    affine = Affline()
    unbreak = Unbreakable()
    rsa = RSA()

    print("CAESAR")
    s1 = Sender(3, caesar)
    r1 = Receiver(3, caesar)
    s1.send_cipher(r1, text)

    print("Sender koder teksten til:\n", s1.test_print())
    print("Mottaker dekoder teksten til:\n", r1.test_print())
    print("")

    print("MULT")
    s2 = Sender(2, mult)
    r2 = Receiver(2, mult)

    s2.send_cipher(r2, text)
    print("Sender koder teksten til:\n", s2.test_print())
    print("Mottaker dekoder teksten til:\n", r2.test_print())
    print("")

    print(("AFFINE"))
    s3 = Sender((3,2), affine)
    r3 = Receiver((3,2), affine)

    s3.send_cipher(r3, text)
    print("Sender koder teksten til:\n", s3.test_print())
    print("Mottaker dekoder teksten til:\n", r3.test_print())
    print("")

    print("RSA")
    s4 = Sender("RSA", rsa)
    r4 = Receiver("RSA", rsa)

    s4.send_cipher(r4, text)
    print("Sender koder teksten til:\n", s4.test_print())
    print("Mottaker dekoder teksten til:\n", r4.test_print())
    print("")

    print("Unbreak")
    s5 = Sender("gland", Unbreakable())
    r5 = Receiver("gland", Unbreakable())

    s5.send_cipher(r5, text)

    print("Sender koder teksten til:\n", s5.test_print())
    print("Mottaker dekoder teksten til:\n", r5.test_print())

    print("")

main()


import os, shutil

def make_classes(splits, list_of_classes):

    """Will create folders and subfolders in current directory according to input '(splits, list_of_classes):'
    Based on how data is to be split and number of prediction classes for storing data. Intended for data in image recognition and for training of CNN.

     splits: [] , list-like, string input, corresponding to file names user wants parent files to be named. Will create folders in which class folders are stored.
     list_of_classes:  [] , list-like input of predictor classes. Will create subfolders for each item in split.

Example
-------
    For binary classification with train, test and validation datasets:
     make_classes(['train','test','val'], ['class_1','class_2']
     Creates folders: 'train','test','val', each with subfolders: 'class_1','class_2'

    """
    for split in splits:
        os.mkdir('{}/'.format(split))
        for c in list_of_classes:
            sub_folder = os.path.join('{}/'.format(split), '{}'.format(c))
            os.mkdir(sub_folder)

def copy_files(orig_dir, dest_dir):

    """Will create copy all files in a directory to a new one.

     orig_dir: string input, string of directory, all files will be copied from this directory.
     dest_dir: string input, string of directory, all files will be copied to this direcory.
    """
    files = [file for file in os.listdir(orig_dir)]

    for file in files:
        origin = os.path.join(orig_dir,file)
        destination = os.path.join(dest_dir,file)
        shutil.copyfile(origin,destination)

def find_files(directory, condition):

    files = [file for file in os.listdir(directory) if condition in file]
    return files

def move_files(directory, files, destination):

    for file in files:
        origin = os.path.join(directory,  file)
        destination_file = os.path.join(destination, file)
        shutil.move(origin,destination_file)

def train_test_val(split_percentages, files):

    train_size = int(len(files)*split_percentages[0])
    test_size = int(len(files)*split_percentages[1])
    val_size = int(len(files)*split_percentages[2])

    train = []
    test = []
    val = []

    for file in files[:train_size]:
        train.append(file)
    for file in files[train_size:(len(files)-val_size)]:
        test.append(file)
    for file in files[-val_size:]:
        val.append(file)

    return train, test, val

def move_files_to_groups_by_split(split_percentages, files, groups, directory, destination_folder):

    for group in groups:
        splits={}
        splits['train'], splits['test'], splits['val'] = train_test_val(split_percentages, files[group])
        for split in splits:
            destination = '{}/{}/{}/'.format(destination_folder,split,group)
            move_files(directory, splits[split], destination)


import socket
import fcntl
import struct
import time

from oled.sequenser import ThreadedPoster
import font

class Summary(ThreadedPoster):
    def __init__(self, size):
        super(Summary, self).__init__(size, self.refresh)

    def refresh(self):
        x = self.width / 2
        left = 5
        while not self.is_terminated():
            try:
                eth = self.get_ip_address('eth0')
            except:
                eth = 'none'
            try:
                wifi = self.get_ip_address('wlan0')
            except:
                wifi = 'none'

            image, draw = self.get_new_image_and_canvas()
            pos = font.text(draw, (x, 3),
                            'Net', 'large', 'hcenter')
            pos = font.text(draw, (left, pos[1] - 2),
                            'eth0:', 'small')
            pos = font.text(draw, (x, pos[1] - 3),
                            str(eth), 'small', 'hcenter')
            pos = font.text(draw, (left, pos[1] - 2),
                            'wlan0:', 'small')
            pos = font.text(draw, (x, pos[1] - 3),
                            str(wifi), 'small', 'hcenter')
            self.image = image
            self.new_image_is_ready()
            time.sleep(2)

    def get_ip_address(self, ifname):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        ifaddr = fcntl.ioctl(
            s.fileno(), 0x8915,
            struct.pack('256s', ifname[:15].encode('utf-8')))[20:24]
        return socket.inet_ntoa(ifaddr)


import twint
from textblob import TextBlob
# Configure
def scraper(tag):

    c = twint.Config()
    # c.Username = " "
    c.Search = '#{}'.format(tag)
    c.Limit = 100
    # c.Since = "2019-08-06"
    c.Format = "Tweet id: {id} | Tweet: {tweet}"
    c.Store_object = True
    tweets=[]
    c.Store_object_tweets_list = tweets
    # Run
    c.Store_csv = True
    # CSV Fieldnames
    c.Custom["tweet"] = ["tweet"]
    # Name of the directory
    c.Output = "twitter{}".format(tag)
    twint.run.Search(c)
    return 'Twint working'