import math
import sys
from unittest import TestCase

from rubicon.java import JavaClass, JavaInterface

class JNITest(TestCase):

    def test_simple_object(self):

        Stack = JavaClass('java/util/Stack')

        stack = Stack()

        stack.push("Hello")
        stack.push("World")

        # The stack methods are protyped to return java/lang/Object,
        # so we need to call toString() to get the actual content...
        self.assertEqual(stack.pop().toString(), "World")
        self.assertEqual(stack.pop().toString(), "Hello")

        # with self.assertRaises(Exception):
        #     stack.pop()

    def test_subclass_impossible(self):
        def make_subclass():
            Stack = JavaClass('java/util/Stack')

            class ImpossibleStackSubclass(Stack):
                pass

        self.assertRaises(NotImplementedError, make_subclass)

    def test_field(self):
        "A field on an instance can be accessed and mutated"
        Example = JavaClass('org/beeware/rubicon/test/Example')

        obj = Example()

        self.assertEqual(obj.base_int_field, 22)
        self.assertEqual(obj.int_field, 33)

        obj.base_int_field = 8888
        obj.int_field = 9999

        self.assertEqual(obj.base_int_field, 8888)
        self.assertEqual(obj.int_field, 9999)

    def test_method(self):
        "An instance method can be invoked."
        Example = JavaClass('org/beeware/rubicon/test/Example')

        obj = Example()
        self.assertEqual(obj.get_base_int_field(), 22)
        self.assertEqual(obj.get_int_field(), 33)

        obj.set_base_int_field(8888)
        obj.set_int_field(9999)

        self.assertEqual(obj.get_base_int_field(), 8888)
        self.assertEqual(obj.get_int_field(), 9999)

    def test_static_field(self):
        "A static field on a class can be accessed and mutated"
        with ExampleClassWithCleanup() as Example:
            Example.set_static_base_int_field(1)
            Example.set_static_int_field(11)

            self.assertEqual(Example.static_base_int_field, 1)
            self.assertEqual(Example.static_int_field, 11)

            Example.static_base_int_field = 1188
            Example.static_int_field = 1199

            self.assertEqual(Example.static_base_int_field, 1188)
            self.assertEqual(Example.static_int_field, 1199)

    def test_static_method(self):
        "A static method on a class can be invoked."
        with ExampleClassWithCleanup() as Example:
            self.assertEqual(Example.get_static_base_int_field(), 1137)
            self.assertEqual(Example.get_static_int_field(), 1142)

            Example.set_static_base_int_field(2288)
            Example.set_static_int_field(2299)

            self.assertEqual(Example.get_static_base_int_field(), 2288)
            self.assertEqual(Example.get_static_int_field(), 2299)

    def test_non_existent_field(self):
        "An attribute error is raised if you invoke a non-existent field."
        Example = JavaClass('org/beeware/rubicon/test/Example')

        obj1 = Example()

        # Non-existent fields raise an error.
        with self.assertRaises(AttributeError):
            obj1.field_doesnt_exist

        # Cache warming doesn't affect anything.
        with self.assertRaises(AttributeError):
            obj1.field_doesnt_exist

    def test_non_existent_method(self):
        "An attribute error is raised if you invoke a non-existent method."
        Example = JavaClass('org/beeware/rubicon/test/Example')

        obj1 = Example()

        # Non-existent methods raise an error.
        with self.assertRaises(AttributeError):
            obj1.method_doesnt_exist()

        # Cache warming doesn't affect anything.
        with self.assertRaises(AttributeError):
            obj1.method_doesnt_exist()

    def test_non_existent_static_field(self):
        "An attribute error is raised if you invoke a non-existent static field."
        Example = JavaClass('org/beeware/rubicon/test/Example')

        # Non-existent fields raise an error.
        with self.assertRaises(AttributeError):
            Example.static_field_doesnt_exist

        # Cache warming doesn't affect anything.
        with self.assertRaises(AttributeError):
            Example.static_field_doesnt_exist

    def test_non_existent_static_method(self):
        "An attribute error is raised if you invoke a non-existent static method."
        Example = JavaClass('org/beeware/rubicon/test/Example')

        # Non-existent methods raise an error.
        with self.assertRaises(AttributeError):
            Example.static_method_doesnt_exist()

        # Cache warming doesn't affect anything.
        with self.assertRaises(AttributeError):
            Example.static_method_doesnt_exist()

    def test_protected_field(self):
        "An attribute error is raised if you invoke a non-public field."
        Example = JavaClass('org/beeware/rubicon/test/Example')

        obj1 = Example()

        # Non-public fields raise an error.
        with self.assertRaises(AttributeError):
            obj1.invisible_field

        # Cache warming doesn't affect anything.
        with self.assertRaises(AttributeError):
            obj1.invisible_field

    def test_protected_method(self):
        "An attribute error is raised if you invoke a non-public method."
        Example = JavaClass('org/beeware/rubicon/test/Example')

        obj1 = Example()

        # Non-public methods raise an error.
        with self.assertRaises(AttributeError):
            obj1.invisible_method()

        # Cache warming doesn't affect anything.
        with self.assertRaises(AttributeError):
            obj1.invisible_method()

    def test_protected_static_field(self):
        "An attribute error is raised if you invoke a non-public static field."
        Example = JavaClass('org/beeware/rubicon/test/Example')

        # Non-public fields raise an error.
        with self.assertRaises(AttributeError):
            Example.static_invisible_field

        # Cache warming doesn't affect anything.
        with self.assertRaises(AttributeError):
            Example.static_invisible_field

    def test_protected_static_method(self):
        "An attribute error is raised if you invoke a non-public static method."
        Example = JavaClass('org/beeware/rubicon/test/Example')

        # Non-public methods raise an error.
        with self.assertRaises(AttributeError):
            Example.static_invisible_method()

        # Cache warming doesn't affect anything.
        with self.assertRaises(AttributeError):
            Example.static_invisible_method()

    def test_polymorphic_constructor(self):
        "Check that the right constructor is activated based on arguments used"
        Example = JavaClass('org/beeware/rubicon/test/Example')

        obj1 = Example()
        obj2 = Example(2242)
        obj3 = Example(3342, 3337)

        self.assertEqual(obj1.base_int_field, 22)
        self.assertEqual(obj1.int_field, 33)

        self.assertEqual(obj2.base_int_field, 44)
        self.assertEqual(obj2.int_field, 2242)

        self.assertEqual(obj3.base_int_field, 3342)
        self.assertEqual(obj3.int_field, 3337)

        # Protected constructors can't be invoked
        with self.assertRaises(ValueError):
            Example("Hello")

    def test_polymorphic_method(self):
        "Check that the right method is activated based on arguments used"
        Example = JavaClass('org/beeware/rubicon/test/Example')

        obj1 = Example()

        self.assertEqual(obj1.doubler(42), 84)
        self.assertEqual(obj1.doubler("wibble"), "wibblewibble")

        # If arguments don't match available options, an error is raised
        with self.assertRaises(ValueError):
            obj1.doubler(1.234)

    def test_polymorphic_static_method(self):
        "Check that the right static method is activated based on arguments used"
        Example = JavaClass('org/beeware/rubicon/test/Example')

        self.assertEqual(Example.tripler(42), 126)
        self.assertEqual(Example.tripler("wibble"), "wibblewibblewibble")

        # If arguments don't match available options, an error is raised
        with self.assertRaises(ValueError):
            Example.tripler(1.234)

    def test_pass_int_array(self):
        """A list of Python ints can be passed as a Java int array."""
        Example = JavaClass("org/beeware/rubicon/test/Example")
        self.assertEqual(3, Example.sum_all_ints([1, 2]))

    def test_heterogenous_list(self):
        """A list of mixed types raise an exception when trying to find the right Java method."""
        Example = JavaClass("org/beeware/rubicon/test/Example")
        with self.assertRaises(ValueError):
            Example.sum_all_ints(["two", 3])
        with self.assertRaises(ValueError):
            Example.sum_all_ints([1, "two"])
        with self.assertRaises(ValueError):
            Example.sum_all_floats([1.0, "two"])
        with self.assertRaises(ValueError):
            Example.sum_all_doubles([1.0, "two"])

    def test_list_that_cannot_be_turned_into_java_primitive_array(self):
        """A list that can't turn into a Java primitive array raises an exception when trying to find the right
        Java method."""
        Example = JavaClass("org/beeware/rubicon/test/Example")
        with self.assertRaises(ValueError):
            Example.sum_all_ints([object()])

    def test_empty_list(self):
        """An empty list results in an inability to find the right Java method."""
        Example = JavaClass("org/beeware/rubicon/test/Example")
        with self.assertRaises(ValueError):
            Example.sum_all_ints([])

    def test_pass_double_array(self):
        """A list of Python floats can be passed as a Java double array."""
        Example = JavaClass("org/beeware/rubicon/test/Example")
        self.assertEqual(3, Example.sum_all_doubles([1.0, 2.0]))

    def test_pass_float_array(self):
        """A list of Python floats can be passed as a Java float array."""
        Example = JavaClass("org/beeware/rubicon/test/Example")
        self.assertEqual(3, Example.sum_all_floats([1.0, 2.0]))

    def test_pass_boolean_array(self):
        """A list of Python bools can be passed as a Java boolean array."""
        Example = JavaClass("org/beeware/rubicon/test/Example")
        self.assertEqual(False, Example.combine_booleans_by_and([True, False]))
        self.assertEqual(True, Example.combine_booleans_by_and([True, True]))

    def test_pass_byte_array(self):
        """A Python bytes object can be passed as a Java byte array."""
        Example = JavaClass("org/beeware/rubicon/test/Example")
        self.assertEqual(ord(b'x'), Example.xor_all_bytes(b'x\x00'))
        self.assertEqual(0, Example.xor_all_bytes(b'xx'))

    def test_static_access_non_static(self):
        "An instance field/method cannot be accessed from the static context"
        Example = JavaClass('org/beeware/rubicon/test/Example')

        obj = Example()

        with self.assertRaises(AttributeError):
            obj.static_int_field

        with self.assertRaises(AttributeError):
            obj.get_static_int_field()

    def test_non_static_access_static(self):
        "A static field/method cannot be accessed from an instance context"
        Example = JavaClass('org/beeware/rubicon/test/Example')

        with self.assertRaises(AttributeError):
            Example.int_field

        with self.assertRaises(AttributeError):
            Example.get_int_field()

    def test_string_argument(self):
        "A method with a string argument can be passed."
        Example = JavaClass('org/beeware/rubicon/test/Example')
        example = Example()
        self.assertEqual(example.duplicate_string("Wagga"), "WaggaWagga")

    def test_string_return(self):
        "If a method or field returns a string, you get a Python string back"
        Example = JavaClass('org/beeware/rubicon/test/Example')
        example = Example()
        self.assertEqual(example.toString(), "This is a Java Example object")

    def test_float_method(self):
        "A method with a float arguments can be handled."
        Example = JavaClass('org/beeware/rubicon/test/Example')
        example = Example()
        self.assertEqual(example.area_of_square(1.5), 2.25)

    def test_double_method(self):
        "A method with a double arguments can be handled."
        Example = JavaClass('org/beeware/rubicon/test/Example')
        example = Example()
        self.assertEqual(example.area_of_circle(1.5), 1.5 * math.pi)

    def test_enum_method(self):
        "A method with enum arguments can be handled."
        Example = JavaClass('org/beeware/rubicon/test/Example')
        example = Example()

        Stuff = JavaClass('org/beeware/rubicon/test/Example$Stuff')

        self.assertEqual(example.label(Stuff.FOO), "Foo")
        self.assertEqual(example.label(Stuff.BAR), "Bar")
        self.assertEqual(example.label(Stuff.WHIZ), "Whiz")

    def test_object_return(self):
        "If a method or field returns an object, you get an instance of that type returned"
        Example = JavaClass('org/beeware/rubicon/test/Example')
        example = Example()

        Thing = JavaClass('org/beeware/rubicon/test/Thing')
        thing = Thing('This is thing', 2)

        example.set_thing(thing)

        the_thing = example.get_thing()
        self.assertEqual(the_thing.toString(), "This is thing 2")

    def test_interface(self):
        "An Java interface can be defined in Python and proxied."
        ICallback = JavaInterface('org/beeware/rubicon/test/ICallback')

        results = {}

        class MyInterface(ICallback):
            def __init__(self, value):
                super(MyInterface, self).__init__()
                self.value = value

            def poke(self, example, value):
                results['string'] = example.toString()
                results['int'] = value + self.value

            def peek(self, example, value):
                results['string'] = example.toString()
                results['int'] = value + self.value

        # Create two handler instances so we can check the right one
        # is being invoked.
        handler1 = MyInterface(5)  # NOQA; F841
        handler2 = MyInterface(10)

        # Create an Example object, and register a handler with it.
        Example = JavaClass('org/beeware/rubicon/test/Example')
        example = Example()
        example.set_callback(handler2)

        # Invoke the callback; check that the results have been peeked as expected
        example.test_peek(42)

        self.assertEqual(results['string'], 'This is a Java Example object')
        self.assertEqual(results['int'], 52)

        example.test_poke(37)

        self.assertEqual(results['string'], 'This is a Java Example object')
        self.assertEqual(results['int'], 47)

    def test_interface_int_return(self):
        """A Java interface with an int-returning method can be defined in Python and proxied,
        including return value."""
        # To ensure Java can call into our Python proxy object and get an `int` out, we
        # ask AddOne to call a Python class which implements a Java interface with a
        # method to return an `int`.
        #
        # For consistency with previous tests, and to verify that parameter passing works
        # with int-returning interfaces, we rely on an `Example` object to store state.
        ICallbackInt = JavaInterface('org/beeware/rubicon/test/ICallbackInt')

        class GetAndIncrementExampleIntField(ICallbackInt):
            def getInt(self, example):
                example.set_int_field(example.int_field + 1)
                return example.int_field

        implementation = GetAndIncrementExampleIntField()

        # Create two `Example` objects to validate there are no weird surprises about where state goes.
        Example = JavaClass('org/beeware/rubicon/test/Example')
        example1 = Example()
        example2 = Example()

        # Validate that `AddOne` calls our Python `getInt()` implementation. The first number is 35
        # because AddOne adds 1, and getInt() adds 1, and it starts at 33.
        AddOne = JavaClass('org/beeware/rubicon/test/AddOne')
        self.assertEqual(35, AddOne().addOne(implementation, example1))
        self.assertEqual(36, AddOne().addOne(implementation, example1))
        # Validate that implementation mutates example1's state, not example2's state.
        self.assertEqual(35, AddOne().addOne(implementation, example2))

    def test_interface_bool_return(self):
        """A Java interface with a bool-returning method can be defined in Python and proxied,
        including return value."""
        ICallbackBool = JavaInterface('org/beeware/rubicon/test/ICallbackBool')

        class MakeBool(ICallbackBool):
            def __init__(self, s):
                super().__init__()
                self.s = s

            def getBool(self):
                if self.s == "yes":
                    return True
                return False

        true_maker = MakeBool("yes")
        false_maker = MakeBool("no")

        # Validate that a Java class can use our Python class when expecting the bool-returning interface.
        TruthInverter = JavaClass("org/beeware/rubicon/test/TruthInverter")
        self.assertFalse(TruthInverter().invert(true_maker))
        self.assertTrue(TruthInverter().invert(false_maker))

    def test_alternatives(self):
        "A class is aware of it's type hierarchy"
        Example = JavaClass('org/beeware/rubicon/test/Example')

        self.assertEqual(
            Example.__dict__['_alternates'],
            [
                b"Lorg/beeware/rubicon/test/Example;",
                b"Lorg/beeware/rubicon/test/BaseExample;",
                b"Ljava/lang/Object;",
            ])

        AbstractCallback = JavaClass('org/beeware/rubicon/test/AbstractCallback')
        self.assertEqual(
            AbstractCallback.__dict__['_alternates'],
            [
                b"Lorg/beeware/rubicon/test/AbstractCallback;",
                b"Lorg/beeware/rubicon/test/ICallback;",
                b"Ljava/lang/Object;",
            ])

        String = JavaClass('java/lang/String')

        self.assertEqual(
            String.__dict__['_alternates'],
            [
                b"Ljava/lang/String;",
                b"Ljava/io/Serializable;",
                b"Ljava/lang/Comparable;",
                b"Ljava/lang/CharSequence;",
                b"Ljava/lang/Object;",
            ])

    def test_inner(self):
        "Inner classes can be accessed"

        Inner = JavaClass('org/beeware/rubicon/test/Example$Inner')

        self.assertEqual(Inner.INNER_CONSTANT, 1234)

    def test_dunder_main(self):
        "When launched from `rubicon-java`, sys.modules should have a `__main__` module."
        self.assertEqual('module', sys.modules['__main__'].__class__.__name__)

class ExampleClassWithCleanup(object):
    '''Returns the `Example` JavaClass, wrapped in a context manager
    to save/restore two class fields.

    Use this instead of `JavaClass('org/beeware/rubicon/test/Example')` when
    you want to mutate the static fields from tests.
    '''

    def __enter__(self):
        Example = JavaClass('org/beeware/rubicon/test/Example')
        self._initial_base = Example.get_static_base_int_field()
        self._initial = Example.get_static_int_field()
        self._klass = Example
        return Example

    def __exit__(self, *args):
        self._klass.set_static_base_int_field(self._initial_base)
        self._klass.set_static_int_field(self._initial)


# coding: utf-8
"""
Raven cli client for harakiri monitoring.
Based on raven test client code.

Original copyrights:
    :copyright: (c) 2012 by the Sentry Team, see AUTHORS for more details.
    :license: BSD, see LICENSE for more details.
"""
from __future__ import print_function
import subprocess
import fileinput
import logging
import re
import sys
from optparse import OptionParser
from raven import get_version, os, Client
from raven.utils import json
from six import StringIO
from raven.utils.stacks import get_lines_from_file

def store_json(option, opt_str, value, parser):
    try:
        value = json.loads(value)
    except ValueError:
        print("Invalid JSON was used for option %s.  Received: %s" % (opt_str, value))
        sys.exit(1)
    setattr(parser.values, option.dest, value)

def convert_traceback(uwsgi_traceback, thread_regex=None):
    """ Convert uwsgi traceback string with following pattern to raven protocol traceback
            thread_id = %s
            filename = %s
            lineno = %s
            function = %s
            line = %s

        More info: http://sentry.readthedocs.org/en/latest/developer/client/#building-the-json-packet
                   http://uwsgi-docs.readthedocs.org/en/latest/Tracebacker.html

        thread_id = MainThread
        filename = /home/belonika/.pythonz/pythons/CPython-2.6.8/lib/python2.6/socket.py
        lineno = 554
        function = create_connection
        line = sock.connect(sa)
    """
    variables = ('thread_id', 'filename', 'lineno', 'function', 'line')
    regexp = r' '.join(('%s = (?P<%s>.+?)' % (var, var) for var in variables))
    traceback = []
    for line in uwsgi_traceback.split('\n'):
        match = re.match(r'^%s$' % regexp, line)
        values = match.groupdict() if match else None
        if values:
            if thread_regex and\
                    not re.match(thread_regex, values['thread_id']):
                continue
            frame_result = {
                'abs_path': values['filename'],
                'context_line': values['line'],
                'filename': (values['filename']),
                'function': values['function'],
                'lineno': int(values['lineno']),

                'module': None,
                'post_context': [],
                'pre_context': [],
                'vars': {}
            }
            pre_context, context_line, post_context = get_lines_from_file(frame_result['abs_path'],
                                                                          frame_result['lineno'] - 1, 5)
            if context_line is not None:
                frame_result.update({
                    'pre_context': pre_context,
                    'context_line': context_line,
                    'post_context': post_context,
                })

            traceback.append(frame_result)

    return traceback

def extract_http(log):
    for line in log.split('\n'):
        match = re.match(
            r'^[^-]+- HARAKIRI \[core (?P<core>.+)\] (?P<remote_addr>.+) - '
            r'(?P<method>.+) (?P<url>.+) since (?P<begin_time>.+)$', line)
        if match:
            break
    if match:
        values = match.groupdict()
        return values['method'], values['url'], values['remote_addr']
    else:
        return None

def send_message(client, options, log):
    if not client.is_enabled():
        print('Error: Client reports as being disabled!')
        sys.exit(1)

    http_info = extract_http(log)

    data = {
        'logger': 'uwsgi.harakiri',
        'stacktrace': {
            'frames': convert_traceback(log, options.get('thread_regex'))
        },
    }

    if http_info:
        method, url, remote_addr = http_info
        data['request'] = {
            'method': method,
            'url': url,
            'env': {
                'REMOTE_ADDR': remote_addr
            }
        }

    ident = client.get_ident(client.captureMessage(
        message='uWSGI harakiri',
        data=data,
        level=logging.ERROR,
        stack=True,
        tags=options.get('tags', {}),
    ))

    if client.state.did_fail():
        return False

    return ident

def group_log(client, options, to_follow, proc=None):
    in_harakiri = False
    harakiri_lines = []
    harakiris_seen = 0
    while 1:
        line = to_follow.readline()
        if not line:
            if proc and proc.returncode:
                print("Error: tail exited uncleanly -- you must use GNU tail")
                os.exit(1)
            break
        if 'HARAKIRI ON WORKER' in line:
            in_harakiri = True
        if in_harakiri:
            harakiri_lines.append(line)
            harakiris_seen += 'HARAKIRI' in line
            if harakiris_seen == 4:
                send_message(client, options, log="".join(harakiri_lines))
                in_harakiri = False
                harakiri_lines = []
                harakiris_seen = 0

def main():
    root = logging.getLogger('sentry.errors')
    root.setLevel(logging.DEBUG)
    root.addHandler(logging.StreamHandler())

    parser = OptionParser(version=get_version())
    parser.add_option("--tags", action="callback", callback=store_json, type="string", nargs=1, dest="tags")
    parser.add_option("--verbose", action="store_true")
    parser.add_option("--dsn")
    parser.add_option("--tail", action="store_true")
    parser.add_option("--watch", action="store_true")
    parser.add_option("--thread-regex")
    opts, args = parser.parse_args()

    dsn = opts.dsn or os.environ.get('SENTRY_DSN')

    if not dsn:
        try:
            from django.conf import settings
        except ImportError:
            pass
        else:
            dsn = settings.RAVEN_CONFIG['dsn']

    if not dsn:
        print("Error: No configuration detected!")
        print("You must either pass a DSN to the command, or set the SENTRY_DSN environment variable.")
        sys.exit(1)

    if not opts.verbose:
        sys.stdout = StringIO()

    client = Client(dsn, include_paths=['raven'], string_max_length=100000)

    if opts.watch:
        if len(args) != 1:
            print('Error: In --watch mode you must provide exactly one file '
                  'argument')
            sys.exit(1)
        tail = subprocess.Popen(['tail', '--follow=name', '--retry', args[0]], stdout=subprocess.PIPE)
        group_log(client, opts.__dict__, tail.stdout, tail)

    elif opts.tail:
        if len(args) > 0:
            print('Error: In --tail mode, no file arguments should be provided'
                  ' -- pipe to STDIN instead')
            sys.exit(1)
        group_log(client, opts.__dict__, sys.stdin)

    else:
        log = ''.join([line for line in fileinput.input(args)])
        send_message(client, opts.__dict__, log=log)

if __name__ == '__main__':
    main()


import os
import json
import click
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt

from sklearn.cluster import KMeans
from yellowbrick.cluster import KElbowVisualizer

def get_matrix(ds_location):
    with open(ds_location) as json_file:
        raw_list = json.load(json_file)
        data_matrix = []
        for data in raw_list:
            temp_row = []
            for column in data:
                temp_row.append(data[column])
            data_matrix.append(temp_row)
    return raw_list, np.asarray(data_matrix)

def _predict_all(model_location, matrix):
    model = tf.keras.models.load_model(model_location)
    model.summary()

    prediction_list = []
    for index, x in enumerate(model.predict(matrix)):
        prediction_list.append(x.astype(np.int64)[0])
    return prediction_list

def _normalize_matrix(prediction_list):
    min = prediction_list[0]
    max = prediction_list[0]
    for pre in prediction_list:
        if pre < min:
            min = pre
        if pre > max:
            max = pre

    for index, prediction in enumerate(prediction_list):
        prediction_list[index] = (prediction - min) / (max - min)
    return np.asanyarray(prediction_list).reshape(-1, 1)

def _find_best_k(data_matrix):
    model = KMeans()
    visualizer = KElbowVisualizer(model, k=(4, 12), timings=False)
    visualizer.fit(data_matrix)
    visualizer.show()

@click.command()
@click.option("--base_folder", "-b",
              default=r"D:\data_sets\linkedin-profiles-and-jobs-data\my",
              help="Base folder")
@click.option("--raw_json", "-r",
              default="_dump.json",
              help="Raw Input JSON")
@click.option("--model_name", "-m",
              default="_temp_model.h5",
              help="Model location")
def start(base_folder, raw_json, model_name):
    print("- Reading the RAW JSON")
    raw_list, data_matrix = get_matrix(os.path.join(base_folder, raw_json))
    data_matrix = data_matrix[:, 1:]

    # temp = np.random.randint(0, data_matrix.shape[0], 50)
    # data_matrix = data_matrix[temp]

    # Data Prediction
    prediction_list = _predict_all(os.path.join(base_folder, model_name), data_matrix)
    normalized_list = _normalize_matrix(prediction_list)
    # / Data Prediction

    # Find the K value
    # _find_best_k(normalized_list)
    # / Find the K value

    # KMeans
    model = KMeans(n_clusters=6, init="k-means++")
    kmeans_prediction = model.fit_predict(normalized_list)
    kmeans_prediction = np.reshape(kmeans_prediction, (-1, 1))
    # / KMeans

    # Plot
    plt.scatter(normalized_list, kmeans_prediction)
    for x in model.cluster_centers_:
        plt.axvline(x=x, ymin=0, ymax=5, color="r")
    plt.show()
    # / Plot

if __name__ == '__main__':
    start()


import os
import sys
import re
import nltk
import math
import numpy
from nltk.stem import WordNetLemmatizer
from nltk import word_tokenize
#nltk.download('wordnet')
#nltk.download('stopwords')
from nltk.corpus import stopwords
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_classif
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB,BernoulliNB
from sklearn.neighbors import KNeighborsClassifier
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics import f1_score

# preprocess class
class preprocess:
	def __init__(self,text):
		self.token_words = []
		self.text = text
		self.inv_pos_index = {}
		self.fin_text = ""

	def lower_case(self):
		self.text = self.text.lower()
		self.Word_Tokenize()

	def remove_punctuations(self):
		self.text = re.sub(r'[^\w\s]', ' ', self.text)

	def Word_Tokenize(self):
		self.token_words = word_tokenize(self.text)

	def remove_nonalpha(self):
		clean = []
		for word in self.token_words:
			new_word = ''.join([i for i in word if i.isalpha()])
			clean.append(new_word)
		self.token_words = clean

	def extra_process(self):
		self.text = self.text.replace('\\n',' ')

	def remove_stopwords(self):
		stop_words = stopwords.words('english')
		clean=[]
		for word in self.token_words:
			if not word in stop_words:
				clean.append(word)
		self.token_words = clean

	def lemma_sentence(self):
		wordnet_lemmatizer = WordNetLemmatizer()
		lemm_sentence=[]
		for word in self.token_words:
			lemm_sentence.append(wordnet_lemmatizer.lemmatize(word))
		self.token_words = lemm_sentence

	def token_to_text(self):
		for token in self.token_words:
			self.fin_text += token+' '
		self.fin_text.rstrip(' ')

	def auto_process(self):
		self.extra_process()
		self.remove_punctuations()
		self.lower_case()
		self.remove_stopwords()
		self.remove_nonalpha()
		self.lemma_sentence()
		self.token_to_text()

class DATA_UTIL:
	def __init__(self,directory):
		self.text = ""
		self.directory = directory
		self.sentence_lists_train = []
		self.sentence_label_train = []
		self.sentence_lists_test = []
		self.sentence_label_test = []
		self.get_text = ""
		self.topKlist = [1,10,100,1000,10000]
		self.X_new = []
		self.X_train = []
		self.y_train = []
		self.X_test = []
		self.y_test = []
		self.multi_score = []
		self.bernouli_score = []
		self.knn_score = []
		self.rocchio_score = []
		self.neighbors = [1,10,50]
		self.margins = [0]

	def preprocess_util(self,text):
		PRE_UTIL = preprocess(text)
		PRE_UTIL.auto_process()
		self.get_text = PRE_UTIL.fin_text

	def load_data_train(self):
		dir_1 = self.directory+"/class1/train"
		dir_2 = self.directory+"/class2/train"

		now_text = ""
		for file_name in sorted(os.listdir(dir_1)):
			with open(os.path.join(dir_1,file_name),"rb") as fp:
				self.preprocess_util(str(fp.read()))
				now_text = self.get_text
			self.sentence_lists_train.append(now_text)
			self.sentence_label_train.append(0)

		for file_name in sorted(os.listdir(dir_2)):
			with open(os.path.join(dir_2,file_name),"rb") as fp:
				self.preprocess_util(str(fp.read()))
				now_text = self.get_text
			self.sentence_lists_train.append(now_text)
			self.sentence_label_train.append(1)

		vectorizer = CountVectorizer()
		self.vec = vectorizer.fit(self.sentence_lists_train)
		self.X_train = self.vec.transform(self.sentence_lists_train)
		self.y_train = numpy.array(self.sentence_label_train)

	def load_data_test(self):
		dir_1 = self.directory+"/class1/test"
		dir_2 = self.directory+"/class2/test"

		now_text = ""
		for file_name in sorted(os.listdir(dir_1)):
			with open(os.path.join(dir_1,file_name),"rb") as fp:
				self.preprocess_util(str(fp.read()))
				now_text = self.get_text
			self.sentence_lists_test.append(now_text)
			self.sentence_label_test.append(0)

		for file_name in sorted(os.listdir(dir_2)):
			with open(os.path.join(dir_2,file_name),"rb") as fp:
				self.preprocess_util(str(fp.read()))
				now_text = self.get_text
			self.sentence_lists_test.append(now_text)
			self.sentence_label_test.append(1)

		self.X_test = self.vec.transform(self.sentence_lists_test)
		self.y_test = numpy.array(self.sentence_label_test)

	def find_naivebayes_score(self):
		multi_preds,bernouli_preds = [],[]
		for topK in self.topKlist:
			mnb = MultinomialNB(alpha=1.0)
			bnb = BernoulliNB()
			X = SelectKBest(mutual_info_classif,k=topK).fit(self.X_train,self.y_train)
			X_train_features = X.transform(self.X_train)
			X_test_features = X.transform(self.X_test)

			mnX = mnb.fit(X_train_features,self.y_train)
			multi_y = mnX.predict(X_test_features)
			self.multi_score.append(f1_score(self.y_test, multi_y, average='macro'))

			bnX = bnb.fit(X_train_features,self.y_train)
			bernouli_y = bnX.predict(X_test_features)
			self.bernouli_score.append(f1_score(self.y_test, bernouli_y, average='macro'))

	def save_outputs(self,file_name):

		 # for naive bayes score
		name = ["NumFeature","MultinomialNB","BernoulliNB"]
		s1 = ["1",str(self.multi_score[0]),str(self.bernouli_score[0])]
		s10 = ["10",str(self.multi_score[1]),str(self.bernouli_score[1])]
		s100 = ["100",str(self.multi_score[2]),str(self.bernouli_score[2])]
		s1000 = ["1000",str(self.multi_score[3]),str(self.bernouli_score[3])]
		s10000 = ["10000",str(self.multi_score[4]),str(self.bernouli_score[4])]
		mname = len(max(name,key=len))
		ms1 = len(max(s1,key=len))
		ms10 = len(max(s10,key=len))
		ms100 = len(max(s100,key=len))
		ms1000 = len(max(s1000,key=len))
		ms10000 = len(max(s10000,key=len))
		fp = open(file_name,"w")
		for i in range(3):
			print("{0} {1} {2} {3} {4} {5}".format(name[i].ljust(mname+1),s1[i].ljust(ms1+1),s10[i].ljust(ms10+1),s100[i].ljust(ms100+1),s1000[i].ljust(ms1000+1),s10000[i].ljust(ms10000+1)))
		for i in range(3):
			fp.write(
	    		"{0} {1} {2} {3} {4} {5}".format(
	       			name[i].ljust(mname+1),
	        		s1[i].ljust(ms1+1),
	        		s10[i].ljust(ms10+1),
	        		s100[i].ljust(ms100+1),
	        		s1000[i].ljust(ms1000+1),
	        		s10000[i].ljust(ms10000+1)
	        	)
	    	)
			fp.write('\n')
		fp.close()

if __name__=="__main__":
	sys_args =(sys.argv)
	path = sys_args[1]
	directory = sys_args[1]
	data = DATA_UTIL(directory)
	data.load_data_train()
	data.load_data_test()
	data.find_naivebayes_score()
	file_name = sys_args[2]
	data.save_outputs(file_name)


Import('*')

if env['platform'] not in ['windows', 'linux']:
    Return()

env = env.Clone()

env.Append(CPPDEFINES = [
    'GLEW_BUILD',
    'GLEW_STATIC',
    #'GLEW_MX', # Multiple Rendering Contexts support
])

env.PrependUnique(CPPPATH = [
    '#/include',
])

glew = env.StaticLibrary(
    target = 'glew',
    source = [
        'glew.c',
    ],
)

env = env.Clone()

if env['platform'] == 'windows':
    env.PrependUnique(LIBS = [
        'glu32',
        'opengl32',
        'gdi32',
        'user32',
    ])
else:
    env.PrependUnique(LIBS = [
        'GLU',
        'GL',
        'X11',
    ])
env.Prepend(LIBS = [glew])

env.Program(
    target = 'glewinfo',
    source = ['glewinfo.c'],
)

env.Program(
    target = 'visualinfo',
    source = ['visualinfo.c'],
)


#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

import logging.config

"""
    description: The example of logging.
    author: LiangCL
    since: 2020/1/13
"""

logging.config.fileConfig('conf/logging.ini')
logger = logging.getLogger(__name__)

def main() -> None:
    logger.debug('debug')
    logger.info('info')
    logger.warning('warning')
    logger.error('error')
    logger.fatal('fatal')

if __name__ == '__main__':
    main()


"""Functions for printing contributor location results"""

from collections import Counter

from github import get_contributor_location
from geolocation import get_country_from_location

def print_by_country(contributors):
    """
    Print contributors aggregated by country

    Args:
        contributors: a list of contributors

    Returns:
    null
    """
    print("COUNTRY | # OF CONTRIBUTORS")
    print("---------------------------")
    country_list = []
    for contributor in contributors:
        location = get_contributor_location(contributor)
        country = get_country_from_location(location)
        country_list.append(country)

    country_counter = Counter(country_list)
    for country, count in country_counter.most_common():
        print(country, count)

def print_by_contributor(contributors, pypi_data=None):
    """
    Print location results by contributor

    Args:
        contributors - a list of contributors

    Returns:
        null
    """
    print("CONTRIBUTOR, LOCATION")
    if pypi_data is not None:
        print("* indicates PyPI maintainer")
    print("---------------------")
    for contributor in contributors:
        location = get_contributor_location(contributor)
        country = get_country_from_location(location)
        try:
            # Check if pypi_data is not None, indicating a PyPI package scan
            if pypi_data is not None and contributor in pypi_data["pypi_maintainers"]:
                print(contributor, "*", "|", location, "|", country)
            else:
                print(contributor, "|", location, "|", country)
        except UnicodeEncodeError:
            print(contributor, "| error")


import pandas as pd
import numpy as np

from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier

from sklearn.model_selection import train_test_split

from pydotplus import graph_from_dot_data
from sklearn.tree import export_graphviz

def custom_round(x, base = 50):
    return int (base * round(float(x)/base))

dat = pd.read_csv('3.csv')

header = ['Id', #1 A
          'Sex', #2 B
          'Race', #3 C
          'First Gen', #4 D
          'SATReading', #5 E
          'SATMath', #6 F
          'High School GPA', #7 G
          'Semester Taken',#8 H
          'GPA',#9 I
          'Major Type',#10 J 1=CS, 2=Math, 3=Science, 4=Non-Science
          'Grade Intro Course',#11 K
          'Grade Follow Up Course',#12 L
          'Grade Fundamentals Course',#13 M
          'Grade Systems Course',#14 N
          'Grade Software Course',#15 O
          'Grade Paradigm Course',#16 P
          'Instructor Intro',#17 Q
          'Instructor Follow Up',#18 R
          'Instructor Fundamentals',#19 S
          'Instructor Systems'#20 T
         ]

dat.columns = header

#select the input variables
my_features_names = ['SATReading','SATMath','High School GPA', 'Grade Intro Course']

#set the dataframe according to the input variables
df = pd.DataFrame(dat, columns = my_features_names)

#clear the NaN data
df = df.dropna(axis=0)

#transform the data
x1 = df['SATReading'].apply((lambda x: custom_round(x, base=50))).values
x2 = df['SATMath'].apply((lambda x: custom_round(x, base=50))).values
x3 = df['High School GPA'].round(1).values

#set X data
X = pd.DataFrame(x1, columns=['SATReading'])
X['SATMath'] = x2
X['High School GPA'] = x3

#set y as target data
y = np.where(df['Grade Intro Course'] >= 3.25, 1, 0)

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.30, random_state=1, stratify=y)

print('Labels counts in (goal) attributes y:', np.bincount(y), len(y))
print('Labels counts in (goal) y_train:', np.bincount(y_train), len(y_train))
print('Labels counts in (goal) y_test:', np.bincount(y_test), len(y_test))

print('Labels counts in (features) X:', len(X))
print('Labels counts in (features) X_train:', len(X_train))
print('Labels counts in (features) X_test:', len(X_test))

#*****************************************************************************
forest = RandomForestClassifier(criterion='gini',
                                n_estimators=25,
                                random_state=1,
                                n_jobs=2)
forest.fit(X_train, y_train)
print("Importances: ", list(zip(X_train, forest.feature_importances_)))

#see accuracy
from sklearn.metrics import accuracy_score

#predict out of the training data set
test_preds = forest.predict(X_test)
train_preds = forest.predict(X_train)
#get the actual goal attributes of the testing data set
test_true = y_test
train_true = y_train
print("Test Data Accuracy: ", accuracy_score(test_true, test_preds))
print("Train Data Accuracy: ", accuracy_score(train_true, train_preds))

#*****************************************************************************
tree = DecisionTreeClassifier(criterion='gini',
                              max_depth=3,
                              random_state=1)
tree.fit(X_train, y_train)

X_combined = np.vstack((X_train, X_test))
y_combined = np.hstack((y_train, y_test))

dot_data = export_graphviz(tree,
                           filled=True,
                           rounded=True,
                           class_names=['Bad',
                                        'Good'],
                           feature_names=['SAT Reading',
                                        'SAT Math',
                                        'H.S. GPA'],
                           out_file=None)
graph = graph_from_dot_data(dot_data)
graph.write_png('3.png')


# _*_coding:utf-8_*_
# @Time    : 2020/10/28 23:26

# https://leetcode-cn.com/problems/zigzag-conversion/
'''
找规律以 n = numRows * 2 - 2 为一个循环，字符所在行号 min(i % n, n - i % n)
'''
class Solution:
    def convert(self, s: str, numRows: int) -> str:
        if numRows == 1:
            return s
        else:
            n = numRows * 2 - 2
            rows = [""] * numRows
            for i, char in enumerate(s):
                rows[min(i % n, n - i % n)] += char
            return "".join(rows)


import click
from arrow.cli import pass_context, json_loads
from arrow.decorators import custom_exception, dict_output

@click.command('write_downloadable')
@click.argument("organism", type=str)
@click.option(
    "--export_type",
    help="Export type. Choices: FASTA, GFF3, VCF",
    default="FASTA",
    show_default=True,
    type=str
)
@click.option(
    "--seq_type",
    help="Export selection. Choices: peptide, cds, cdna, genomic",
    default="peptide",
    show_default=True,
    type=str
)
@click.option(
    "--export_format",
    help="Export format, either gzip or text",
    default="text",
    show_default=True,
    type=str
)
@click.option(
    "--export_gff3_fasta",
    help="Export reference sequence when exporting GFF3 annotations.",
    is_flag=True
)
@click.option(
    "--sequences",
    help="Names of references sequences to add (default is all)",
    type=str
)
@click.option(
    "--region",
    help="Region to export in form sequence:min..max e.g., chr3:1001..1034",
    type=str
)
@pass_context
@custom_exception
@dict_output
def cli(ctx, organism, export_type="FASTA", seq_type="peptide", export_format="text", export_gff3_fasta=False, sequences=None, region=""):
    """Prepare a download for an organism

Output:

    a dictionary containing download information
    """
    return ctx.gi.io.write_downloadable(organism, export_type=export_type, seq_type=seq_type, export_format=export_format, export_gff3_fasta=export_gff3_fasta, sequences=sequences, region=region)


#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
This experiment was created using PsychoPy2 Experiment Builder (v1.80.04), Tue Jun  3 21:55:22 2014
If you publish work using this script please cite the relevant PsychoPy publications
  Peirce, JW (2007) PsychoPy - Psychophysics software in Python. Journal of Neuroscience Methods, 162(1-2), 8-13.
  Peirce, JW (2009) Generating stimuli for neuroscience using PsychoPy. Frontiers in Neuroinformatics, 2:10. doi: 10.3389/neuro.11.010.2008
"""

from __future__ import division  # so that 1/3=0.333 instead of 1/3=0
from psychopy import visual, core, data, event, logging, sound, gui
from psychopy.constants import *  # things like STARTED, FINISHED
import numpy as np  # whole numpy lib is available, prepend 'np.'
from numpy import sin, cos, tan, log, log10, pi, average, sqrt, std, deg2rad, rad2deg, linspace, asarray
from numpy.random import random, randint, normal, shuffle
import os  # handy system and path functions

# Store info about the experiment session
expName = 'DBP'  # from the Builder filename that created this script
expInfo = {'participant':'', 'session':'001'}
dlg = gui.DlgFromDict(dictionary=expInfo, title=expName)
if dlg.OK == False: core.quit()  # user pressed cancel
expInfo['date'] = data.getDateStr()  # add a simple timestamp
expInfo['expName'] = expName

# Setup filename for saving
filename = u'Beh_data' + os.path.sep + '%s_%s_%s' %(expInfo['participant'],'Ortho', expInfo['date'])

# An ExperimentHandler isn't essential but helps with data saving
thisExp = data.ExperimentHandler(name=expName, version='',
    extraInfo=expInfo, runtimeInfo=None,
    originPath=None,
    savePickle=True, saveWideText=True,
    dataFileName=filename)
#save a log file for detail verbose info
logFile = logging.LogFile(filename+'.log', level=logging.EXP)
logging.console.setLevel(logging.WARNING)  # this outputs to the screen, not a file

endExpNow = False  # flag for 'escape' or other condition => quit the exp

# Start Code - component code to be run before the window creation

# Setup the Window
win = visual.Window(size=(1440, 900), fullscr=True, screen=0, allowGUI=False, allowStencil=False,
    monitor='testMonitor', color=[0,0,0], colorSpace='rgb',
    blendMode='avg', useFBO=True,
    )
# store frame rate of monitor if we can measure it successfully
expInfo['frameRate']=win.getActualFrameRate()
if expInfo['frameRate']!=None:
    frameDur = 1.0/round(expInfo['frameRate'])
else:
    frameDur = 1.0/60.0 # couldn't get a reliable measure so guess

# Initialize components for Routine "instructions"
instructionsClock = core.Clock()
instrText = visual.TextStim(win=win, ori=0, name='instrText',
    text=u'Choose the side (left or right) with the word that is spelled correctly.\r\nPress any button to continue.\r\n',    font=u'Arial',
    pos=[0, 0], height=0.1, wrapWidth=None,
    color=u'white', colorSpace=u'rgb', opacity=1,
    depth=0.0)

# Initialize components for Routine "trial"
trialClock = core.Clock()
imgStimulus = visual.ImageStim(win=win, name='imgStimulus',
    image='sin', mask=None,
    ori=0, pos=[0, 100], size=[500, 500], units='pix',
    color=[1,1,1], colorSpace='rgb', opacity=1,
    flipHoriz=False, flipVert=False,
    texRes=128, interpolate=True, depth=0.0)
ISI = core.StaticPeriod(win=win, screenHz=expInfo['frameRate'], name='ISI')
combinedWords = visual.TextStim(win=win, ori=0, name='combinedWords',
    text='default text',    font='Arial',
    pos=[0, -0.45], height=0.15, wrapWidth=5000,
    color='white', colorSpace='rgb', opacity=1,
    depth=-2.0)
correct = 0
difficulty = 3
numTrials = 50

#SCcode - set counting variables for beginning of experiment
streakCorr = 0
maxTrials = 60
numTrials = 0
numCorr = 0

# Initialize components for Routine "feedback"
feedbackClock = core.Clock()
feedbackText = visual.TextStim(win=win, ori=0, name='feedbackText',
    text=u'+',    font=u'Arial',
    pos=[0, 0], height=0.3, wrapWidth=None,
    color=u'green', colorSpace=u'rgb', opacity=1,
    depth=0.0)

# Initialize components for Routine "EndofExpFeedback"
EndofExpFeedbackClock = core.Clock()
endText = visual.TextStim(win=win, ori=0, name='endText',
    text=u'END\n\nSCORE: 00/00',    font=u'Arial',
    pos=[0, 0], height=0.1, wrapWidth=None,
    color=u'white', colorSpace=u'rgb', opacity=1,
    depth=0.0)

# Create some handy timers
globalClock = core.Clock()  # to track the time since experiment started
routineTimer = core.CountdownTimer()  # to track time remaining of each (non-slip) routine

#------Prepare to start Routine "instructions"-------
t = 0
instructionsClock.reset()  # clock
frameN = -1
# update component parameters for each repeat
key_resp_2 = event.BuilderKeyResponse()  # create an object of type KeyResponse
key_resp_2.status = NOT_STARTED
# keep track of which components have finished
instructionsComponents = []
instructionsComponents.append(instrText)
instructionsComponents.append(key_resp_2)
for thisComponent in instructionsComponents:
    if hasattr(thisComponent, 'status'):
        thisComponent.status = NOT_STARTED

#-------Start Routine "instructions"-------
continueRoutine = True
while continueRoutine:
    # get current time
    t = instructionsClock.getTime()
    frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
    # update/draw components on each frame

    # *instrText* updates
    if t >= 0.0 and instrText.status == NOT_STARTED:
        # keep track of start time/frame for later
        instrText.tStart = t  # underestimates by a little under one frame
        instrText.frameNStart = frameN  # exact frame index
        instrText.setAutoDraw(True)

    # *key_resp_2* updates
    if t >= 0.0 and key_resp_2.status == NOT_STARTED:
        # keep track of start time/frame for later
        key_resp_2.tStart = t  # underestimates by a little under one frame
        key_resp_2.frameNStart = frameN  # exact frame index
        key_resp_2.status = STARTED
        # keyboard checking is just starting
        event.clearEvents(eventType='keyboard')
    if key_resp_2.status == STARTED:
        theseKeys = event.getKeys()

        # check for quit:
        if "escape" in theseKeys:
            endExpNow = True
        if len(theseKeys) > 0:  # at least one key was pressed
            # a response ends the routine
            continueRoutine = False

    # check if all components have finished
    if not continueRoutine:  # a component has requested a forced-end of Routine
        routineTimer.reset()  # if we abort early the non-slip timer needs reset
        break
    continueRoutine = False  # will revert to True if at least one component still running
    for thisComponent in instructionsComponents:
        if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
            continueRoutine = True
            break  # at least one component has not yet finished

    # check for quit (the Esc key)
    if endExpNow or event.getKeys(keyList=["escape"]):
        core.quit()

    # refresh the screen
    if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
        win.flip()
    else:  # this Routine was not non-slip safe so reset non-slip timer
        routineTimer.reset()

#-------Ending Routine "instructions"-------
for thisComponent in instructionsComponents:
    if hasattr(thisComponent, "setAutoDraw"):
        thisComponent.setAutoDraw(False)

# set up handler to look after randomisation of conditions etc
trialLoop = data.TrialHandler(nReps=1, method=u'random',
    extraInfo=expInfo, originPath=None,
    trialList=data.importConditions(u'Conditions_Orthographic.xlsx'),
    seed=None, name='trialLoop')
thisExp.addLoop(trialLoop)  # add the loop to the experiment
thisTrialLoop = trialLoop.trialList[0]  # so we can initialise stimuli with some values
# abbreviate parameter names if possible (e.g. rgb=thisTrialLoop.rgb)
if thisTrialLoop != None:
    for paramName in thisTrialLoop.keys():
        exec(paramName + '= thisTrialLoop.' + paramName)

#SCcode - set initial difficulty
difficulty = 3

for thisTrialLoop in trialLoop:
    currentLoop = trialLoop
    # abbreviate parameter names if possible (e.g. rgb = thisTrialLoop.rgb)
    if thisTrialLoop != None:
        for paramName in thisTrialLoop.keys():
            exec(paramName + '= thisTrialLoop.' + paramName)

    # SCcode - set the arrays
    imgArray = [imgfile1, imgfile2, imgfile3, imgfile4, imgfile5]
    combinedTextArray = [text1, text2, text3, text4, text5]
    widthArray = [w1, w2, w3, w4, w5]
    heightArray = [h1, h2, h3, h4, h5]

    #------Prepare to start Routine "trial"-------
    t = 0
    trialClock.reset()  # clock
    frameN = -1
    routineTimer.add(6.500000)
    # SCcode - update component parameters for each repeat
    imgStimulus.setImage(imgArray[difficulty - 1])
    combinedWords.setText(combinedTextArray[difficulty - 1])
    #bottomword.setText(bottomTextArray[difficulty - 1])
    response = event.BuilderKeyResponse()  # create an object of type KeyResponse
    response.status = NOT_STARTED

    # keep track of which components have finished
    trialComponents = []
    trialComponents.append(imgStimulus)
    trialComponents.append(ISI)
    trialComponents.append(combinedWords)
    trialComponents.append(response)

    for thisComponent in trialComponents:
        if hasattr(thisComponent, 'status'):
            thisComponent.status = NOT_STARTED

    #-------Start Routine "trial"-------
    continueRoutine = True
    while continueRoutine:
        # get current time
        t = trialClock.getTime()
        frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
        # update/draw components on each frame

        # *imgStimulus* updates
        if t >= 0.5 and imgStimulus.status == NOT_STARTED:
            # keep track of start time/frame for later
            imgStimulus.tStart = t  # underestimates by a little under one frame
            imgStimulus.frameNStart = frameN  # exact frame index
            imgStimulus.setAutoDraw(True)
        elif imgStimulus.status == STARTED and t >= (0.5 + (6.0-win.monitorFramePeriod*0.75)): #most of one frame period left
            imgStimulus.setAutoDraw(False)
        if imgStimulus.status == STARTED:  # only update if being drawn
            #imgStimulus.setSize([500,500], log=False)
            imgStimulus.setSize([widthArray[difficulty - 1], heightArray[difficulty - 1]], log=False)

        # *combinedWords* updates
        if t >= 0.5 and combinedWords.status == NOT_STARTED:
            # keep track of start time/frame for later
            combinedWords.tStart = t  # underestimates by a little under one frame
            combinedWords.frameNStart = frameN  # exact frame index
            combinedWords.setAutoDraw(True)
        elif combinedWords.status == STARTED and t >= (0.5 + (6.0-win.monitorFramePeriod*0.75)): #most of one frame period left
            combinedWords.setAutoDraw(False)

        # *response* updates
        if t >= 0.5 and response.status == NOT_STARTED:
            # keep track of start time/frame for later
            response.tStart = t  # underestimates by a little under one frame
            response.frameNStart = frameN  # exact frame index
            response.status = STARTED
            # keyboard checking is just starting
            response.clock.reset()  # now t=0
            event.clearEvents(eventType='keyboard')
        elif response.status == STARTED and t >= (0.5 + (6.0-win.monitorFramePeriod*0.75)): #most of one frame period left
            response.status = STOPPED
        if response.status == STARTED:
            theseKeys = event.getKeys(keyList=['left', 'right'])

            # check for quit:
            if "escape" in theseKeys:
                endExpNow = True
            if len(theseKeys) > 0:  # at least one key was pressed
                response.keys = theseKeys[-1]  # just the last key pressed
                response.rt = response.clock.getTime()
                # was this 'correct'?
                if (response.keys == str(corrAns)) or (response.keys == corrAns):
                    response.corr = 1
                else:
                    response.corr = 0
                # a response ends the routine
                continueRoutine = False

        # *ISI* period
        if t >= 0.0 and ISI.status == NOT_STARTED:
            # keep track of start time/frame for later
            ISI.tStart = t  # underestimates by a little under one frame
            ISI.frameNStart = frameN  # exact frame index
            ISI.start(0.5)
        elif ISI.status == STARTED: #one frame should pass before updating params and completing
            ISI.complete() #finish the static period

        # check if all components have finished
        if not continueRoutine:  # a component has requested a forced-end of Routine
            routineTimer.reset()  # if we abort early the non-slip timer needs reset
            break
        continueRoutine = False  # will revert to True if at least one component still running
        for thisComponent in trialComponents:
            if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
                continueRoutine = True
                break  # at least one component has not yet finished

        # check for quit (the Esc key)
        if endExpNow or event.getKeys(keyList=["escape"]):
            core.quit()

        # refresh the screen
        if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
            win.flip()
        else:  # this Routine was not non-slip safe so reset non-slip timer
            routineTimer.reset()

    #-------Ending Routine "trial"-------
    for thisComponent in trialComponents:
        if hasattr(thisComponent, "setAutoDraw"):
            thisComponent.setAutoDraw(False)
    # check responses
    if response.keys in ['', [], None]:  # No response was made
       response.keys=None
       # was no response the correct answer?!
       if str(corrAns).lower() == 'none': response.corr = 1  # correct non-response
       else: response.corr = 0  # failed to respond (incorrectly)
    # store data for trialLoop (TrialHandler)
    trialLoop.addData('response.keys',response.keys)
    trialLoop.addData('response.corr', response.corr)
    trialLoop.addData('difficulty', difficulty)

    numTrials = numTrials + 1

    #SCcode - check difficulty
    if response.corr == 1:
        numCorr = numCorr + 1
        streakCorr = streakCorr + 1
        if streakCorr >= 3:
            streakCorr = 0
            difficulty += 1
            if difficulty > 5:
                difficulty = 5
    else:
        streakCorr = 0
        difficulty -= 1
        if difficulty < 1:
            difficulty = 1

    if response.keys != None:  # we had a response
        trialLoop.addData('response.rt', response.rt)

    #------Prepare to start Routine "feedback"-------
    #t = 0
    feedbackClock.reset()  # clock
    frameN = -1
    routineTimer.add(6.500000-t)

    if response.corr == 1:
        feedbackText.setText(u'+')
        feedbackText.setSize(0.3)
        feedbackText.setColor(u'white')
    else:
        feedbackText.setText(u'+')
        feedbackText.setSize(0.3)
        feedbackText.setColor(u'white')

    # update component parameters for each repeat
    # keep track of which components have finished
    feedbackComponents = []
    feedbackComponents.append(feedbackText)
    for thisComponent in feedbackComponents:
        if hasattr(thisComponent, 'status'):
            thisComponent.status = NOT_STARTED

    #-------Start Routine "feedback"-------
    continueRoutine = True
    while continueRoutine and routineTimer.getTime() > 0:
        # get current time
        t = feedbackClock.getTime()
        frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
        # update/draw components on each frame

        # *feedbackText* updates
        if t >= 0.5 and feedbackText.status == NOT_STARTED:
            # keep track of start time/frame for later
            feedbackText.tStart = t  # underestimates by a little under one frame
            feedbackText.frameNStart = frameN  # exact frame index
            feedbackText.setAutoDraw(True)
        elif feedbackText.status == STARTED and t >= (0.5 + (6.0-win.monitorFramePeriod*0.75)-t): #most of one frame period left
            feedbackText.setAutoDraw(False)

        # check if all components have finished
        if not continueRoutine:  # a component has requested a forced-end of Routine
            routineTimer.reset()  # if we abort early the non-slip timer needs reset
            break
        continueRoutine = False  # will revert to True if at least one component still running
        for thisComponent in feedbackComponents:
            if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
                continueRoutine = True
                break  # at least one component has not yet finished

        # check for quit (the Esc key)
        if endExpNow or event.getKeys(keyList=["escape"]):
            core.quit()

        # refresh the screen
        if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
            win.flip()

    #-------Ending Routine "feedback"-------
    for thisComponent in feedbackComponents:
        if hasattr(thisComponent, "setAutoDraw"):
            thisComponent.setAutoDraw(False)
    thisExp.nextEntry()

# completed 1 repeats of 'trialLoop'

#------Prepare to start Routine "EndofExpFeedback"-------
t = 0
EndofExpFeedbackClock.reset()  # clock
frameN = -1

endText.setText(u'Congratulations! You completed the round. Press any button to exit.')
# update component parameters for each repeat
endExperimentKeystroke = event.BuilderKeyResponse()  # create an object of type KeyResponse
endExperimentKeystroke.status = NOT_STARTED
# keep track of which components have finished
EndofExpFeedbackComponents = []
EndofExpFeedbackComponents.append(endText)
EndofExpFeedbackComponents.append(endExperimentKeystroke)
for thisComponent in EndofExpFeedbackComponents:
    if hasattr(thisComponent, 'status'):
        thisComponent.status = NOT_STARTED

#-------Start Routine "EndofExpFeedback"-------
continueRoutine = True
while continueRoutine:
    # get current time
    t = EndofExpFeedbackClock.getTime()
    frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
    # update/draw components on each frame

    # *endText* updates
    if t >= 0.5 and endText.status == NOT_STARTED:
        # keep track of start time/frame for later
        endText.tStart = t  # underestimates by a little under one frame
        endText.frameNStart = frameN  # exact frame index
        endText.setAutoDraw(True)

    # *endExperimentKeystroke* updates
    if t >= 0.5 and endExperimentKeystroke.status == NOT_STARTED:
        # keep track of start time/frame for later
        endExperimentKeystroke.tStart = t  # underestimates by a little under one frame
        endExperimentKeystroke.frameNStart = frameN  # exact frame index
        endExperimentKeystroke.status = STARTED
        # keyboard checking is just starting
        event.clearEvents(eventType='keyboard')
    if endExperimentKeystroke.status == STARTED:
        theseKeys = event.getKeys()

        # check for quit:
        if "escape" in theseKeys:
            endExpNow = True
        if len(theseKeys) > 0:  # at least one key was pressed
            # a response ends the routine
            continueRoutine = False

    # check if all components have finished
    if not continueRoutine:  # a component has requested a forced-end of Routine
        routineTimer.reset()  # if we abort early the non-slip timer needs reset
        break
    continueRoutine = False  # will revert to True if at least one component still running
    for thisComponent in EndofExpFeedbackComponents:
        if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
            continueRoutine = True
            break  # at least one component has not yet finished

    # check for quit (the Esc key)
    if endExpNow or event.getKeys(keyList=["escape"]):
        core.quit()

    # refresh the screen
    if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
        win.flip()
    else:  # this Routine was not non-slip safe so reset non-slip timer
        routineTimer.reset()

#-------Ending Routine "EndofExpFeedback"-------
for thisComponent in EndofExpFeedbackComponents:
    if hasattr(thisComponent, "setAutoDraw"):
        thisComponent.setAutoDraw(False)

win.close()
core.quit()


def search(arr,key):
    i = 0
    found = False
    stop = False

    while i < len(arr) and not found and not stop:
        if key == arr[i]:
            found = True
        else:
            if key >= arr[i]:
                i += 1
            else:
                stop = True
    return found

array = [1, 2, 4, 5, 9, 12]
print(search(array, 3))


"""
Consider the forest as an N x M grid.
Each cell is either empty (represented by .) or blocked by a tree (represented by X).
You can move LEFT, RIGHT, UP, and DOWN through empty cells,
but you cannot travel through a tree cell. Starting cell is marked
with the character M, and the target cell is marked with a *.
The upper-left corner is indexed as (0, 0).
Find a number of times you are able to move in more than one direction.
"""

from src.graph import UndirectedGraph
from src.shortest_path import dijkstra_path

def count_number_of_road_forks(field):
    """
    Returns number of times you are able to move in more
    than one direction by a given forest

    :param field: Array of strings that represent forest
    :return: number of road forks
    """
    graph = UndirectedGraph()
    start = None
    end = None
    height = len(field)
    width = len(field[0])
    for i, row in enumerate(field):
        for j, symbol in enumerate(row):
            if symbol == 'X':
                continue

            index = __linear_index(i, j, width)
            if symbol == 'M':
                start = index
            if symbol == '*':
                end = index

            if __can_go_to(i - 1, j, height, width):
                if field[i - 1][j] != 'X':
                    neighbor_index = __linear_index(i - 1, j, width)
                    graph.add_edge(neighbor_index, index, 1)

            if __can_go_to(i, j - 1, height, width):
                if field[i][j - 1] != 'X':
                    neighbor_index = __linear_index(i, j - 1, width)
                    graph.add_edge(neighbor_index, index, 1)

    path = dijkstra_path(graph, start, end)
    fork_count = 1 if len(graph.get_edges(start)) > 1 else 0
    for vertex in path[1:-1]:
        if len(graph.get_edges(vertex)) - 1 > 1:
            fork_count += 1
    return fork_count

def __linear_index(i, j, width):
    return i * width + j

def __can_go_to(i, j, width, height):
    return 0 <= i < width and 0 <= j < height


import random
import math

class Movement:
    """Implement different movement options."""

    def default(self, data, robot):
        return robot.a, robot.a_alpha

    def position(self, data, robot):
        return 0, 0

    def vision(self, data, robot):
        return robot.a, robot.a_alpha

    def alert(self, data, robot):
        return robot.a, robot.a_alpha

    def bonk(self, data, robot):
        return robot.a, robot.a_alpha

class RandomMovement(Movement):

    def position(self, data, robot):

        x, y, alpha, v, v_alpha = data

        if v < 15:
            a = 1
            a_alpha = random.randint(-20, 20)
        else:
            a = 0
            a_alpha = random.randint(-20, 20)
        return a, a_alpha

class NussschneckeMovement(Movement):

    def position(self, data, robot):

        x, y, alpha, v, v_alpha = data

        if v < 7:
            a = 0.5
            a_alpha = 1
            return a, a_alpha
        else:
            a = 0
            a_alpha = 0
        return a, a_alpha

class SpiralMovement(Movement):

    def position(self, data, robot):

        x, y, alpha, v, v_alpha = data

        if v < 20:
            a = 1
            a_alpha = 1
            return a, a_alpha
        else:
            a = 1
            a_alpha = 0
        return a, a_alpha

class SpinMovement(Movement):

    def position(self, data, robot):

        x, y, alpha, v, v_alpha = data

        a = 0
        a_alpha = 99999999
        if v_alpha > 30:
            a = 0
            a_alpha = 0
        return a, a_alpha

class FollowMovement(Movement):
    # TODO fix self follow Error
    def __init__(self, target):
        self.target = target

    # simple variant without extrapolation
    def alert(self, data, robot):
        # setting robot destination to the coordinates of target robot
        robot.destination = data[self.target]
        return robot.a, robot.a_alpha

    def position(self, data, robot):
        x, y, alpha, v, v_alpha = data

        # setting the robots destination
        if not robot.destination:
            destination_x = x
            destination_y = y
        else:
            destination_x = robot.destination[0]
            destination_y = robot.destination[1]

        obj_position = (destination_x, destination_y)

        # simplifying alpha and velocity
        alpha = alpha % 360
        if v == 0:
            v = 0.00001

        # calculating velocity vector
        velocity_vector = calculate_vector(v, alpha)
        velocity_vector_magnitude = math.sqrt(
            velocity_vector[0] ** 2 + velocity_vector[1] ** 2)

        # calculating vector between robot and destination
        destination_vector = calculate_vector_between_points(
            obj_position, x, y)
        destination_vector_magnitude = math.sqrt(
            destination_vector[0] ** 2 + destination_vector[1] ** 2)

        # calculating the value of the angle_change needed
        destination_alpha_degree = calculate_destination_alpha(velocity_vector, destination_vector,
                                                               velocity_vector_magnitude,
                                                               destination_vector_magnitude)

        # determining direction and sign of turning angle
        direction = calculate_direction(velocity_vector, destination_vector)
        delta_alpha = set_angle_sign(destination_alpha_degree, direction)

        # setting a to accelerate to its top speed
        v_max = 15
        a = set_acceleration(v, v_max)
        # setting a_alpha values
        a_alpha = set_angle_acceleration(
            direction, delta_alpha, v_alpha, robot)

        return a, a_alpha

class RandomTargetMovement(Movement):
    # TODO fix self follow Error
    def alert(self, data, robot):
        # setting robot destination to the coordinates of target robot
        robot.destination = (random.randint(10, 990), random.randint(10, 990))
        return robot.a, robot.a_alpha

    def position(self, data, robot):
        x, y, alpha, v, v_alpha = data

        # setting the robots destination
        if not robot.destination:
            destination_x = x
            destination_y = y
            # TODO fix stuff
            return robot.a, robot.a_alpha
        else:
            destination_x = robot.destination[0]
            destination_y = robot.destination[1]
        obj_position = (destination_x, destination_y)

        # simplifying alpha and velocity
        alpha = alpha % 360
        if v == 0:
            v = 0.00001

        # calculating velocity vector
        velocity_vector = calculate_vector(v, alpha)
        velocity_vector_magnitude = math.sqrt(
            velocity_vector[0] ** 2 + velocity_vector[1] ** 2)

        # calculating vector between robot and destination
        destination_vector = calculate_vector_between_points(
            obj_position, x, y)
        destination_vector_magnitude = math.sqrt(
            destination_vector[0] ** 2 + destination_vector[1] ** 2)

        # calculating the value of the angle_change needed
        destination_alpha_degree = calculate_destination_alpha(velocity_vector, destination_vector,
                                                               velocity_vector_magnitude,
                                                               destination_vector_magnitude)

        # determining direction and sign of turning angle
        direction = calculate_direction(velocity_vector, destination_vector)
        delta_alpha = set_angle_sign(destination_alpha_degree, direction)

        # setting a to accelerate to its top speed
        v_max = 15
        a = set_acceleration(v, v_max)
        # setting a_alpha values
        a_alpha = set_angle_acceleration(
            direction, delta_alpha, v_alpha, robot)

        return a, a_alpha

class SimpleAvoidMovement(Movement):

    def vision(self, data, robot):
        robot.destination = prime_object(data)
        return robot.a, robot.a_alpha

    def position(self, data, robot):
        x, y, alpha, v, v_alpha, = data
        if v == 0:
            v = 0.001
        v_max = 10
        tile_size = 10
        obj_position = robot.destination[0]
        obj_coordinates = (
            obj_position[0] * tile_size + 5, obj_position[1] * tile_size + 5)

        if robot.destination[1] == 1 or robot.destination[1] == 2 or robot.destination[1] == 3:
            obj_type = "wall"
            obj_distance = robot.destination[2]
        else:
            obj_type = "robot"
            obj_distance = robot.destination[1]

        # calculate object angle
        obj_angle = calculate_angle_between_vectors(
            obj_coordinates, x, y, v, alpha)

        # calculate vectors
        velocity_vector = calculate_vector(v, alpha)
        object_vector = calculate_vector_between_points(obj_coordinates, x, y)

        # set Threshold
        threshold = calculate_threshold(
            obj_type, v, alpha, v_alpha, v_max, robot)

        # getting information about angle and direction
        turn_direction = calculate_direction(object_vector, velocity_vector)
        delta_alpha = set_delta_alpha(obj_type, obj_distance,
                                      threshold, obj_angle, turn_direction, v_alpha)

        # setting a values for a and a_alpha
        a = set_acceleration(v, v_max)
        a_alpha = set_angle_acceleration(
            turn_direction, delta_alpha, v_alpha, robot)

        return a, a_alpha

class RunMovement(Movement):

    def alert(self, data, robot):
        robot.robomap = data
        robot.threat = prime_robot(data)
        return robot.a, robot.a_alpha

    def vision(self, data, robot):
        robot.destination = prime_object(data)
        return robot.a, robot.a_alpha

    def position(self, data, robot):
        x, y, alpha, v, v_alpha, = data
        if v == 0:
            v = 0.001
        v_max = 10
        tile_size = 10

        # calculate object data
        obj_position = robot.destination[0]
        obj_coordinates = (
            obj_position[0] * tile_size + 5, obj_position[1] * tile_size + 5)
        obj_angle = calculate_angle_between_vectors(
            obj_coordinates, x, y, v, alpha)
        if robot.destination[1] == 1 or robot.destination[1] == 2 or robot.destination[1] == 3:
            obj_type = "wall"
            obj_distance = robot.destination[2]
        else:
            obj_type = "robot"
            obj_distance = robot.destination[1]

        # calculate robot data
        threat = robot.threat
        threat_coordinates = threat[0]
        threat_angle = calculate_angle_between_vectors(
            threat_coordinates, x, y, v, alpha)

        # calculate vectors
        velocity_vector = calculate_vector(v, alpha)
        object_vector = calculate_vector_between_points(obj_coordinates, x, y)
        threat_vector = (threat_coordinates[0]-x, threat_coordinates[1]-y)

        # set Threshold
        threshold = calculate_threshold(
            obj_type, v, alpha, v_alpha, v_max, robot)

        # getting information about angle and direction
        turn_direction = calculate_direction(object_vector, velocity_vector)
        threat_turn_direction = calculate_direction(
            threat_vector, velocity_vector)
        delta_alpha = set_run_delta_alpha(obj_type, obj_distance, threshold, obj_angle, turn_direction,
                                          v_alpha, threat_angle, threat_turn_direction,)

        # setting a values for a and a_alpha
        a = set_acceleration(v, v_max)
        a_alpha = set_angle_acceleration(
            turn_direction, delta_alpha, v_alpha, robot)

        return a, a_alpha

class ChaseMovement(Movement):
    def __init__(self, target):
        self.target = target

    def vision(self, data, robot):
        robot.destination = search(data, self.target)
        return robot.a, robot.a_alpha

    def position(self, data, robot):
        x, y, alpha, v, v_alpha, = data
        target_bot = robot.destination
        if type(target_bot) == bool:
            # set values to look around
            a = 0
            if v_alpha < 0 and abs(v_alpha) < robot.a_alpha_max:
                a_alpha = - 1
            elif v_alpha >= 0 and abs(v_alpha) < robot.a_alpha_max:
                a_alpha = 1
            elif abs(v_alpha) >= robot.a_alpha_max:
                a_alpha = 0
        else:
            a, a_alpha = position_destination_robot(self, data, robot)
            robot.destination = None

        return a, a_alpha

class ChaseMovementGun(Movement):
    def __init__(self, target):
        self.target = target

    def vision(self, data, robot):
        robot.destination = search(data, self.target)
        return robot.a, robot.a_alpha

    def position(self, data, robot):
        x, y, alpha, v, v_alpha, = data
        # execute shoot behaviour
        shoot_straight(robot, data)
        target_bot = robot.destination
        if type(target_bot) == bool:
            a = 0
            if v_alpha < robot.a_alpha_max:
                a_alpha = 1
            elif v_alpha >= robot.a_alpha_max:
                a_alpha = 0
        else:
            a, a_alpha = position_destination_robot(self, data, robot)
            robot.destination = None

        return a, a_alpha

class SimpleAvoidMovementGun(Movement):

    def vision(self, data, robot):
        robot.destination = prime_object(data)
        return robot.a, robot.a_alpha

    def position(self, data, robot):
        x, y, alpha, v, v_alpha, = data

        if v == 0:
            v = 0.001
        v_max = 10
        tile_size = 10
        obj_position = robot.destination[0]
        obj_coordinates = (
            obj_position[0] * tile_size + 5, obj_position[1] * tile_size + 5)

        if robot.destination[1] == 1 or robot.destination[1] == 2 or robot.destination[1] == 3:
            obj_type = "wall"
            obj_distance = robot.destination[2]
        else:
            obj_type = "robot"
            obj_distance = robot.destination[1]

        # calculate object angle
        obj_angle = calculate_angle_between_vectors(
            obj_coordinates, x, y, v, alpha)

        # calculate vectors
        velocity_vector = calculate_vector(v, alpha)
        object_vector = calculate_vector_between_points(obj_coordinates, x, y)

        # set Threshold
        threshold = calculate_threshold(
            obj_type, v, alpha, v_alpha, v_max, robot)

        # getting information about angle and direction
        turn_direction = calculate_direction(object_vector, velocity_vector)
        delta_alpha = set_delta_alpha(obj_type, obj_distance,
                                      threshold, obj_angle, turn_direction, v_alpha)

        # setting a values for a and a_alpha
        a = set_acceleration(v, v_max)
        a_alpha = set_angle_acceleration(
            turn_direction, delta_alpha, v_alpha, robot)

        # execute shoot behaviour
        if obj_type == "robot":
            shoot_straight(robot, data)

        return a, a_alpha

class PermanentGunMovement(RandomTargetMovement):

    def position(self, data, robot):
        robot.shoot()
        return super().position(data, robot)

class ChaseAvoidMovement(Movement):

    def __init__(self, target):
        self.target = target

    def vision(self, data, robot):
        # determine if a obstacle needs to be avoided
        dist_index = len(prime_object(data)) - 1
        obj_dist = prime_object(data)[dist_index]
        is_wall = (dist_index == 2)
        act_dist = 100
        if is_wall:
            avoid = (obj_dist < act_dist)
        else:
            avoid = False

        # case AvoidMovement
        if avoid:
            robot.destination = prime_object(data)
            return robot.a, robot.a_alpha
        # case ChaseMovement
        else:
            robot.destination = search(data, self.target)
            return robot.a, robot.a_alpha

    def position(self, data, robot):
        # determine whether destination is a target or obstacle
        if type(robot.destination) == bool:
            destination_type = "target"
        elif len(robot.destination) == 2:
            destination_type = "target"
        else:
            destination_type = "obstacle"
        if destination_type == "obstacle":
            a, a_alpha = SimpleAvoidMovement.position(self, data, robot)
        else:
            a, a_alpha = ChaseMovement.position(self, data, robot)
        return a, a_alpha

class ChaseAvoidMovementGun(ChaseAvoidMovement):
    def position(self, data, robot):
        shoot_straight(robot, data)
        return super().position(data, robot)

def calculate_distance(a_x, a_y, b_x, b_y):
    v_x = b_x - a_x
    v_y = b_y - a_y
    distance = math.sqrt(v_x ** 2 + v_y ** 2)
    return distance

def calc_cross_product(B, P):
    # calculates cross product
    b_x = B[0]
    b_y = B[1]
    p_x = P[0]
    p_y = P[1]

    cp = b_x * p_y - b_y * p_x
    return cp

def calculate_vector(magnitude, angle):
    radian = (angle / 180 * math.pi)
    vector_x = (magnitude * math.sin(radian))
    vector_y = - (magnitude * math.cos(radian))
    vector = (vector_x, vector_y)
    return vector

def calculate_vector_between_points(obj_position, x, y):
    object_vector_x = obj_position[0] - x
    object_vector_y = obj_position[1] - y
    object_vector = (object_vector_x, object_vector_y)
    return object_vector

def calculate_angle_between_vectors(obj_position, x, y, v, alpha):
    object_vector_x = obj_position[0] - x
    object_vector_y = obj_position[1] - y
    object_vector_magnitude = math.sqrt(
        object_vector_x ** 2 + object_vector_y ** 2)

    velocity_vector = calculate_vector(v, alpha)
    velocity_vector_x = velocity_vector[0]
    velocity_vector_y = velocity_vector[1]
    velocity_vector_magnitude = math.sqrt(
        velocity_vector_x ** 2 + velocity_vector_y ** 2)

    vector_multiplication = (velocity_vector_x * object_vector_x +
                             velocity_vector_y * object_vector_y)
    magnitude_multiplication = velocity_vector_magnitude * object_vector_magnitude
    if magnitude_multiplication != 0:
        if vector_multiplication / magnitude_multiplication > 1:
            ratio = 1
        elif vector_multiplication / magnitude_multiplication < -1:
            ratio = -1
        else:
            ratio = vector_multiplication / magnitude_multiplication

        if magnitude_multiplication == 0:
            obj_alpha = 0
        else:
            obj_alpha = math.acos(ratio)
    else:
        obj_alpha = 0
    obj_angle = (obj_alpha * 180 / math.pi) % 360
    return obj_angle

def calculate_direction(main_vector, second_vector):
    cross_product = calc_cross_product(
        (main_vector[0], main_vector[1]),
        (second_vector[0], second_vector[1]))

    if cross_product > 0:
        direction = "right"
    elif cross_product < 0:
        direction = "left"
    elif cross_product == 0:
        direction = "none"
    return direction

def calculate_threshold(obj_type, v, alpha, v_alpha, v_max, robot):
    # distance to object at which the robot starts acting
    if obj_type == "wall":
        delta_alpha = 90
        obj_size = 10
        obj_r = math.sqrt(2) * obj_size
    elif obj_type == "robot":
        delta_alpha = 180
        enemy_radius = 50 + v_max
        obj_r = enemy_radius
    delta_alpha_per_unit = abs(robot.a_alpha_max / v_max)
    turn_distance = (delta_alpha + abs(v_alpha)) * delta_alpha_per_unit
    threshold = turn_distance + 2 * robot.radius + obj_r
    # post processing
    threshold = threshold / 1.5
    return threshold

def calculate_destination_alpha(vec1, vec2, vec1_magnitude, vec2_magnitude):
    vector_multiplication = (vec1[0] * vec2[0] +
                             vec1[1] * vec2[1])
    magnitude_multiplication = vec1_magnitude * vec2_magnitude
    if magnitude_multiplication != 0:
        if -1 < vector_multiplication / magnitude_multiplication < 1:
            destination_alpha = math.acos(
                vector_multiplication / magnitude_multiplication) - 0.01
        else:
            destination_alpha = 0
    elif magnitude_multiplication == 0:
        destination_alpha = 0
    destination_alpha_degree = (destination_alpha * 180 / math.pi) % 360
    return destination_alpha_degree

def set_delta_alpha(obj_type, distance, threshold, obj_angle, turn_direction, v_alpha):
    # set delta_alpha based on obstacle type and distance
    absolute_delta_alpha = 10
    if obj_type == "wall":
        if distance <= threshold and turn_direction == "right":
            delta_alpha = absolute_delta_alpha
        elif distance <= threshold and turn_direction == "left":
            delta_alpha = - absolute_delta_alpha
        else:
            delta_alpha = 0
    if obj_type == "robot":
        if distance <= threshold and turn_direction == "right":
            delta_alpha = (180 - abs(obj_angle))
        elif distance <= threshold and turn_direction == "left":
            delta_alpha = - (180 - abs(obj_angle))
        else:
            delta_alpha = 0
    return delta_alpha

def set_run_delta_alpha(obj_type, distance, threshold, obj_angle, turn_direction, v_alpha,
                        threat_angle, threat_turn_direction):
    # set delta_alpha based on obstacle and threat
    absolute_delta_alpha = 20
    if obj_type == "wall":
        if distance <= threshold and turn_direction == "right":
            delta_alpha = absolute_delta_alpha
        elif distance <= threshold and turn_direction == "left":
            delta_alpha = - absolute_delta_alpha
        elif distance <= threshold and turn_direction == "none":
            delta_alpha = 0

    if obj_type == "robot":
        if distance <= threshold and turn_direction == "right":
            delta_alpha = (180 - abs(obj_angle))
        elif distance <= threshold and turn_direction == "left":
            delta_alpha = - (180 - abs(obj_angle))
        elif distance <= threshold and turn_direction == "none":
            delta_alpha = 0

    smoothifier = (180 - threat_angle)/180
    if distance > threshold:
        if threat_turn_direction == "right":
            delta_alpha = 20 * smoothifier
        elif threat_turn_direction == "left":
            delta_alpha = - 20 * smoothifier
        elif threat_turn_direction == "none":
            delta_alpha = 0

    return delta_alpha

def set_angle_sign(angle, direction):
    if direction == "right":
        signed_angle = angle
    elif direction == "left":
        signed_angle = - angle
    elif direction == "none":
        signed_angle = angle
    return signed_angle

def set_angle_acceleration(direction, delta_alpha, v_alpha, robot):
    # setting a_alpha values
    a_alpha_max = robot.a_alpha_max
    if direction == "right":
        if delta_alpha >= a_alpha_max + v_alpha:
            a_alpha = a_alpha_max
        elif delta_alpha < a_alpha_max + v_alpha:
            a_alpha = delta_alpha - v_alpha

    elif direction == "left":
        if abs(delta_alpha) >= abs(a_alpha_max - v_alpha):
            a_alpha = - a_alpha_max
        elif abs(delta_alpha) < abs(a_alpha_max - v_alpha):
            a_alpha = -(abs(delta_alpha)) + abs(v_alpha)

    elif direction == "none":
        a_alpha = 0.01

    return a_alpha

def set_acceleration(velocity, v_max):
    # setting a to accelerate to a speed of v_max
    if velocity < v_max:
        a = 1
    else:
        a = 0
    return a

def search(array_tuple, pos):
    robot_array = array_tuple[1]
    found_bot = robot_array[pos]
    return found_bot

def prime_object(array_tuple):
    robot_array = array_tuple[1]
    obstacle_array = array_tuple[0]
    significance = math.inf
    index_of_obj = 0
    type_of_obj = 0
    robot_multiplier = 1

    for i in range(len(obstacle_array)):
        obj_distance = obstacle_array[i][2]
        if obj_distance < significance and obj_distance:
            significance = obj_distance
            index_of_obj = i
            type_of_obj = 0

    for i in range(len(robot_array)):
        if type(robot_array[i]) == tuple:
            obj_significance = robot_array[i][1] * robot_multiplier
            if obj_significance < significance and obj_significance > 0:
                significance = obj_significance
                index_of_obj = i
                type_of_obj = 1

    significant_object = array_tuple[type_of_obj][index_of_obj]
    return significant_object

def prime_robot(array):
    distance_array = []
    robot_x = array[0][0]
    robot_y = array[0][1]
    for i in range(len(array)):
        distance_array.append(calculate_distance(
            robot_x, robot_y, array[i][0], array[i][1]))
    significance = math.inf
    significant_index = 1
    for i in range(len(distance_array)):
        if distance_array[i] < significance and distance_array[i] > 0:
            significance = distance_array[i]
            significant_index = i
    significant_robot = (array[significant_index],
                         distance_array[significant_index])
    return significant_robot

def print_info(boolean, velocity_vector, object_vector, threshold, turn_direction, delta_alpha, a, a_alpha,
               obj_distance, obj_angle, robot):
    if boolean:
        print("Object: " + str(robot.destination))
        print("Vv: " + str(velocity_vector))
        print("Ov: " + str(object_vector))
        print("obj_angle: " + str(obj_angle))
        print("distance: " + str(obj_distance))
        print("threshold: " + str(threshold))
        print("turn_direction: " + str(turn_direction))
        print("delta_alpha: " + str(delta_alpha))
        print("a: " + str(a))
        print("a_alpha: " + str(a_alpha))
        print("-------------------------")

def position_destination_robot(self, data, robot):
    x, y, alpha, v, v_alpha = data

    # setting the robots destination
    if not robot.destination:
        destination_x = x
        destination_y = y
    else:
        destination_x = robot.destination[0][0]
        destination_y = robot.destination[0][1]
    obj_position = (destination_x, destination_y)
    if v == 0:
        v = 0.00001

    # calculating velocity vector
    velocity_vector = calculate_vector(v, alpha)
    velocity_vector_magnitude = math.sqrt(
        velocity_vector[0] ** 2 + velocity_vector[1] ** 2)

    # calculating vector between robot and destination
    destination_vector = calculate_vector_between_points(obj_position, x, y)
    destination_vector_magnitude = math.sqrt(
        destination_vector[0] ** 2 + destination_vector[1] ** 2)

    # calculating the value of the angle_change needed
    destination_alpha_degree = calculate_destination_alpha(velocity_vector, destination_vector,
                                                           velocity_vector_magnitude, destination_vector_magnitude)

    # determining direction and sign of turning angle
    direction = calculate_direction(velocity_vector, destination_vector)
    delta_alpha = set_angle_sign(destination_alpha_degree, direction)

    # setting a to accelerate to its top speed
    v_max = 15
    a = set_acceleration(v, v_max)
    # setting a_alpha values
    a_alpha = set_angle_acceleration(direction, delta_alpha, v_alpha, robot)

    return a, a_alpha

def shoot_straight(robot, data):
    x, y, alpha, v, v_alpha = data
    if type(robot.destination) == tuple:
        coordinates = robot.destination[0]
        angle = calculate_angle_between_vectors(coordinates, x, y, v, alpha)
        ready = not (robot.is_shooting() or robot.is_reloading())
        if ready and 0.01 < angle <= 90:
            # set acceptable inaccuracy
            max_inaccuracy = robot.radius
            # calculate aim inaccuracy
            inaccuracy = calculate_inaccuracy((x, y), coordinates, alpha, v)
            # decide action
            if inaccuracy <= max_inaccuracy and angle <= 90:
                robot.shoot()

def calculate_inaccuracy(position, coordinates, alpha, vel):
    # For angles < 90
    x = position[0]
    y = position[1]
    c_x = coordinates[0]
    c_y = coordinates[1]
    robot_radian = (alpha / 180 * math.pi)

    # get angle between aim direction and target, as radian
    angle = calculate_angle_between_vectors(coordinates, x, y, vel, alpha)
    angle = angle % 360
    target_radian = (angle / 180 * math.pi)

    # calculate distance between position and coordinates
    distance = math.sqrt((c_x-x)**2 + (c_y-y)**2)

    # calculate opposite's length of Triangle
    a = (math.sin(target_radian)*distance)
    b = (math.sin(robot_radian)*distance)
    opp_abs = math.sqrt(a**2 + b**2)

    # calculate inaccuracy
    inaccuracy = math.sin(target_radian) * opp_abs
    return inaccuracy


#
# Copyright 2020 - Swiss Data Science Center (SDSC)
# A partnership between École Polytechnique Fédérale de Lausanne (EPFL) and
# Eidgenössische Technische Hochschule Zürich (ETHZ).
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Renku service api versions."""
from typing import Any, Callable, List, Optional

from flask import Blueprint

class ApiVersion:
    """Represents a Blueprint API version."""

    def __init__(self, name: str, is_base_version: bool = False):
        self.name = name
        self.is_base_version = is_base_version

class VersionedBlueprint(Blueprint):
    """A Blueprint that supports versioning."""

    def add_url_rule(
        self,
        rule: str,
        endpoint: Optional[str] = None,
        view_func: Optional[Callable] = None,
        provide_automatic_options: Optional[bool] = None,
        versions: Optional[List[ApiVersion]] = None,
        **options: Any,
    ) -> None:
        """Overwrite Blueprint add_url_rule to support versioning."""
        if versions is None:
            return

        for version in versions:
            if version.is_base_version:
                super().add_url_rule(
                    rule, endpoint, view_func, provide_automatic_options=provide_automatic_options, **options
                )

            version_rule = f"/{version.name}{rule}"
            super().add_url_rule(
                version_rule, endpoint, view_func, provide_automatic_options=provide_automatic_options, **options
            )

V1_0 = ApiVersion("1.0")
V1_1 = ApiVersion("1.1")
V1_2 = ApiVersion("1.2")
V1_3 = ApiVersion("1.3")
V1_4 = ApiVersion("1.4")
V1_5 = ApiVersion("1.5")
V2_0 = ApiVersion("2.0")
V2_1 = ApiVersion("2.1", is_base_version=True)

VERSIONS_FROM_V1_5 = [V1_5, V2_0, V2_1]
VERSIONS_FROM_V1_4 = [V1_4] + VERSIONS_FROM_V1_5
VERSIONS_FROM_V1_1 = [V1_1, V1_2, V1_3] + VERSIONS_FROM_V1_4
ALL_VERSIONS = [V1_0] + VERSIONS_FROM_V1_1

MINIMUM_VERSION = V1_0
MAXIMUM_VERSION = V2_1