# coding=utf8

import os
import re
import copy
import itertools
import collections
import numpy as np
from overrides import overrides
from typing import List, Dict
from allennlp.data.tokenizers import Token, WordTokenizer
from allennlp.data.tokenizers.word_splitter import SpacyWordSplitter
from .atis_entity_extractor import lambda_calculus_entity_extractor, funql_entity_extractor, prolog_entity_extractor

def clean_id(s, id_suffix, strip=None):
    true_id = s.replace(' ', '_')
    if strip:
        for v in strip:
            true_id = true_id.replace(v, '').strip()
    return '%s:%s' % (true_id, id_suffix)

def clean_name(s, strip=None, split=None, prefix=None):
    if split:
        for v in split:
            s = s.replace(v, ' ')
    if strip:
        for v in strip:
            s = s.replace(v, '')
    if prefix:
        s = prefix + s
    return s

def read_db(db_path, basename, id_col, name_col, id_suffix,
            strip_id=None, strip_name=None, split_name=None, prefix_name=None):
    filename = os.path.join(db_path, basename)
    data = []  # Pairs of (name, id)
    with open(filename) as f:
        for line in f:
            row = [s[1:-1] for s in re.findall('"[^"]*"|[0-9]+', line.strip())]
            cur_name = clean_name(row[name_col].lower(), strip=strip_name,
                                  split=split_name, prefix=prefix_name)
            cur_id = clean_id(row[id_col].lower(), id_suffix, strip=strip_id)
            data.append((cur_name, cur_id))
    return data

def print_aligned(a, b, indent=0):
    a_toks = []
    b_toks = []
    for x, y in zip(a, b):
        cur_len = max(len(x), len(y))
        a_toks.append(x.ljust(cur_len))
        b_toks.append(y.ljust(cur_len))

    prefix = ' ' * indent
    print('%s%s' % (prefix, ' '.join(a_toks)))
    print('%s%s' % (prefix, ' '.join(b_toks)))

def parse_entry(line):
    """Parse an entry from the CCG lexicon."""
    return tuple(line.strip().split(' :- NP : '))

def strip_unk(w):
    # Strip unk:%06d identifiers
    m = re.match('^unk:[0-9]{6,}:(.*)$', w)
    if m:
        return m.group(1)
    else:
        return w

class ATISGNNLambdaCalculusEntityMatcher:
    TYPE_DICT = {
        'ci': 'city',
        'da': 'day',
        'al': 'airline',
        'ti': 'time',
        'pd': 'time of day',
        'dn': 'date number',
        'mn': 'month',
        'ap': 'airport',
        'cl': 'class',
        'fb': 'fare code',
        'fn': 'flight number',
        'me': 'meal',
        'do': 'dollars',
        'rc': 'restrictions',
        'ac': 'aircraft',
        'yr': 'year',
        'mf': 'manufacturer',
        'dc': 'dc',
        'st': 'state',
        'hr': 'hour',
        'i': 'stop'
    }

    DAYS_OF_WEEK = [
        (s, '%s:_da' % s)
        for s in ('monday', 'tuesday', 'wednesday', 'thursday',
                  'friday', 'saturday', 'sunday')
    ]

    NEXT_DAYS_OF_WEEK = [('day following next wednesday', 'thursday:_da')]

    # For dates
    WORD_NUMBERS = [('one', '1:_dn'), ('two', '2:_dn'), ('three', '3:_dn'), ('four', '4:_dn'), ('five', '5:_dn'),
                    ('six', '6:_dn'), ('seven', '7:_dn'), ('eight', '8:_dn'), ('nine', '9:_dn'), ('ten', '10:_dn'),
                    ('eleven', '11:_dn'), ('twelve', '12:_dn'), ('thirteen', '13:_dn'), ('fourteen', '14:_dn'),
                    ('fifteen', '15:_dn'), ('sixteen', '16:_dn'), ('seventeen', '17:_dn'), ('eighteen', '18:_dn'),
                    ('nineteen', '19:_dn'), ('twenty', '20:_dn'), ('twenty one', '21:_dn'),
                    ('twenty two', '22:_dn'),
                    ('twenty three', '23:_dn'), ('twenty four', '24:_dn'), ('twenty five', '25:_dn'),
                    ('twenty six', '26:_dn'), ('twenty seven', '27:_dn'), ('twenty eight', '28:_dn'),
                    ('twenty nine', '29:_dn'), ('thirty', '30:_dn'), ('thirty one', '31:_dn')]

    ORDINAL_NUMBERS = [('second', '2:_dn'), ('third', '3:_dn'), ('fourth', '4:_dn'), ('fifth', '5:_dn'),
                       ('sixth', '6:_dn'), ('seventh', '7:_dn'), ('eighth', '8:_dn'), ('ninth', '9:_dn'),
                       ('tenth', '10:_dn'), ('eleventh', '11:_dn'), ('twelfth', '12:_dn'), ('thirteenth', '13:_dn'),
                       ('fourteenth', '14:_dn'), ('fifteenth', '15:_dn'), ('sixteenth', '16:_dn'),
                       ('seventeenth', '17:_dn'), ('eighteenth', '18:_dn'), ('nineteenth', '19:_dn'),
                       ('twentieth', '20:_dn'), ('twenty first', '21:_dn'), ('twenty second', '22:_dn'),
                       ('twenty third', '23:_dn'), ('twenty fourth', '24:_dn'), ('twenty fifth', '25:_dn'),
                       ('twenty sixth', '26:_dn'), ('twenty seventh', '27:_dn'), ('twenty eighth', '28:_dn'),
                       ('twenty ninth', '29:_dn'), ('thirtieth', '30:_dn'),
                       ('thirty first', '31:_dn')]

    MEALS = [(m, '%s:_me' % m) for m in ('breakfast', 'lunch', 'dinner', 'snack')]

    MEAL_CODES = [('s/', 's_:_rc'), ('sd / d', 'sd_d:_rc'), ('d / s', 'd_s:_rc')]

    ST_CITIES = [(m, "%s:_ci" % m.replace(" . ", "_")) for m in ('st . louis', 'st . petersburg', 'st . paul')]

    BAT_CODES = [('737', '737:_bat'), ('767', '767:_bat')]

    AP_CODES = [('mco', 'mco:_ap'), ('ord', 'ord:_ap')]

    AL_CODES = [('us air', 'usair:_al'), ('delta', 'delta:_al'), ('ff', 'ff:_al'),
                ('canadian airlines international', 'canadian_airlines_international:_al')]

    def __init__(self, db_path):
        self.entries = collections.OrderedDict()
        self.handlers = []
        self.unique_word_map = collections.OrderedDict()
        self.seen_words = set()

        # CCG Lexicon
        filename = os.path.join(db_path, 'lexicon.txt')
        entries = []
        with open(filename) as f:
            for line in f:
                x, y = line.strip().split(' :- NP : ')
                y = y.replace(':', ':_').strip()
                entries.append((x, y))
        self.add_entries(entries)

        # Read DB
        self.add_entries(read_db(db_path, 'CITY.TAB', 1, 1, '_ci', strip_id=['.']))
        self.add_entries(self.DAYS_OF_WEEK)
        self.add_entries([(x + 's', y) for x, y in self.DAYS_OF_WEEK])  # Handle "on tuesdays"
        self.add_entries(read_db(db_path, 'AIRLINE.TAB', 0, 1, '_al',
                                 strip_name=[', inc.', ', ltd.']))
        self.add_entries(read_db(db_path, 'INTERVAL.TAB', 0, 0, '_pd'))
        self.add_entries(read_db(db_path, 'MONTH.TAB', 1, 1, '_mn'))
        self.add_entries(read_db(db_path, 'AIRPORT.TAB', 0, 1, '_ap',
                                 strip_name=[], split_name=['/']))
        self.add_entries(read_db(db_path, 'COMP_CLS.TAB', 1, 1, '_cl'))
        self.add_entries(read_db(db_path, 'CLS_SVC.TAB', 0, 0, '_fb', prefix_name='code '))
        self.add_entries(self.MEALS)
        self.add_entries(self.WORD_NUMBERS)
        self.add_entries(self.ORDINAL_NUMBERS)
        self.add_entries(self.ST_CITIES)
        self.add_entries(self.MEAL_CODES)
        self.add_entries(self.BAT_CODES)
        self.add_entries(self.AP_CODES)
        self.add_entries(self.AL_CODES)
        self.add_entries(self.NEXT_DAYS_OF_WEEK)

        self.handle_times()
        self.handle_rc()
        self.handle_stop()
        self.handle_dollars()
        self.handle_flight_numbers()

    def handle_times(self):
        # Mod 12 deals with 12am/12pm special cases...
        self.add_handler('([0-9]{1,2})\s*am$',
                         lambda m: '%d00:_ti' % (int(m.group(1)) % 12))
        self.add_handler('([0-9]{1,2}) pm$',
                         lambda m: '%d00:_ti' % (int(m.group(1)) % 12 + 12))
        self.add_handler('([0-9]{1,2})([0-9]{2}) am$',
                         lambda m: '%d%02d:_ti' % (int(m.group(1)) % 12, int(m.group(2))))
        self.add_handler('([0-9]{1,2})([0-9]{2}) pm$',
                         lambda m: '%d%02d:_ti' % (int(m.group(1)) % 12 + 12, int(m.group(2))))
        self.add_handler("([0-9]{1,2}) o'clock$",
                         lambda m: '%d00:_ti' % (int(m.group(1)) % 12))
        self.add_handler("([0-9]{1,2}) o'clock am$",
                         lambda m: '%d00:_ti' % (int(m.group(1)) % 12))
        self.add_handler("([0-9]{1,2}) o'clock pm$",
                         lambda m: '%d00:_ti' % (int(m.group(1)) % 12 + 12))
        self.add_handler("([0-9]+) hours$",
                         lambda m: '%d:_hr' % (int(m.group(1))))

    def handle_flight_numbers(self):
        self.add_handler('[0-9]{2,}$', lambda m: '%d:_fn' % int(m.group(0)))

    def handle_dollars(self):
        self.add_handler('([0-9]+)$', lambda m: '%d:_do' % int(m.group(1)))
        self.add_handler('([0-9]+) dollars$', lambda m: '%d:_do' % int(m.group(1)))

    def handle_rc(self):
        self.add_handler(re.compile(r'ap/(\d+)$'), lambda m: 'ap_%d:_rc' % int(m.group(1)))
        self.add_handler(re.compile(r'ap(\d+)$'), lambda m: 'ap_%d:_rc' % int(m.group(1)))

    def handle_stop(self):
        self.add_handler('([0-9]+) stop$', lambda m: '%d:_i' % int(m.group(1)))
        self.add_handler('([0-9]+) stops$', lambda m: '%d:_i' % int(m.group(1)))

    def add_entries(self, entries):
        for name, entity in entries:
            # Update self.entries
            if name in self.entries:
                if entity not in self.entries[name]:
                    self.entries[name].append(entity)
            else:
                self.entries[name] = [entity]

            # Update self.unique_word_map
            # for w in name.split(' '):
            #     if w in self.seen_words:
            #         # This word is not unique!
            #         if w in self.unique_word_map:
            #             del self.unique_word_map[w]
            #     else:
            #         self.unique_word_map[w] = entity
            #         self.seen_words.add(w)

    def add_handler(self, regex, func):
        self.handlers.append((regex, func))

    def _match_candidates(self, tokens: List[Token]) -> List:
        words = [t.text for t in tokens]
        entities = [[] for i in range(len(words))]
        ind_pairs = sorted(list(itertools.combinations(range(len(words) + 1), 2)),
                        key=lambda x: x[0] - x[1])
        ret_entries = []
        words = [strip_unk(w) for w in words]  # Strip unk:%06d stuff

        # Handlers
        for i, j in ind_pairs:
            if any(x for x in entities[i:j]): continue
            span = ' '.join(words[i:j])
            for regex, func in self.handlers:
                m = re.match(regex, span)
                if m:
                    entity = func(m)
                    assert isinstance(entity, str)
                    for k in range(i, j):
                        entities[k] += [entity]
                    ret_entries.append(((i, j), [entity]))

        # Entries
        for i, j in ind_pairs:
            # if any(x for x in entities[i:j]): continue
            span = ' '.join(words[i:j])
            if span in self.entries:
                entity = self.entries[span]
                assert isinstance(entity, list)
                for k in range(i, j):
                    entities[k] += entity
                ret_entries.append(((i, j), entity))

        # Unique words
        for i in range(len(words)):
            if any(x for x in entities[i:i+1]): continue
            word = words[i]
            if entities[i]: continue
            if word in self.unique_word_map:
                entity = self.unique_word_map[word]
                entities[i] = [entity]
                ret_entries.append(((i, i+1), [entity]))

        return ret_entries

    def match(self, tokens: List[Token]) -> List[Dict]:
        entity_candidates = self._match_candidates(tokens)
        formatted_entity_candidates = list()
        for ((beg_idx, end_idx), entities) in entity_candidates:
            fes = list()
            for e in entities:
                match = re.match("^(.*):_(.*)$", e)
                if match is None:
                    assert re.match('^\d+$', e)
                    ev = e
                    et = 'i'
                else:
                    ev = match.group(1)
                    et = match.group(2)
                fes.append({
                    "value": ev.replace('_', " "),
                    "beg_idx": beg_idx,
                    "end_idx": end_idx,
                    "type": et,
                    "formatted_value": e
                })
            formatted_entity_candidates += fes

        # Remove Duplicate entities
        entity_dict = dict()
        for entity in formatted_entity_candidates:
            if entity['formatted_value'] not in entity_dict:
                entity_dict[entity['formatted_value']] = list()
            entity_dict[entity['formatted_value']].append(entity)

        results = list()
        for _, entities in entity_dict.items():
            indices = list()
            for e in entities:
                beg_idx, end_idx = e['beg_idx'], e['end_idx']
                indices += list(range(beg_idx, end_idx))
            ne = copy.deepcopy(entities[0])
            del ne['beg_idx']
            del ne['end_idx']
            ne['indices'] = list(set(indices))
            results.append(ne)

        return results

class ATISGNNEntityMatcher(ATISGNNLambdaCalculusEntityMatcher):

    def __init__(self, db_path):
        super().__init__(db_path)
        self.add_entries([('new york', 'lga:_ap'), ('the airport in dallas', 'dfw:_ap')])

    @overrides
    def match(self, tokens: List[Token]) -> List[Dict]:
        entity_candidates = super().match(tokens)
        for entity in entity_candidates:
            formatted_value = entity['formatted_value']
            match = re.match("^(.*):_(.*)$", formatted_value)
            if match is None:
                assert re.match('^\d+$', e)
                ev = formatted_value
                et = 'i'
            else:
                ev = match.group(1)
                et = match.group(2)
            entity['formatted_value'] = ev

        # Remove Duplicate entities
        entity_dict = dict()
        for entity in entity_candidates:
            if entity['formatted_value'] not in entity_dict:
                entity_dict[entity['formatted_value']] = list()
            entity_dict[entity['formatted_value']].append(entity)

        results = list()
        for _, entities in entity_dict.items():
            types = list()
            for e in entities:
                types.append(e['type'])
            ne = copy.deepcopy(entities[0])
            ne['type'] = ';'.join(types)
            results.append(ne)

        return results

def test_entity_linking():
    base_path = os.path.join('../../', 'data', 'atis')
    entity_path = os.path.join(base_path, 'db')

    matcher = ATISGNNEntityMatcher(entity_path)
    toknerizer = WordTokenizer(SpacyWordSplitter())

    import sys
    sys.path += ['../../']
    from grammars.grammar import get_grammar
    from grammars.utils import get_logical_form_preprocessor
    preprocessor = get_logical_form_preprocessor('atis', 'prolog')
    grammar = get_grammar('atis', 'prolog')

    train_data = os.path.join(base_path, 'atis_prolog_test.tsv')
    empty_count = 0
    max_number_of_candidates = 0
    numbers = list()
    invalid_count = 0
    inst_count = 0
    with open(train_data, 'r') as f:
        for lidx, line in enumerate(f):
            line = line.strip()
            sentence, funql = line.split('\t')
            tokens = toknerizer.tokenize(sentence)
            candidates = matcher.match(tokens)
            inst_count += 1

            if len(candidates) > max_number_of_candidates:
                max_number_of_candidates = len(candidates)

            has_duplicate_entity = False
            for cidx1, can1 in enumerate(candidates):
                for cidx2, can2 in enumerate(candidates):
                    if cidx1 == cidx2:
                        continue
                    if can1['value'] == can2['value'] and can1['type'] == can2['type']:
                        has_duplicate_entity = True
                        break
                if has_duplicate_entity:
                    break

            if len(candidates) == 0:
                empty_count += 1
            numbers.append(len(candidates))

            # Validate
            processed_funql = preprocessor(funql).lower()
            golden_entities = prolog_entity_extractor(grammar, processed_funql)

            valid = True
            for ge in golden_entities:
                for candidate in candidates:
                    compare_value = candidate['value'] if 'formatted_value' not in candidate \
                        else candidate['formatted_value']
                    if compare_value == ge or candidate.get('abbreviation', "") == ge:
                        break
                else:
                    valid = False
            if not valid:
                invalid_count += 1

            print(lidx)
            print(sentence)
            print(tokens)
            print(funql)
            print("Number of Candidates: ", len(candidates))
            print("Has Duplicate Candidates: ", has_duplicate_entity)
            print(candidates)
            print(golden_entities)
            print("Is Valid: ", valid)
            print('===\n\n')

    print("Largest number of candidates: ", max_number_of_candidates)
    print("Number of empty candidates: ", empty_count)
    print("Averaged candidates: ", np.mean(numbers))
    print("Invalid Count: ", invalid_count)
    print("Overall Recall: ", (inst_count - invalid_count) / inst_count)

if __name__ == '__main__':
    # matcher = ATISGNNLambdaCalculusEntityMatcher('../../data/atis/db')
    # from allennlp.data.tokenizers import Token, WordTokenizer
    # from allennlp.data.tokenizers.word_splitter import SpacyWordSplitter
    # toknerizer = WordTokenizer(SpacyWordSplitter())
    #
    # question = "i'm looking for flights from pittsburgh to philadelphia leaving before 9am"
    # tokens = toknerizer.tokenize(question)
    #
    # matched_entities = matcher.match(tokens)
    # for entity in matched_entities:
    #     string = " ".join([tokens[idx].text for idx in entity['indices']])
    #     print(string, entity['value'], entity['type'])

    test_entity_linking()


from model import WikiModel, GoogleModel, WikiGoogle
from json import load
from pathlib import Path

def get_accuracy(model, questions):
    correct = 0
    for question in questions:
        pred = model.predict(question, [questions[question]["a1"], questions[question]["a2"], questions[question]["a3"]])
        print(pred)
        if pred[0] == questions[question]["correct"]:
            correct += 1
    return correct / len(questions)

def load_questions():
    table_file = Path("record.json")
    if table_file.exists():
        d = load(open('record.json'))
        return d
    return dict()

if __name__ == "__main__":
    n_co = [0.5, 1.5]
    pn_co = [3, 4]
    len_co = [2]

    questions = load_questions()

    m = WikiGoogle()
    print(get_accuracy(m, questions))
    # with open("results.txt", "w") as f:
    #     f.write("results:\n")
    # for n in n_co:
    #     for p in pn_co:
    #         for l in len_co:
    #             m = WikiModel(n, p, l)
    #             with open("results.txt", "a") as f:
    #                 r = "n:{} p:{} l:{} accuracy: {}".format(n, p, l, get_accuracy(m, questions))
    #                 f.write(r + "\n")


from threading import Lock
from threading import Thread
import time

class WorkerPool:
    """Manages pool of synchronized workers."""

    def __init__(self, worker, tasks, min_interval, context, max_workers):
        """Create new WorkerPool.
        Args:
            worker (function): func which will be used inside of
                _SynchronizedWorker.
            tasks (Queue): queue of tasks.
            min_interval (float): Minimal interval between task executions in
                seconds.
            context (object): Context object shared across all workers in pool.
            max_workers (int): Maximal number of workers.
        """
        self.workers = []
        self.tasks = tasks
        self.context = context
        self.max_workers = max_workers
        self.clock = _SharedValue(0)
        self.lock = Lock()
        for i in range(max_workers):
            new_worker = _SynchronizedWorker(
                worker, tasks, min_interval, self.lock, self.clock,
                context=context)
            self.workers.append(new_worker)

    def start(self):
        """Start all workers."""
        for worker in self.workers:
            worker.start()

    def wait_until_done(self):
        """Wait until all tasks done and workers are joined."""
        self.tasks.join()
        for worker in self.workers:
            worker.join()

class _SynchronizedWorker(Thread):
    """Runs target function (worker) over tasks queue until it ends.
    Each execution of a target function can start running no earlier than
    `min_interval` from previous execution.
    """

    def __init__(
            self, worker, tasks, min_interval, lock, clock, context=None,
            **kwargs):
        """Create new _SynchronizedWorker.
        Args:
            worker (function): target function.
            tasks (Queue): queue of tasks.
            min_interval (float): Minimal interval between task executions in
                seconds.
            lock (Lock): Lock used for synchronizing workers.
            clock (_SharedValue): Time of last worker execution (from epoch).
            context (object): Context object shared across all workers in pool.
        """
        self.tasks = tasks
        self.min_interval = min_interval
        self.lock = lock
        self.clock = clock
        kwargs['target'] = self._patch(worker)
        if context is not None:
            kwargs['args'] = (context, )
        super().__init__(daemon=True, **kwargs)

    def _patch(self, target):
        """For updating Thread target function.
        Args:
            target (function): Thread target.
        """
        def wrapper(*args, **kwargs):
            while not self.tasks.empty():
                task = self.tasks.get()

                with self.lock:
                    interval = time.time() - self.clock.value
                    time.sleep(max(0, self.min_interval - interval))
                    self.clock.value = time.time()

                new_task = target(task, *args, **kwargs)

                self.tasks.task_done()
                if new_task:
                    self.tasks.put(new_task)
        return wrapper

class _SharedValue:
    """Class that contains single value."""

    def __init__(self, value):
        """Create new SharedValue.
        Args:
            value (any): Any value.
        """
        self.value = value


import logging

import tensorflow as tf

from energy_py.common.memories import memory_register

logger = logging.getLogger(__name__)

class BaseAgent(object):
    """ The energy_py base agent class """

    def __init__(
            self,
            env,
            total_steps=0,
            sess=None,
            memory_type='deque',
            memory_length=10000,
            min_reward=-10,
            max_reward=10,
            act_path='./act_path',
            learn_path='./learn_path'
    ):

        self.sess = sess
        self.env = env

        self.observation_space = env.observation_space
        self.action_space = env.action_space

        self.memory_type = memory_type
        self.memory = memory_register[memory_type](
            memory_length,
            self.observation_space.shape,
            self.action_space.shape
        )

        #  reward clipping
        self.min_reward = min_reward
        self.max_reward = max_reward

        self.act_step = 0
        self.learn_step = 0

        #  TODO replace the lists with defaultdict(list)
        self.act_summaries = []
        self.act_writer = tf.summary.FileWriter(act_path)

        self.learn_summaries = []
        self.learn_writer = tf.summary.FileWriter(learn_path)

    def reset(self):
        """
        Resets the agent internals
        """
        logger.debug('Resetting the agent internals')
        self.memory.reset()
        self.act_step = 0
        self.learn_step = 0

        return self._reset()

    def act(self, observation, explore=1.0):
        """
        Action selection by agent

        args
            observation (np array) shape=(1, observation_dim)
            explore (float) 0.0 = 100% greedy, 1.0 = 100% explore

        return
            action (np array) shape=(1, num_actions)
        """
        logger.debug('Agent is acting')
        self.act_step += 1

        return self._act(
            observation.reshape(1, *self.observation_space.shape),
            explore=explore
        )

    def learn(self, **kwargs):
        """
        Agent learns from experience

        args
            batch (dict) batch of experience
            sess (tf.Session)

        return
            training_history (object) info about learning (i.e. loss)
        """
        logger.debug('Agent is learning')
        self.learn_step += 1

        return self._learn(**kwargs)

    def remember(self, observation, action, reward, next_observation, done):
        """
        Store experience in the agent's memory

        args
            observation (np.array)
            action (np.array)
            reward (np.array)
            next_observation (np.array)
            done (np.array)
        """
        logger.debug('Agent is remembering')

        if self.min_reward and self.max_reward:
            reward = max(self.min_reward, min(reward, self.max_reward))

        return self.memory.remember(
            observation, action, reward, next_observation, done
        )


from __future__ import absolute_import, division, print_function

__metaclass__ = type

DOCUMENTATION = r"""
---
module: scaleway_vpcgw_pat_rule
short_description: Manage Scaleway vpcgw's pat_rule
description:
    - This module can be used to manage Scaleway vpcgw's pat_rule.
version_added: "2.1.0"
author:
    - Nathanael Demacon (@quantumsheep)
extends_documentation_fragment:
    - scaleway.scaleway.scaleway
    - scaleway.scaleway.scaleway_waitable_resource
requirements:
    - scaleway >= 0.6.0
options:
    state:
        description:
            - Indicate desired state of the target.
            - C(present) will create the resource.
            - C(absent) will delete the resource, if it exists.
        default: present
        choices: ["present", "absent"]
        type: str
    pat_rule_id:
        description: pat_rule_id
        type: str
        required: false
    gateway_id:
        description: gateway_id
        type: str
        required: true
    public_port:
        description: public_port
        type: int
        required: true
    private_ip:
        description: private_ip
        type: str
        required: true
    private_port:
        description: private_port
        type: int
        required: true
    protocol:
        description: protocol
        type: str
        required: true
        choices:
            - unknown
            - both
            - tcp
            - udp
    zone:
        description: zone
        type: str
        required: false
"""

EXAMPLES = r"""
- name: Create a pat_rule
  scaleway.scaleway.scaleway_vpcgw_pat_rule:
    access_key: "{{ scw_access_key }}"
    secret_key: "{{ scw_secret_key }}"
    gateway_id: "aaaaaa"
    public_port: "aaaaaa"
    private_ip: "aaaaaa"
    private_port: "aaaaaa"
    protocol: "aaaaaa"
"""

RETURN = r"""
---
pat_rule:
    description: The pat_rule information
    returned: when I(state=present)
    type: dict
    sample:
        id: 00000000-0000-0000-0000-000000000000
        gateway_id: 00000000-0000-0000-0000-000000000000
        created_at: "aaaaaa"
        updated_at: "aaaaaa"
        public_port: 3
        private_ip: "aaaaaa"
        private_port: 3
        protocol: both
        zone: "aaaaaa"
"""

from ansible.module_utils.basic import (
    AnsibleModule,
    missing_required_lib,
)
from ansible_collections.scaleway.scaleway.plugins.module_utils.scaleway import (
    scaleway_argument_spec,
    scaleway_waitable_resource_argument_spec,
    scaleway_get_client_from_module,
    scaleway_pop_client_params,
    scaleway_pop_waitable_resource_params,
)

try:
    from scaleway import Client
    from scaleway.vpcgw.v1 import VpcgwV1API

    HAS_SCALEWAY_SDK = True
except ImportError:
    HAS_SCALEWAY_SDK = False

def create(module: AnsibleModule, client: "Client") -> None:
    api = VpcgwV1API(client)

    id = module.params.pop("id", None)
    if id is not None:
        resource = api.get_pat_rule(pat_rule_id=id)

        if module.check_mode:
            module.exit_json(changed=False)

        module.exit_json(changed=False, data=resource)

    if module.check_mode:
        module.exit_json(changed=True)

    not_none_params = {
        key: value for key, value in module.params.items() if value is not None
    }
    resource = api.create_pat_rule(**not_none_params)

    module.exit_json(changed=True, data=resource.__dict__)

def delete(module: AnsibleModule, client: "Client") -> None:
    api = VpcgwV1API(client)

    id = module.params.pop("id", None)

    if id is not None:
        resource = api.get_pat_rule(pat_rule_id=id, region=module.params["region"])
    else:
        module.fail_json(msg="id is required")

    if module.check_mode:
        module.exit_json(changed=True)

    api.delete_pat_rule(pat_rule_id=resource.id, region=module.params["region"])

    module.exit_json(
        changed=True,
        msg=f"vpcgw's pat_rule {resource.id} deleted",
    )

def core(module: AnsibleModule) -> None:
    client = scaleway_get_client_from_module(module)

    state = module.params.pop("state")
    scaleway_pop_client_params(module)
    scaleway_pop_waitable_resource_params(module)

    if state == "present":
        create(module, client)
    elif state == "absent":
        delete(module, client)

def main() -> None:
    argument_spec = scaleway_argument_spec()
    argument_spec.update(scaleway_waitable_resource_argument_spec())
    argument_spec.update(
        state=dict(type="str", default="present", choices=["absent", "present"]),
        pat_rule_id=dict(type="str"),
        gateway_id=dict(
            type="str",
            required=True,
        ),
        public_port=dict(
            type="int",
            required=True,
        ),
        private_ip=dict(
            type="str",
            required=True,
        ),
        private_port=dict(
            type="int",
            required=True,
        ),
        protocol=dict(
            type="str",
            required=True,
            choices=["unknown", "both", "tcp", "udp"],
        ),
        zone=dict(
            type="str",
            required=False,
        ),
    )

    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
    )

    if not HAS_SCALEWAY_SDK:
        module.fail_json(msg=missing_required_lib("scaleway"))

    core(module)

if __name__ == "__main__":
    main()


# 2653. Sliding Subarray Beauty
from sortedcontainers import SortedList

class Solution:
  def getSubarrayBeauty(self, nums: List[int], k: int, x: int) -> List[int]:
    # maintain a window and use a SortedList for log(k) time operations
    n = len(nums)
    window, result = SortedList(), []
    for i in range(k):
      window.add(nums[i])

    for i in range(n - k):
      result.append(min(0, window[x - 1]))
      window.add(nums[i + k])
      window.remove(nums[i])
    result.append(min(0, window[x - 1]))

    return result


from itertools import count
from ntpath import join
from typing import Any
import pandas as pd
import numpy as np
from xlsxwriter.utility import xl_rowcol_to_cell
import logging
import re
import openpyxl
from pathlib import Path
#from flaskr.validator import Check_action

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
f_handler = logging.FileHandler('generator.log', 'a+', 'utf-8')
c_handler = logging.StreamHandler()
formatter = logging.Formatter(
    '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
f_handler.setFormatter(formatter)
c_handler.setFormatter(formatter)
logger.addHandler(f_handler)
logger.addHandler(c_handler)

class Report_Creation(): #Check_action

    file_name = ""
    output_message = ""
    error_list = {}
    file_data = {}

    work_N1 = ""
    work_N2 = ""
    work_descrizione_N1 = ""
    work_descrizione_N2 = ""
    work_nota_agenda = ""

    work_sheet = "" #sheet di lavoro di df_mapping
    work_codice_prestazione_siss = ""
    work_descrizione_prestazione_siss = ""
    work_codice_agenda_siss = ""
    work_casi_1_n = ""
    work_abilitazione_esposizione_siss = ""
    work_codici_disciplina_catalogo = ""
    work_descrizione_disciplina_catalogo = ""
    work_codice_QD = ""
    work_descrizione_QD = ""
    work_operatore_logico_QD = ""
    work_codice_metodica = ""
    work_descrizione_metodica = ""
    work_codice_distretto = ""
    work_descrizione_distretto = ""
    work_operatore_logico_distretto = ""
    work_priorita_U = ""
    work_priorita_primo_accesso_D = ""
    work_priorita_primo_accesso_P = ""
    work_priorita_primo_accesso_B = ""
    work_accesso_programmabile_ZP = ""

    #df_mapping = pd.DataFrame
    #xfile = openpyxl.Workbook

    #count_ROW = 1
    #count_COLUMN = "A"

    def __init__(self,df_mapping, file_data, work_sheet, work_N1, work_N2,
                  work_descrizione_N1, work_descrizione_N2, work_codice_prestazione_siss,
                  work_descrizione_prestazione_siss, work_codice_agenda_siss, work_casi_1_n,
                  work_abilitazione_esposizione_siss, work_prenotabile_siss, work_codici_disciplina_catalogo,
                  work_descrizione_disciplina_catalogo, work_codice_QD, work_codice_metodica,
                  work_codice_distretto, work_priorita_U, work_priorita_primo_accesso_D,
                  work_priorita_primo_accesso_P, work_priorita_primo_accesso_B, work_accesso_programmabile_ZP,
                  work_combinata, work_codice_agenda_interno, work_codice_prestazione_interno,
                  work_inviante, work_accesso_farmacia, work_accesso_CCR,
                  work_accesso_cittadino, work_accesso_MMG, work_accesso_amministrativo,
                  work_accesso_PAI, work_gg_preparazione, work_gg_refertazione,
                  work_nota_operatore, work_nota_agenda, work_nota_revoca, work_disciplina,
                  work_sesso, work_eta_min, work_eta_max, work_alert_column, work_delimiter, error_dict):#

        self.df_mapping = df_mapping
        self.file_data = file_data
        self.work_sheet = work_sheet
        self.work_N1 = work_N1
        self.work_N2 = work_N2
        self.work_descrizione_N1 = work_descrizione_N1
        self.work_descrizione_N2 = work_descrizione_N2
        self.work_codice_prestazione_siss = work_codice_prestazione_siss
        self.work_descrizione_prestazione_siss = work_descrizione_prestazione_siss
        self.work_codice_agenda_siss = work_codice_agenda_siss
        self.work_casi_1_n = work_casi_1_n
        self.work_abilitazione_esposizione_siss = work_abilitazione_esposizione_siss
        self.work_prenotabile_siss = work_prenotabile_siss
        self.work_codici_disciplina_catalogo = work_codici_disciplina_catalogo
        self.work_descrizione_disciplina_catalogo = work_descrizione_disciplina_catalogo
        self.work_codice_QD = work_codice_QD
        self.work_codice_metodica = work_codice_metodica
        self.work_codice_distretto = work_codice_distretto
        self.work_priorita_U = work_priorita_U
        self.work_priorita_primo_accesso_D = work_priorita_primo_accesso_D
        self.work_priorita_primo_accesso_P = work_priorita_primo_accesso_P
        self.work_priorita_primo_accesso_B = work_priorita_primo_accesso_B
        self.work_accesso_programmabile_ZP = work_accesso_programmabile_ZP
        self.work_combinata = work_combinata
        self.work_codice_agenda_interno = work_codice_agenda_interno
        self.work_codice_prestazione_interno = work_codice_prestazione_interno
        self.work_inviante = work_inviante
        self.work_accesso_farmacia = work_accesso_farmacia
        self.work_accesso_CCR = work_accesso_CCR
        self.work_accesso_cittadino = work_accesso_cittadino
        self.work_accesso_MMG = work_accesso_MMG
        self.work_accesso_amministrativo = work_accesso_amministrativo
        self.work_accesso_PAI = work_accesso_PAI
        self.work_gg_preparazione = work_gg_preparazione
        self.work_gg_refertazione = work_gg_refertazione
        self.work_nota_operatore = work_nota_operatore
        self.work_nota_agenda = work_nota_agenda
        self.work_nota_revoca = work_nota_revoca
        self.work_disciplina = work_disciplina
        self.work_sesso = work_sesso
        self.work_eta_min = work_eta_min
        self.work_eta_max = work_eta_max
        self.work_alert_column = work_alert_column
        self.work_delimiter = work_delimiter
        self.error_dict = error_dict

        self.count_ROW = 1
        self.count_COLUMN = "A"
        self.sheet_report = Any

        #numero_agende = 0
        #super().__init__(self)

    '''def __call__(self, df_mapping, file_data):
        self.get_report(self)
        self.df_mapping = df_mapping
        self.file_data = file_data'''

    def get_report(self):
        print("start Validation Report")

        try:
            #self.df_mapping = pd.read_excel(self.file_data, sheet_name=self.work_sheet, converters={self.work_codici_disciplina_catalogo: str, self.work_codice_prestazione_siss: str, self.work_codice_metodica: str, self.work_codice_distretto: str}).replace(np.nan, '', regex=True)
            print("0:"+ str(self.file_data))
            xfile = openpyxl.load_workbook(self.file_data) #recupero file excel da file system
            print("1")
            #sheet_mapping = xfile.get_sheet_by_name(self.work_sheet) #recupero sheet excel mapping
            try:
                self.sheet_report = xfile.get_sheet_by_name('Report Validazione') #recupero sheet excel report validazione
            except:
                #creo Report Validazione se non esiste
                print("1.1: Non esiste sheet Validazione - creazione sheet")
                self.sheet_report = xfile.create_sheet('Report Validazione')
                print("1.2")
            print("2")
            #sheet_report["A1"] = "Report Validazione1" #A1

            #self.sheet_report[str(self.count_COLUMN)+str(self.count_ROW)] = "Report Validazione" #A1
            print("3.1")
            #print("3.2: "  + str(self.count_COLUMN)+str(self.count_ROW))
            #self.count_ROW+=1
            self.write_row(self.count_COLUMN, "Report Validazione")

            print("4")
        except:
            print("non esiste file o sheet")

        self.get_N1_N2()

        self.get_Num_Prestazioni()

        numero_agende = self.get_Num_Agende()

        self.get_Num_PA_Esposte()

        self.get_Num_PA_Prenotabili()

        self.get_Combinate()

        self.get_Raggruppate()

        self.get_Nota_Amministrativa()

        self.get_Nota_Revoca()

        self.get_Discipline()

        self.get_Agende_con_QD(numero_agende)

        self.get_Campi_Descrittivi() #Sesso, GG di prep, GG di ref, Età min ed Età max

        self.get_Riassunto_Errori()

        xfile.save(self.file_data)

        '''
        #for index, row in df_mapping.iterrows():

        print("start definizione output agenda QD")
        out1 = ""
        out_message = ""
        for ind in error_dict['error_QD_agenda']:
            out1 = out1 + "at index: , \n"
            out_message = "__> QD: diversi per le prestazioni della stessa agenda"
            if sheet_report[self.work_alert_column+ind].value is not None:
                sheet_report[self.work_alert_column+ind] = str(sheet_report[self.work_alert_column+ind].value) + "; \n" + out_message #modificare colonna alert
            else:
                sheet_report[self.work_alert_column+ind] = out_message

        self.output_message = self.output_message + "\nerror_QD_agenda: \n" + out1
        print("finish print Validation Report")
        xfile.save(self.file_data)
        return error_dict'''

    def get_N1_N2(self):
        print("get N1 and N2")

        CODICE_N1 = self.work_N1
        CODICE_N2 = self.work_N2
        DESCRIZIONE_N1 = self.work_descrizione_N1
        DESCRIZIONE_N2 = self.work_descrizione_N2

        cod_N1 = []
        cod_N2 = []
        desc_N1 = []
        desc_N2 = []

        try:
            for index, row in self.df_mapping.iterrows():
                if str(row[CODICE_N1]) not in cod_N1:
                    cod_N1.append(str(row[CODICE_N1]))
                if str(row[CODICE_N2]) not in cod_N2:
                    cod_N2.append(str(row[CODICE_N2]))
                if str(row[DESCRIZIONE_N1]) not in desc_N1:
                    desc_N1.append(str(row[DESCRIZIONE_N1]))
                if str(row[DESCRIZIONE_N2]) not in desc_N2:
                    desc_N2.append(str(row[DESCRIZIONE_N2]))
        except Exception as e:
            logger.error('Failed to get N1 and N2: '+ str(e))
            if cod_N1 == []:
                cod_N1.append("valore assente")
            if cod_N2 == []:
                cod_N2.append("valore assente")
            if desc_N1 == []:
                desc_N1.append("valore assente")
            if desc_N2 == []:
                desc_N2.append("valore assente")

        self.write_row(self.count_COLUMN, "N1: " + ", ".join(cod_N1), 1) #lascio uno spazio dalla riga precedente
        self.write_row(self.count_COLUMN, "Descrizione N1: " + ", ".join(desc_N1))
        self.write_row(self.count_COLUMN, "N2: " + ", ".join(cod_N2))
        self.write_row(self.count_COLUMN, "Descrizione N2: " + ", ".join(desc_N2))
        #self.sheet_report[str(self.count_COLUMN)+str(self.count_ROW)] = "N1: " + ", ".join(N1)

    def get_Num_Prestazioni(self):
        print("get Numero coppie prestazioni/agende")

        contatore = 0

        for index, row in self.df_mapping.iterrows():
            contatore += 1

        self.write_row(self.count_COLUMN, "Numero di coppie prestazione/agenda: " + str(contatore), 1)

    def get_Num_Agende(self):
        print("get Numero agende")

        agende_list = []
        contatore = 0

        for index, row in self.df_mapping.iterrows():
            if row[self.work_codice_agenda_siss] not in agende_list:
                contatore += 1
                agende_list.append(row[self.work_codice_agenda_siss])

        self.write_row(self.count_COLUMN, "Numero di agende nell'offerta sanitaria: " + str(contatore), 1)
        return contatore

    def get_Num_PA_Esposte(self):
        print("get Numero coppie PA esposte")

        contatore = 0
        contatore2 = 0
        col_abilitazione = self.work_abilitazione_esposizione_siss

        for index, row in self.df_mapping.iterrows():
            contatore2 += 1
            if row[col_abilitazione] == "S":
                contatore += 1

        self.write_row(self.count_COLUMN, "Numero di coppie prestazione/agenda abilitate all'esposizione: " + str(contatore) + " su " + str(contatore2), 1)

    def get_Num_PA_Prenotabili(self):
        print("get Numero coppie PA esposte e prenotabili")

        contatore = 0
        contatore2 = 0
        col_abilitazione = self.work_abilitazione_esposizione_siss
        col_prenotabile = self.work_prenotabile_siss

        for index, row in self.df_mapping.iterrows():
            contatore2 += 1
            if row[col_abilitazione] == "S" and row[col_prenotabile] == "S":
                contatore += 1

        self.write_row(self.count_COLUMN, "Numero di coppie prestazione/agenda abilitate all'esposizione e prenotabili: " + str(contatore) + " su " + str(contatore2), 0)

    def get_Combinate(self):
        print("get Numero coppie PA combinate")

        contatore = 0

        for index, row in self.df_mapping.iterrows():
            if row[self.work_combinata] != "" and row[self.work_combinata] != "N" and row[self.work_abilitazione_esposizione_siss] =="S":
                contatore += 1

        self.write_row(self.count_COLUMN, "Numero di coppie prestazione/agenda in combinata: " + str(contatore), 1)

    def get_Raggruppate(self):
        print("get Numero coppie PA raggruppate")
    '''
        contatore = 0

        for index, row in self.df_mapping.iterrows():
            if row[self.work_ragg] != "":
                contatore += 1

        self.write_row(self.count_COLUMN, "Numero di coppie prestazione/agenda in combinata: " + str(contatore), 1)
    '''

    def get_Nota_Amministrativa(self):
        print("get Nota Amministrativa")
        #occorrenze_nota = 0
        contatore = {}
        note_agenda_list = []

        for index, row in self.df_mapping.iterrows():
            if row[self.work_nota_agenda] not in note_agenda_list:
                contatore[row[self.work_nota_agenda]] = 1
                note_agenda_list.append(row[self.work_nota_agenda])
            else:
                occorrenze_nota = contatore.get(row[self.work_nota_agenda])
                contatore[row[self.work_nota_agenda]] = occorrenze_nota + 1

        self.write_row(self.count_COLUMN, str(len(contatore)) + " Note amministrative configurate: ", 1)

        for note, cont in contatore.items():
            #if contatore == 1:
            self.write_row("B", " per " + str(cont) + " coppie prestazione/agenda è presente la nota: " + str(note), 0)
            #else:
            #    self.write_row("B", str(note), 0)
            #    contatore -= 1

    def get_Nota_Revoca(self):
        print("get Nota Revoca")

        contatore = 0
        note_revoca_list = []

        for index, row in self.df_mapping.iterrows():
            if row[self.work_nota_revoca] not in note_revoca_list:
                contatore += 1
                note_revoca_list.append(row[self.work_nota_revoca])

        self.write_row(self.count_COLUMN, str(contatore) + " Note revoca configurate: ", 1)

        for note in note_revoca_list:
            #if contatore == 1:
            self.write_row("B", str(note), 0)

    def get_Discipline(self):
        print("get Discipline")

        discipline_list = []

        for index, row in self.df_mapping.iterrows():
            if str(row[self.work_disciplina]) not in discipline_list:
                discipline_list.append(str(row[self.work_disciplina]))

        self.write_row(self.count_COLUMN, "Discipline dell'offerta sanitaria: " + ", ".join(discipline_list), 1)

    def get_Agende_con_QD(self, num_agende):
        print("get agende con QD")

        list_agende = []
        contatore = 0 #conta le agende con QD

        for index, row in self.df_mapping.iterrows():
            if row[self.work_abilitazione_esposizione_siss]=="S":
                if str(row[self.work_codice_QD]) != "" and str(row[self.work_codice_agenda_siss]) not in list_agende:
                    contatore += 1
                    list_agende.append(str(row[self.work_codice_agenda_siss]))

        contatore_agende_no_QD = num_agende - contatore

        string_OUT = "Sono presenti " + str(contatore) + " AGENDE con QD configurati e " + str(contatore_agende_no_QD) + " AGENDE sprovviste di QD"
        self.write_row(self.count_COLUMN, string_OUT, 1)

    def get_Campi_Descrittivi(self): #Sesso, GG di prep, GG di ref, Età min ed Età max
        print("get Sesso, GG di prep, GG di ref, Età min ed Età max")

        sesso_list = []
        gg_prep_list = []
        gg_ref_list = []
        eta_min_list = []
        eta_max_list = []
        eta_min_max_list = []

        for index, row in self.df_mapping.iterrows():
            if str(row[self.work_sesso]) not in sesso_list:
                sesso_list.append(str(row[self.work_sesso]))
            if str(row[self.work_gg_preparazione]) not in gg_prep_list:
                gg_prep_list.append(str(row[self.work_gg_preparazione]))
            if str(row[self.work_gg_refertazione]) not in gg_ref_list:
                gg_ref_list.append(str(row[self.work_gg_refertazione]))

            eta_min_max = str(row[self.work_eta_min]) + " <->" + str(row[self.work_eta_max])
            if eta_min_max not in eta_min_max_list:
                eta_min_max_list.append(str(eta_min_max))

        self.write_row(self.count_COLUMN, "Sesso nell'offerta sanitaria: " + ", ".join(sesso_list), 1)
        self.write_row(self.count_COLUMN, "Giorni di preparazione definiti nell'offerta sanitaria: " + ", ".join(gg_prep_list))
        self.write_row(self.count_COLUMN, "Giorni di refertazione definiti nell'offerta sanitaria: " + ", ".join(gg_ref_list))
        self.write_row(self.count_COLUMN, "Range di Età minime e massime definite nell'offerta sanitaria: " + ", ".join(eta_min_max_list))
        #self.write_row(self.count_COLUMN, "Età massime definite nell'offerta sanitaria: " + ", ".join(eta_max_list))

    def get_Riassunto_Errori(self):
        print("get Riassunto errori rilevati")

        #self.write_row(self.count_COLUMN, "Errori trovati: " + ", ".join(self.error_dict), 1)
        self.write_row(self.count_COLUMN, "Errori trovati: ", 1)
        for key, value in self.error_dict.items():
            print(key, ' : ', value)
            self.write_row(self.count_COLUMN, key + ": ", 0)
            for k, v in value.items():
                self.write_row(self.count_COLUMN, k + ' : ' + ", ".join(v), 0)

    def write_row(self, column, message, row=0):
        self.count_ROW += row #lascio uno spazio dalla riga prima
        self.sheet_report[str(column)+str(self.count_ROW)] = message
        self.count_ROW += 1 #vado a riga successiva per messaggio dopo


"""
Implemention of a ListEditor demo plugin for Traits UI demo program

This demo shows each of the four styles of ListEditor.
"""

from traits.api import HasTraits, List, Str
from traitsui.api import Item, Group, View

#-------------------------------------------------------------------------------
#  Demo Class
#-------------------------------------------------------------------------------

class ListEditorDemo ( HasTraits ):
    """ This class specifies the details of the BooleanEditor demo.
    """

    # The Trait to be displayed in the editor
    play_list = List( Str, ["The Merchant of Venice", "Hamlet", "MacBeth"])

    # Items are used to define display; one per editor style.
    list_group = Group( Item('play_list', style='simple', label='Simple'),
                        Item('_'),
                        Item('play_list', style='custom', label='Custom'),
                        Item('_'),
                        Item('play_list', style='text', label='Text'),
                        Item('_'),
                        Item('play_list',
                              style='readonly',
                              label='ReadOnly'))

    # Demo view
    view1 = View( list_group,
                  title = 'ListEditor',
                  buttons = ['OK'],
                  height=400,
                  width=400 )

# Create the demo:
popup = ListEditorDemo()

# Run the demo (if invoked from the command line):
if __name__ == '__main__':
    popup.configure_traits()


import speech_recognition as sr
import pyttsx3
import pywhatkit
import datetime
import wikipedia
import pyjokes

def talk(text):
    engine.say(text)
    engine.runAndWait()

listener = sr.Recognizer()
engine=pyttsx3.init()
voices=engine.getProperty('voices')    #this and the next statements are changing male voice to female voice
engine.setProperty('voice',voices[1].id)
engine.say('I am your alexa')
engine.say('what can i do for you')
engine.runAndWait()
def take_command():
    try:
        with sr.Microphone() as source:
            print('listening...')
            voice = listener.listen(source)
            command = listener.recognize_google(voice)
            command=command.lower()
            if 'alexa' in command:
                command=command.replace('alexa','')  # in this line we are removing word alexa from the string
                print(command)
    except:
        pass
    return command

def run_alexa():
    command = take_command()
    print(command)
    if 'play' in command:
        song = command.replace('play', '')
        talk('playing' + song)
        # talk('playing' + song)
        print('playing...')
        pywhatkit.playonyt(song)
    elif 'time' in command:
        time=datetime.datetime.now().strftime('%I:%M %p')  #it is converting 24 hour clock
        print(time)
        talk('current time is' + time)
    elif 'who is' in command:
        person=command.replace('who is','')
        information=wikipedia.summary(person,4)   #this 4 is telling us the number of lines we want alexa to read
        print(information)
        talk(information)
    elif 'language' in command:
        talk('I speak English language')
    elif 'where do you live' in command:
        talk('I live inside your machine')
    elif 'sleep' in command:
        talk('I hope you had a good day! good night. sweet dreams. see you tommorow')
    elif 'joke' in command:
        print(pyjokes.get_joke())
        talk(pyjokes.get_joke())
    elif 'date' in command:
        talk('yes! but you will have to come inside your machine to meet me! haha')
    else:
        talk('Sorry! Can you please repeat?')

while True:
    run_alexa()


import text_gen
from datetime import datetime, timedelta
from collections import OrderedDict

def groupEventsByDay(events):
    eventMap = OrderedDict()
    for event in events:
        eventDate = event.startDate.date()
        if eventDate in eventMap:
            eventMap[eventDate].append(event)
        else:
            eventMap[eventDate] = [event]
    return eventMap

def summerizeEvents(provider, startDate, endDate):
    events = groupEventsByDay(provider.retrieveEventsByDate(startDate,
                                                            endDate))

    if events is None or len(events) == 0:
        return 'You have no events scheduled at the given time'

    return text_gen.eventsAsSpoken(events)


import argparse
import patch_clamp.serialize_spike_times as s

parser = argparse.ArgumentParser(description="add peak times to the database")
parser.add_argument("-query", help="Insert query for database")
parser.add_argument("-sweeps", help="Max sweeps", type=int)
parser.add_argument("-db", help="Database path")
parser.add_argument("-include", help="`yes` or `maybe` for database include")
parser.add_argument(
    "-dry_run",
    help="if present, write to STDOUT, else, write to the database",
    action="store_true",
)

if __name__ == "__main__":

    args = parser.parse_args()
    SWEEP_MAX = args.sweeps
    QUERY = args.query
    DB_PATH = args.db
    INCLUDE = args.include

    for sweep in range(SWEEP_MAX):
        print(f"[INFO] Working on sweep {sweep}...")
        sweepdata = s.get_groups_per_sweep(sweep, INCLUDE, QUERY, DB_PATH)
        all_d = map(s.get_x, sweepdata)
        for f in all_d:
            serialized = s.serialize(f)
            for item in serialized:
                item = s.add_current(item)
                if args.dry_run:
                    print(item)
                if not args.dry_run:
                    s.to_db(item, DB_PATH, s.PEAK_INS_QUERY)