from __future__ import print_function

import os
import string

import mock
import pytest
from click import UsageError
from click.testing import CliRunner

from dagster import (
    DagsterInvariantViolationError,
    PartitionSetDefinition,
    RepositoryDefinition,
    ScheduleDefinition,
    lambda_solid,
    pipeline,
    repository_partitions,
    schedules,
    seven,
    solid,
)
from dagster.check import CheckError
from dagster.cli.pipeline import (
    execute_backfill_command,
    execute_execute_command,
    execute_list_command,
    execute_print_command,
    execute_scaffold_command,
    pipeline_backfill_command,
    pipeline_execute_command,
    pipeline_list_command,
    pipeline_print_command,
    pipeline_scaffold_command,
)
from dagster.cli.run import run_list_command, run_wipe_command
from dagster.cli.schedule import (
    schedule_list_command,
    schedule_restart_command,
    schedule_start_command,
    schedule_stop_command,
    schedule_up_command,
    schedule_wipe_command,
)
from dagster.config.field_utils import Shape
from dagster.core.instance import DagsterInstance, InstanceType
from dagster.core.launcher import RunLauncher
from dagster.core.serdes import ConfigurableClass
from dagster.core.storage.event_log import InMemoryEventLogStorage
from dagster.core.storage.local_compute_log_manager import NoOpComputeLogManager
from dagster.core.storage.root import LocalArtifactStorage
from dagster.core.storage.runs import InMemoryRunStorage
from dagster.utils import script_relative_path
from dagster.utils.test import FilesytemTestScheduler

def no_print(_):
    return None

@lambda_solid
def do_something():
    return 1

@lambda_solid
def do_input(x):
    return x

@pipeline(name='foo')
def foo_pipeline():
    do_something()

def define_foo_pipeline():
    return foo_pipeline

@pipeline(name='baz', description='Not much tbh')
def baz_pipeline():
    do_input()

def define_bar_repo():
    return RepositoryDefinition('bar', {'foo': define_foo_pipeline, 'baz': lambda: baz_pipeline},)

@solid
def spew(context):
    context.log.info('HELLO WORLD')

@solid
def fail(context):
    raise Exception('I AM SUPPOSED TO FAIL')

@pipeline
def stdout_pipeline():
    spew()

@pipeline
def stderr_pipeline():
    fail()

def test_list_command():
    runner = CliRunner()

    execute_list_command(
        {
            'repository_yaml': None,
            'python_file': script_relative_path('test_cli_commands.py'),
            'module_name': None,
            'fn_name': 'define_bar_repo',
        },
        no_print,
    )

    result = runner.invoke(
        pipeline_list_command,
        ['-f', script_relative_path('test_cli_commands.py'), '-n', 'define_bar_repo'],
    )

    assert result.exit_code == 0
    assert result.output == (
        'Repository bar\n'
        '**************\n'
        'Pipeline: baz\n'
        'Description:\n'
        'Not much tbh\n'
        'Solids: (Execution Order)\n'
        '    do_input\n'
        '*************\n'
        'Pipeline: foo\n'
        'Solids: (Execution Order)\n'
        '    do_something\n'
    )

    execute_list_command(
        {
            'repository_yaml': None,
            'python_file': None,
            'module_name': 'dagster_examples.intro_tutorial.repos',
            'fn_name': 'define_repo',
        },
        no_print,
    )

    result = runner.invoke(
        pipeline_list_command, ['-m', 'dagster_examples.intro_tutorial.repos', '-n', 'define_repo']
    )
    assert result.exit_code == 0
    assert result.output == (
        'Repository hello_cereal_repository\n'
        '**********************************\n'
        'Pipeline: complex_pipeline\n'
        'Solids: (Execution Order)\n'
        '    load_cereals\n'
        '    sort_by_calories\n'
        '    sort_by_protein\n'
        '    display_results\n'
        '*******************************\n'
        'Pipeline: hello_cereal_pipeline\n'
        'Solids: (Execution Order)\n'
        '    hello_cereal\n'
    )

    execute_list_command(
        {
            'repository_yaml': script_relative_path('repository_module.yaml'),
            'python_file': None,
            'module_name': None,
            'fn_name': None,
        },
        no_print,
    )

    result = runner.invoke(
        pipeline_list_command, ['-y', script_relative_path('repository_module.yaml')]
    )
    assert result.exit_code == 0
    assert result.output == (
        'Repository hello_cereal_repository\n'
        '**********************************\n'
        'Pipeline: complex_pipeline\n'
        'Solids: (Execution Order)\n'
        '    load_cereals\n'
        '    sort_by_calories\n'
        '    sort_by_protein\n'
        '    display_results\n'
        '*******************************\n'
        'Pipeline: hello_cereal_pipeline\n'
        'Solids: (Execution Order)\n'
        '    hello_cereal\n'
    )

    with pytest.raises(UsageError):
        execute_list_command(
            {
                'repository_yaml': None,
                'python_file': 'foo.py',
                'module_name': 'dagster_examples.intro_tutorial.repos',
                'fn_name': 'define_repo',
            },
            no_print,
        )

    result = runner.invoke(
        pipeline_list_command,
        ['-f', 'foo.py', '-m', 'dagster_examples.intro_tutorial.repos', '-n', 'define_repo'],
    )
    assert result.exit_code == 2

    with pytest.raises(UsageError):
        execute_list_command(
            {
                'repository_yaml': None,
                'python_file': None,
                'module_name': 'dagster_examples.intro_tutorial.repos',
                'fn_name': None,
            },
            no_print,
        )

    result = runner.invoke(pipeline_list_command, ['-m', 'dagster_examples.intro_tutorial.repos'])
    assert result.exit_code == 2

    with pytest.raises(UsageError):
        execute_list_command(
            {
                'repository_yaml': None,
                'python_file': script_relative_path('test_cli_commands.py'),
                'module_name': None,
                'fn_name': None,
            },
            no_print,
        )

    result = runner.invoke(
        pipeline_list_command, ['-f', script_relative_path('test_cli_commands.py')]
    )
    assert result.exit_code == 2

def valid_execute_args():
    return [
        {
            'repository_yaml': script_relative_path('repository_file.yaml'),
            'pipeline_name': ('foo',),
            'python_file': None,
            'module_name': None,
            'fn_name': None,
        },
        {
            'repository_yaml': script_relative_path('repository_module.yaml'),
            'pipeline_name': ('hello_cereal_pipeline',),
            'python_file': None,
            'module_name': None,
            'fn_name': None,
        },
        {
            'repository_yaml': None,
            'pipeline_name': ('foo',),
            'python_file': script_relative_path('test_cli_commands.py'),
            'module_name': None,
            'fn_name': 'define_bar_repo',
        },
        {
            'repository_yaml': None,
            'pipeline_name': ('hello_cereal_pipeline',),
            'python_file': None,
            'module_name': 'dagster_examples.intro_tutorial.repos',
            'fn_name': 'define_repo',
        },
        {
            'repository_yaml': None,
            'pipeline_name': (),
            'python_file': None,
            'module_name': 'dagster_examples.intro_tutorial.repos',
            'fn_name': 'hello_cereal_pipeline',
        },
        {
            'repository_yaml': None,
            'pipeline_name': (),
            'python_file': script_relative_path('test_cli_commands.py'),
            'module_name': None,
            'fn_name': 'define_foo_pipeline',
        },
        {
            'repository_yaml': None,
            'pipeline_name': (),
            'python_file': script_relative_path('test_cli_commands.py'),
            'module_name': None,
            'fn_name': 'foo_pipeline',
        },
    ]

def valid_cli_args():
    return [
        ['-y', script_relative_path('repository_file.yaml'), 'foo'],
        ['-y', script_relative_path('repository_module.yaml'), 'hello_cereal_pipeline'],
        ['-f', script_relative_path('test_cli_commands.py'), '-n', 'define_bar_repo', 'foo'],
        [
            '-m',
            'dagster_examples.intro_tutorial.repos',
            '-n',
            'define_repo',
            'hello_cereal_pipeline',
        ],
        ['-m', 'dagster_examples.intro_tutorial.repos', '-n', 'hello_cereal_pipeline'],
        ['-f', script_relative_path('test_cli_commands.py'), '-n', 'define_foo_pipeline'],
    ]

def test_print_command():
    for cli_args in valid_execute_args():
        execute_print_command(verbose=True, cli_args=cli_args, print_fn=no_print)

    for cli_args in valid_execute_args():
        execute_print_command(verbose=False, cli_args=cli_args, print_fn=no_print)

    runner = CliRunner()

    for cli_args in valid_cli_args():
        result = runner.invoke(pipeline_print_command, cli_args)
        assert result.exit_code == 0

        result = runner.invoke(pipeline_print_command, ['--verbose'] + cli_args)
        assert result.exit_code == 0

    res = runner.invoke(
        pipeline_print_command,
        [
            '--verbose',
            '-f',
            script_relative_path('test_cli_commands.py'),
            '-n',
            'define_bar_repo',
            'baz',
        ],
    )
    assert res.exit_code == 0

def test_execute_mode_command():
    runner = CliRunner()

    add_result = runner_pipeline_execute(
        runner,
        [
            '-y',
            script_relative_path('../repository.yaml'),
            '--env',
            script_relative_path('../environments/multi_mode_with_resources/add_mode.yaml'),
            '-d',
            'add_mode',
            'multi_mode_with_resources',  # pipeline name
        ],
    )

    assert add_result

    mult_result = runner_pipeline_execute(
        runner,
        [
            '-y',
            script_relative_path('../repository.yaml'),
            '--env',
            script_relative_path('../environments/multi_mode_with_resources/mult_mode.yaml'),
            '-d',
            'mult_mode',
            'multi_mode_with_resources',  # pipeline name
        ],
    )

    assert mult_result

    double_adder_result = runner_pipeline_execute(
        runner,
        [
            '-y',
            script_relative_path('../repository.yaml'),
            '--env',
            script_relative_path(
                '../environments/multi_mode_with_resources/double_adder_mode.yaml'
            ),
            '-d',
            'double_adder_mode',
            'multi_mode_with_resources',  # pipeline name
        ],
    )

    assert double_adder_result

def test_execute_preset_command():
    runner = CliRunner()
    add_result = runner_pipeline_execute(
        runner,
        [
            '-y',
            script_relative_path('../repository.yaml'),
            '-p',
            'add',
            'multi_mode_with_resources',  # pipeline name
        ],
    )

    assert 'PIPELINE_SUCCESS' in add_result.output

    # Can't use -p with --env
    bad_res = runner.invoke(
        pipeline_execute_command,
        [
            '-y',
            script_relative_path('../repository.yaml'),
            '-p',
            'add',
            '--env',
            script_relative_path(
                '../environments/multi_mode_with_resources/double_adder_mode.yaml'
            ),
            'multi_mode_with_resources',  # pipeline name
        ],
    )
    assert bad_res.exit_code == 2

def test_execute_command():
    for cli_args in valid_execute_args():
        execute_execute_command(env=None, cli_args=cli_args)

    for cli_args in valid_execute_args():
        execute_execute_command(
            env=[script_relative_path('default_log_error_env.yaml')], cli_args=cli_args
        )

    runner = CliRunner()

    for cli_args in valid_cli_args():
        runner_pipeline_execute(runner, cli_args)

        runner_pipeline_execute(
            runner, ['--env', script_relative_path('default_log_error_env.yaml')] + cli_args
        )

    res = runner.invoke(
        pipeline_execute_command,
        ['-y', script_relative_path('repository_module.yaml'), 'hello_cereal_pipeline', 'foo'],
    )
    assert res.exit_code == 1
    assert isinstance(res.exception, CheckError)
    assert 'Can only handle zero or one pipeline args.' in str(res.exception)

def test_stdout_execute_command():
    runner = CliRunner()
    result = runner_pipeline_execute(
        runner, ['-f', script_relative_path('test_cli_commands.py'), '-n', 'stdout_pipeline']
    )
    assert 'HELLO WORLD' in result.output

def test_stderr_execute_command():
    runner = CliRunner()
    result = runner_pipeline_execute(
        runner, ['-f', script_relative_path('test_cli_commands.py'), '-n', 'stderr_pipeline']
    )
    assert 'I AM SUPPOSED TO FAIL' in result.output

def test_fn_not_found_execute():
    with pytest.raises(DagsterInvariantViolationError) as exc_info:
        execute_execute_command(
            env=None,
            cli_args={
                'repository_yaml': None,
                'pipeline_name': (),
                'python_file': script_relative_path('test_cli_commands.py'),
                'module_name': None,
                'fn_name': 'nope',
            },
        )

    assert 'nope not found in module' in str(exc_info.value)

def not_a_repo_or_pipeline_fn():
    return 'kdjfkjdf'

not_a_repo_or_pipeline = 123

def test_fn_is_wrong_thing():
    with pytest.raises(DagsterInvariantViolationError) as exc_info:
        execute_execute_command(
            env={},
            cli_args={
                'repository_yaml': None,
                'pipeline_name': (),
                'python_file': script_relative_path('test_cli_commands.py'),
                'module_name': None,
                'fn_name': 'not_a_repo_or_pipeline',
            },
        )

    assert str(exc_info.value) == (
        'not_a_repo_or_pipeline must be a function that returns a '
        'PipelineDefinition or a RepositoryDefinition, or a function '
        'decorated with @pipeline.'
    )

def test_fn_returns_wrong_thing():
    with pytest.raises(DagsterInvariantViolationError) as exc_info:
        execute_execute_command(
            env={},
            cli_args={
                'repository_yaml': None,
                'pipeline_name': (),
                'python_file': script_relative_path('test_cli_commands.py'),
                'module_name': None,
                'fn_name': 'not_a_repo_or_pipeline_fn',
            },
        )

    assert str(exc_info.value) == (
        'not_a_repo_or_pipeline_fn is a function but must return a '
        'PipelineDefinition or a RepositoryDefinition, or be decorated '
        'with @pipeline.'
    )

def runner_pipeline_execute(runner, cli_args):
    result = runner.invoke(pipeline_execute_command, cli_args)
    if result.exit_code != 0:
        # CliRunner captures stdout so printing it out here
        raise Exception(
            (
                'dagster pipeline execute commands with cli_args {cli_args} '
                'returned exit_code {exit_code} with stdout:\n"{stdout}" and '
                '\nresult as string: "{result}"'
            ).format(
                cli_args=cli_args, exit_code=result.exit_code, stdout=result.stdout, result=result
            )
        )
    return result

def test_scaffold_command():
    for cli_args in valid_execute_args():
        cli_args['print_only_required'] = True
        execute_scaffold_command(cli_args=cli_args, print_fn=no_print)

        cli_args['print_only_required'] = False
        execute_scaffold_command(cli_args=cli_args, print_fn=no_print)

    runner = CliRunner()

    for cli_args in valid_cli_args():
        result = runner.invoke(pipeline_scaffold_command, cli_args)
        assert result.exit_code == 0

        result = runner.invoke(pipeline_scaffold_command, ['-p'] + cli_args)
        assert result.exit_code == 0

def test_default_memory_run_storage():
    cli_args = {
        'repository_yaml': script_relative_path('repository_file.yaml'),
        'pipeline_name': ('foo',),
        'python_file': None,
        'module_name': None,
        'fn_name': None,
    }
    result = execute_execute_command(env=None, cli_args=cli_args)
    assert result.success

def test_override_with_in_memory_storage():
    cli_args = {
        'repository_yaml': script_relative_path('repository_file.yaml'),
        'pipeline_name': ('foo',),
        'python_file': None,
        'module_name': None,
        'fn_name': None,
    }
    result = execute_execute_command(
        env=[script_relative_path('in_memory_env.yaml')], cli_args=cli_args
    )
    assert result.success

def test_override_with_filesystem_storage():
    cli_args = {
        'repository_yaml': script_relative_path('repository_file.yaml'),
        'pipeline_name': ('foo',),
        'python_file': None,
        'module_name': None,
        'fn_name': None,
    }
    result = execute_execute_command(
        env=[script_relative_path('filesystem_env.yaml')], cli_args=cli_args
    )
    assert result.success

def test_run_list():
    runner = CliRunner()
    result = runner.invoke(run_list_command)
    assert result.exit_code == 0

def test_run_wipe_correct_delete_message():
    runner = CliRunner()
    result = runner.invoke(run_wipe_command, input="DELETE\n")
    assert 'Deleted all run history and event logs' in result.output
    assert result.exit_code == 0

def test_run_wipe_incorrect_delete_message():
    runner = CliRunner()
    result = runner.invoke(run_wipe_command, input="WRONG\n")
    assert 'Exiting without deleting all run history and event logs' in result.output
    assert result.exit_code == 0

@schedules(scheduler=FilesytemTestScheduler)
def define_bar_scheduler():
    return [
        ScheduleDefinition(
            "foo_schedule",
            cron_schedule="* * * * *",
            pipeline_name="test_pipeline",
            environment_dict={},
        )
    ]

def test_schedules_list_without_dagster_home():
    runner = CliRunner()

    result = runner.invoke(
        schedule_list_command, ['-y', script_relative_path('repository_file.yaml')]
    )

    assert result.exit_code == 2
    assert 'Error: $DAGSTER_HOME is not set' in result.output

def test_schedules_list():
    runner = CliRunner()

    with seven.TemporaryDirectory() as temp_dir:
        with mock.patch.dict(os.environ, {"DAGSTER_HOME": temp_dir}):
            result = runner.invoke(
                schedule_list_command, ['-y', script_relative_path('repository_file.yaml')]
            )

            assert result.exit_code == 0
            assert result.output == ('Repository bar\n' '**************\n')

def test_schedules_up():
    runner = CliRunner()

    with seven.TemporaryDirectory() as temp_dir:
        with mock.patch.dict(os.environ, {"DAGSTER_HOME": temp_dir}):
            result = runner.invoke(
                schedule_up_command, ['-y', script_relative_path('repository_file.yaml')]
            )

            assert result.exit_code == 0
            assert result.output == 'Changes:\n  + foo_schedule (add)\n'

def test_schedules_up_and_list():
    runner = CliRunner()

    with seven.TemporaryDirectory() as temp_dir:
        with mock.patch.dict(os.environ, {"DAGSTER_HOME": temp_dir}):
            result = runner.invoke(
                schedule_up_command, ['-y', script_relative_path('repository_file.yaml')]
            )

            result = runner.invoke(
                schedule_list_command, ['-y', script_relative_path('repository_file.yaml')]
            )

            assert result.exit_code == 0
            assert (
                result.output == 'Repository bar\n'
                '**************\n'
                'Schedule: foo_schedule [STOPPED]\n'
                'Cron Schedule: * * * * *\n'
            )

def test_schedules_start_and_stop():
    runner = CliRunner()

    with seven.TemporaryDirectory() as temp_dir:
        with mock.patch.dict(os.environ, {"DAGSTER_HOME": temp_dir}):
            result = runner.invoke(
                schedule_up_command, ['-y', script_relative_path('repository_file.yaml')]
            )

            result = runner.invoke(
                schedule_start_command,
                ['-y', script_relative_path('repository_file.yaml'), 'foo_schedule'],
            )

            assert result.exit_code == 0
            assert 'Started schedule foo_schedule with ' in result.output

            result = runner.invoke(
                schedule_stop_command,
                ['-y', script_relative_path('repository_file.yaml'), 'foo_schedule'],
            )

            assert result.exit_code == 0
            assert 'Stopped schedule foo_schedule with ' in result.output

def test_schedules_start_all():
    runner = CliRunner()
    with seven.TemporaryDirectory() as temp_dir:
        with mock.patch.dict(os.environ, {"DAGSTER_HOME": temp_dir}):
            result = runner.invoke(
                schedule_up_command, ['-y', script_relative_path('repository_file.yaml')]
            )

            result = runner.invoke(
                schedule_start_command,
                ['-y', script_relative_path('repository_file.yaml'), '--start-all'],
            )

            assert result.exit_code == 0
            assert result.output == 'Started all schedules for repository bar\n'

def test_schedules_wipe_correct_delete_message():
    runner = CliRunner()

    with seven.TemporaryDirectory() as temp_dir:
        with mock.patch.dict(os.environ, {"DAGSTER_HOME": temp_dir}):
            result = runner.invoke(
                schedule_up_command, ['-y', script_relative_path('repository_file.yaml')]
            )

            result = runner.invoke(
                schedule_wipe_command,
                ['-y', script_relative_path('repository_file.yaml')],
                input="DELETE\n",
            )

            assert result.exit_code == 0
            assert 'Wiped all schedules and schedule cron jobs' in result.output

            result = runner.invoke(
                schedule_up_command,
                ['-y', script_relative_path('repository_file.yaml'), '--preview'],
            )

            # Verify schedules were wiped
            assert result.exit_code == 0
            assert result.output == 'Planned Changes:\n  + foo_schedule (add)\n'

def test_schedules_wipe_incorrect_delete_message():
    runner = CliRunner()

    with seven.TemporaryDirectory() as temp_dir:
        with mock.patch.dict(os.environ, {"DAGSTER_HOME": temp_dir}):
            result = runner.invoke(
                schedule_up_command, ['-y', script_relative_path('repository_file.yaml')]
            )

            result = runner.invoke(
                schedule_wipe_command,
                ['-y', script_relative_path('repository_file.yaml')],
                input="WRONG\n",
            )

            assert result.exit_code == 0
            assert 'Exiting without deleting all schedules and schedule cron jobs' in result.output

            result = runner.invoke(
                schedule_up_command,
                ['-y', script_relative_path('repository_file.yaml'), '--preview'],
            )

            # Verify schedules were not wiped
            assert result.exit_code == 0
            assert (
                result.output
                == 'No planned changes to schedules.\n1 schedules will remain unchanged\n'
            )

def test_schedules_restart():
    runner = CliRunner()

    with seven.TemporaryDirectory() as temp_dir:
        with mock.patch.dict(os.environ, {"DAGSTER_HOME": temp_dir}):
            result = runner.invoke(
                schedule_up_command, ['-y', script_relative_path('repository_file.yaml')]
            )

            result = runner.invoke(
                schedule_start_command,
                ['-y', script_relative_path('repository_file.yaml'), 'foo_schedule'],
            )

            result = runner.invoke(
                schedule_restart_command,
                ['-y', script_relative_path('repository_file.yaml'), 'foo_schedule'],
            )

            assert result.exit_code == 0
            assert 'Restarted schedule foo_schedule' in result.output

def test_schedules_restart_all():
    runner = CliRunner()

    with seven.TemporaryDirectory() as temp_dir:
        with mock.patch.dict(os.environ, {"DAGSTER_HOME": temp_dir}):
            result = runner.invoke(
                schedule_up_command, ['-y', script_relative_path('repository_file.yaml')]
            )

            result = runner.invoke(
                schedule_start_command,
                ['-y', script_relative_path('repository_file.yaml'), 'foo_schedule'],
            )

            result = runner.invoke(
                schedule_restart_command,
                [
                    '-y',
                    script_relative_path('repository_file.yaml'),
                    'foo_schedule',
                    '--restart-all-running',
                ],
            )

            assert result.exit_code == 0
            assert result.output == 'Restarted all running schedules for repository bar\n'

def test_multiproc():
    with seven.TemporaryDirectory() as temp:
        runner = CliRunner(env={'DAGSTER_HOME': temp})
        add_result = runner_pipeline_execute(
            runner,
            [
                '-y',
                script_relative_path('../repository.yaml'),
                '-p',
                'multiproc',
                'multi_mode_with_resources',  # pipeline name
            ],
        )
        assert 'PIPELINE_SUCCESS' in add_result.output

def test_multiproc_invalid():
    # force ephemeral instance by removing out DAGSTER_HOME
    runner = CliRunner(env={'DAGSTER_HOME': None})
    add_result = runner_pipeline_execute(
        runner,
        [
            '-y',
            script_relative_path('../repository.yaml'),
            '-p',
            'multiproc',
            'multi_mode_with_resources',  # pipeline name
        ],
    )
    # which is invalid for multiproc
    assert 'DagsterUnmetExecutorRequirementsError' in add_result.output

class InMemoryRunLauncher(RunLauncher, ConfigurableClass):
    def __init__(self, inst_data=None):
        self._inst_data = inst_data
        self._queue = []

    def launch_run(self, _instance, run):
        self._queue.append(run)
        return run

    def queue(self):
        return self._queue

    @classmethod
    def config_type(cls):
        return Shape({})

    @classmethod
    def from_config_value(cls, inst_data, config_value):
        return cls(inst_data=inst_data,)

    @property
    def inst_data(self):
        return self._inst_data

@repository_partitions
def define_baz_partitions():
    return [
        PartitionSetDefinition(
            name='baz_partitions', pipeline_name='baz', partition_fn=lambda: string.ascii_lowercase,
        )
    ]

def backfill_execute_args(execution_args):
    backfill_args = {
        'repository_yaml': script_relative_path('repository_file.yaml'),
        'noprompt': True,
    }
    pipeline_name = execution_args.get('pipeline_name')
    if pipeline_name:
        backfill_args['pipeline_name'] = (pipeline_name,)
    for name, value in execution_args.items():
        if name != 'pipeline_name':
            backfill_args[name] = value
    return backfill_args

def backfill_cli_runner_args(execution_args):
    backfill_args = ['-y', script_relative_path('repository_file.yaml'), '--noprompt']
    pipeline_name = execution_args.get('pipeline_name')
    if pipeline_name:
        backfill_args.append(pipeline_name)
    for name, value in execution_args.items():
        if name != 'pipeline_name':
            backfill_args.extend(['--{}'.format(name.replace('_', '-')), value])
    return backfill_args

def run_test_backfill(
    execution_args, expected_count=None, error_message=None, use_run_launcher=True
):
    runner = CliRunner()
    run_launcher = InMemoryRunLauncher() if use_run_launcher else None
    with seven.TemporaryDirectory() as temp_dir:
        instance = DagsterInstance(
            instance_type=InstanceType.EPHEMERAL,
            local_artifact_storage=LocalArtifactStorage(temp_dir),
            run_storage=InMemoryRunStorage(),
            event_storage=InMemoryEventLogStorage(),
            compute_log_manager=NoOpComputeLogManager(temp_dir),
            run_launcher=run_launcher,
        )
        with mock.patch('dagster.core.instance.DagsterInstance.get') as _instance:
            _instance.return_value = instance

            if error_message:
                with pytest.raises(UsageError) as error_info:
                    execute_backfill_command(backfill_execute_args(execution_args), no_print)
                assert error_info and error_message in error_info.value.message

            result = runner.invoke(
                pipeline_backfill_command, backfill_cli_runner_args(execution_args)
            )
            if error_message:
                assert result.exit_code == 2
            else:
                assert result.exit_code == 0
                if expected_count:
                    assert len(run_launcher.queue()) == expected_count

def test_backfill_no_run_launcher():
    args = {'pipeline_name': 'baz'}  # legit partition args
    run_test_backfill(
        args, use_run_launcher=False, error_message='A run launcher must be configured'
    )

def test_backfill_no_pipeline():
    args = {'pipeline_name': 'nonexistent'}
    run_test_backfill(args, error_message='No pipeline found')

def test_backfill_no_partition_sets():
    args = {'pipeline_name': 'foo'}
    run_test_backfill(args, error_message='No partition sets found')

def test_backfill_no_named_partition_set():
    args = {'pipeline_name': 'baz', 'partition_set': 'nonexistent'}
    run_test_backfill(args, error_message='No partition set found')

def test_backfill_launch():
    args = {'pipeline_name': 'baz', 'partition_set': 'baz_partitions'}
    run_test_backfill(args, expected_count=len(string.ascii_lowercase))

def test_backfill_partition_range():
    args = {'pipeline_name': 'baz', 'partition_set': 'baz_partitions', 'from': 'x'}
    run_test_backfill(args, expected_count=3)

    args = {'pipeline_name': 'baz', 'partition_set': 'baz_partitions', 'to': 'c'}
    run_test_backfill(args, expected_count=3)

    args = {'pipeline_name': 'baz', 'partition_set': 'baz_partitions', 'from': 'c', 'to': 'f'}
    run_test_backfill(args, expected_count=4)

def test_backfill_partition_enum():
    args = {'pipeline_name': 'baz', 'partition_set': 'baz_partitions', 'partitions': 'c,x,z'}
    run_test_backfill(args, expected_count=3)


import pygame,sys
from Room import Room,Overworld

class Game:
    def __init__(self) -> None:
        self.overworld = Overworld(screen,self.start_game)
        self.status = 'overworld'
        self.current_room = 0

    def start_game(self):
        self.room = Room(self.current_room, self.create_overworld)
        self.status = "game_running"

    def create_overworld(self):
        self.overworld = Overworld(screen,self.start_game)
        self.status = 'overworld'

    def run(self):
        if self.status == 'overworld':
            self.overworld.run()
        else:
            self.room.run()

pygame.init()
screen = pygame.display.set_mode((900,506))
pygame.display.set_caption('Text Based Game')
game = Game()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    game.run()
    pygame.display.update()


from flask.ext.mongokit import MongoKit, Document
from datetime import datetime
from sensorapp import db, app

@db.register
class Device(Document):
    __database__ = app.config["DB_NAME"]
    __collection__ = "device"
    structure = {
        'name': unicode,
        'digit_pin_num': int,
        'analog_pin_num': int,
        'type': unicode,
        'location': unicode,
        'sensor_list': list,
        'actuator_list': list,
        'created_user':unicode,
        'created_time': datetime
    }
    required_fields = ['name', 'created_time']
    default_values = {'created_time': datetime.utcnow()}
    use_dot_notation = True

@db.register
class Sensor(Document):
    __database__ = app.config["DB_NAME"]
    __collection__ = "sensor"
    structure = {
        'name': unicode,
        'type': unicode,
        'digit_or_analog': unicode,
        'location': unicode,
        'ability': unicode,
        'at_device_id': unicode,
        'at_device_name': unicode,
        'at_pin': int,
        'created_user': unicode,
        'created_time': datetime
    }
    required_fields = ['name', 'created_time']
    default_values = {'created_time': datetime.utcnow()}
    use_dot_notation = True

@db.register
class Actuator(Document):
    __database__ = app.config["DB_NAME"]
    __collection__ = "actuator"
    structure = {
        'name': unicode,
        'type': unicode,
        'digit_or_analog': unicode,
        'location': unicode,
        'ability': unicode,
        'at_device_id': unicode,
        'at_device_name': unicode,
        'at_pin': int,
        'created_user': unicode,
        'created_time': datetime
    }
    required_fields = ['name', 'created_time']
    default_values = {'created_time': datetime.utcnow()}
    use_dot_notation = True

@db.register
class SensorData(Document):
    __database__ = app.config["DB_NAME"]
    __collection__ = "sensordata"
    structure = {
        'value': float,
        'from_sensor_id': unicode,
        'from_sensor_name': unicode,
        'sensing_time': datetime,
        'created_time': datetime
    }
    required_fields = ['value', 'from_sensor_name', 'sensing_time' ,'created_time']
    default_values = {'created_time': datetime.utcnow()}
    use_dot_notation = True

@db.register
class ActuatorData(Document):
    __database__ = app.config["DB_NAME"]
    __collection__ = "actuatordata"
    structure = {
        'value': float,
        'from_actuator_id': unicode,
        'from_actuator_name': unicode,
        'created_by': unicode,
        'acting_time': datetime,
        'created_time': datetime
    }
    required_fields = ['value', 'from_actuator_name', 'acting_time' ,'created_time']
    default_values = {'created_time': datetime.utcnow()}
    use_dot_notation = True

db.register([Device])
db.register([Sensor])
db.register([Actuator])
db.register([SensorData])
db.register([ActuatorData])


#Healthy programmer
# 9am - 5pm
# Water = water.mp3 (3.5 liters)every 40min - Drank - log
# Eyes = eyes.mp3 (Every 30 min) - EyesDone - log
# Pysical Activity = pysical.mp3 (every 45 min)- ExDone - log
#
# Rules - pygame module to play audio

from pygame import mixer
from datetime import datetime
from time import time

def musiconloop(file,stopper):
    mixer.init()
    mixer.music.load(file)
    mixer.music.play()
    while True:
        input_of_user = input()
        if input_of_user == stopper:
            mixer.music.stop()
            break

def log_now(msg):
    with open("mylogs.txt","a") as f:
        f.write(f"{msg} {datetime.now()}\n")

if __name__ == '__main__':

    init_waters = time()
    init_eyes = time()
    init_exercise = time()
    watersecs = 10  #40min
    eyessecs = 30  #30 min
    exsecs = 50    #45 min

    while True:
        if time() - init_waters > watersecs:
            print ("Drink Water!! ..Write 'drank' to stop the alarm")
            musiconloop('waters.mp3' ,'drank')
            init_waters = time()
            log_now("Drank water at")

        if time() - init_eyes > eyessecs:
            print ("Eyes Exercise time!! ..Write 'doneeyes' to stop the alarm")
            musiconloop('eyes.mp3' ,'doneeyes')
            init_eyes = time()
            log_now("Eyes relaxed done at")

        if time() - init_exercise > exsecs:
            print ("Exercise Time!! ..Write 'doneex' to stop the alarm")
            musiconloop('excercise.mp3' ,'doneex')
            init_exercise = time()
            log_now("Exercise done at")


#coding: utf-8

import pygame
from block import Block
import constants

#insert this class in ship method gen_shoot()
class Bullet(Block):
	def __init__(self,x,y, sign, speed, targets_nopoints= None, targets_points=None, point_receptor=None):
		super(Bullet, self).__init__(x,y,10,10,constants.YELLOW)
		self.dir_x = 0
		self.dir_y = -1*sign*speed
		#Next 2 shall be pygame.sprite.Group()...
		if isinstance(targets_nopoints, pygame.sprite.Group):
			self.t_n_points= targets_nopoints
		else:

			self.t_n_points= None
		if isinstance(targets_points, pygame.sprite.Group):
			self.t_w_points= targets_points		#must have self.value...
			self.point_receptor=point_receptor	#must have change_points_by(x) method
		else:
			self.t_w_points= None

	def update(self):
		#always go up
		self.rect.y += self.dir_y
		#verify if within bounds
		if self.rect.y < 0 or self.rect.y >= constants.SCREEN_HEIGHT:
			self.kill() #removes from ALL the pygame's Groups
			del self
			return

		if self.t_n_points != None:
			collision_list = pygame.sprite.spritecollide(self, self.t_n_points, True)
			#Having spritecollide set to True destroys obstacles
			if len(collision_list)>0:
				self.kill()

		if self.t_w_points != None:
			collision_list = pygame.sprite.spritecollide(self, self.t_w_points, True)
			#Having spritecollide set to True destroys obstacles
			if len(collision_list)>0:
				self.kill()
				for el in collision_list:
					self.point_receptor.change_points_by(el.value)


"""This file contains the signature validator abstraction"""

import base64
import json

from cose.headers import KID
from cose.keys.keyops import VerifyOp
from cose.messages import Sign1Message
from cose.keys import CoseKey
from cose.algorithms import Es256, Ps256
from cose.keys.keytype import KtyEC2, KtyRSA
from cose.keys.keyparam import KpKty, KpKeyOps
from cose.keys.keyparam import KpAlg, EC2KpX, EC2KpY, EC2KpCurve, RSAKpE, RSAKpN
from cose.keys.curves import P256
from cose.exceptions import CoseException
from cryptography import x509
from cryptography.hazmat.primitives.asymmetric import ec, rsa
from cryptography.utils import int_to_bytes

from classes.TrustList import TrustList

class SignatureValidator:
    """Validate COSE signatures"""
    def __init__(self, trust_list: TrustList):
        self._trust_list = trust_list

    def validate(self, payload: bytes):
        """Validates the signature, or returns the errors"""
        try:
            message = Sign1Message.decode(payload)
            kid = self._get_kid(message)
            print(f"KID = {kid}")
            dsc = self._trust_list.find(kid)
            cert: x509.base = dsc.certificate()
            if cert is None:
                return {
                    "valid": False,
                    "error": {
                        "type": "TRUST-LIST",
                        "message": f"KID {kid} not found in the trust-list"
                    }
                }
            message.key = self._get_key(cert)
            if message.verify_signature():
                return {
                    "valid": True,
                    "error": None
                }
            return {
                "valid": False,
                "error": "Invalid signature! Reason: unknown."
            }
        except UnicodeDecodeError as err:
            return {
                "valid": False,
                "error": {
                    "type": "UNICODE",
                    "message": err
                }
            }
        except json.decoder.JSONDecodeError as err:
            return {
                "valid": False,
                "error": {
                    "type": "JSON",
                    "message": err
                }
            }
        except (CoseException, AttributeError, TypeError) as err:
            return {
                "valid": False,
                "error": {
                    "type": "COSE",
                    "message": err
                }
            }

    @staticmethod
    def _get_kid(message) -> str:
        """Returns the KID from the message"""
        if KID in message.phdr.keys():
            return base64.b64encode(message.phdr[KID]).decode("UTF-8")
        return base64.b64encode(message.uhdr[KID]).decode("UTF-8")

    @staticmethod
    def _get_key(cert: x509.base) -> CoseKey:
        """Returns the CoseKey"""
        if isinstance(cert.public_key(), rsa.RSAPublicKey):
            return CoseKey.from_dict(
                {
                    KpKeyOps: [VerifyOp],
                    KpKty: KtyRSA,
                    KpAlg: Ps256,  # RSSASSA-PSS-with-SHA-256-and-MFG1
                    RSAKpE: int_to_bytes(cert.public_key().public_numbers().e),
                    RSAKpN: int_to_bytes(cert.public_key().public_numbers().n)
                }
            )
        elif isinstance(cert.public_key(), ec.EllipticCurvePublicKey):
            return CoseKey.from_dict(
                {
                    KpKeyOps: [VerifyOp],
                    KpKty: KtyEC2,
                    EC2KpCurve: P256,  # Ought o be pk.curve - but the two libs clash
                    KpAlg: Es256,  # ecdsa-with-SHA256
                    EC2KpX: int_to_bytes(cert.public_key().public_numbers().x),
                    EC2KpY: int_to_bytes(cert.public_key().public_numbers().y)
                }
            )
        else:
            raise Exception(f"Algorithm unsupported: { cert.signature_algorithm_oid }")


#!/usr/bin/env python3
#
# Bonus. GPE auto-training + GSA using external (from publication) dataset loaded from json file
#
import os

from gpytorch.likelihoods import GaussianLikelihood
from gpytorch.means import LinearMean
from gpytorch.kernels import MaternKernel, ScaleKernel

from GPErks.gp.data.dataset import Dataset
from GPErks.gp.experiment import GPExperiment
from GPErks.gp.mean import LinearMean
from GPErks.log.logger import get_logger
from GPErks.serialization.path import posix_path
from GPErks.train.emulator import GPEmulator
from GPErks.utils.random import set_seed
from GPErks.perks.gsa import SobolGSA

def main():
    get_logger()
    seed = 8
    set_seed(seed)

    device = "cpu"

    # This new method loads your dataset into a dictionary where keys = features, values = Dataset objects
    # (each Dataset is built to create the experiment that will emulate the corresponding scalar feature (key))
    datasets = Dataset.build_from_file(posix_path(os.getcwd(), "data", "datasets", "Stefano_8p_sham.json"))
    features = list(datasets.keys())
    print(features)  # available features to be emulated

    # # Note: if you want to create a .json file containing your dataset, you can do so like this:
    # X = np.loadtxt(data_dir / "X.txt", dtype=float)
    # Y = np.loadtxt(data_dir / "Y.txt", dtype=float)
    # xlabels = read_labels_from_file(data_dir / "xlabels.txt")
    # ylabels = read_labels_from_file(data_dir / "ylabels.txt")
    # data_dct = {
    #     "X_train": X.tolist(),
    #     "Y_train": Y.tolist(),
    #     # "X_val": X_val.tolist(), # (if available, otherwise can omit this dct key)
    #     # "Y_val": Y_val.tolist(), # (if available, otherwise can omit this dct key)
    #     # "X_test": X_test.tolist(), # (if available, otherwise can omit this dct key)
    #     # "Y_test": Y_test.tolist(), # (if available, otherwise can omit this dct key)
    #     "x_labels": xlabels,  # (if available, otherwise can omit this dct key)
    #     "y_labels": ylabels,  # (if available, otherwise can omit this dct key)
    #     # "l_bounds": a list here (if available, otherwise can omit this dct key)
    #     # "u_bounds": a list here (if available, otherwise can omit this dct key)
    #     "info": "A short description about the dataset"
    # }
    # with open(Path(os.getcwd())/"datasetname.json", "w") as f:
    #     json.dump(data_dct, f, indent=4)
    #
    # # Also note that there is already a utility function that does this for you:
    # # from GPErks.utils.jsonfiles import create_json_dataset_from_arrays

    feature = "EDV"  # we will emulate just one feature as an example

    # GPE auto-training
    print(f"\nEmulating target feature: {feature}")
    dataset = datasets[feature]

    likelihood = GaussianLikelihood()
    mean = LinearMean(degree=1, input_size=dataset.input_size, bias=True)
    covariance = ScaleKernel(MaternKernel(ard_num_dims=dataset.input_size))
    metrics = []

    experiment = GPExperiment(
        dataset,
        likelihood,
        mean,
        covariance,
        metrics=metrics,
        seed=seed
    )

    emulator = GPEmulator(experiment, device)
    emulator.train_auto()  # you could use a more manual approach here with early stopping etc.
    msg = experiment.print_stats()
    print(f"\nFitted emulator hyperparameters:{msg}")

    # GSA
    gsa = SobolGSA(dataset, n=1024, seed=seed)
    # the following method is used to perform GSA whenever a (trained) emulator object is available, also covering
    # the case where it was trained using an externally imported dataset as in this example
    gsa.estimate_Sobol_indices_with_emulator(emulator, n_draws=1000)
    gsa.summary()

    gsa.correct_Sobol_indices(threshold=0.01)
    gsa.plot()
    gsa.plot_donut()
    gsa.plot_fancy_donut()
    gsa.plot_heatmap()
    gsa.plot_network()

if __name__ == "__main__":
    main()


from spectractor import parameters
from spectractor.simulation.simulator import AtmosphereGrid, SpectrumSimulatorSimGrid
from spectractor.config import load_config
from spectractor.simulation.image_simulation import ImageSim
from spectractor.logbook import LogBook
from spectractor.extractor.extractor import Spectractor

if __name__ == "__main__":
    from argparse import ArgumentParser

    parser = ArgumentParser()
    parser.add_argument(dest="input", metavar='path', default=["tests/data/reduc_20170530_134.fits"],
                        help="Input fits file name. It can be a list separated by spaces, or it can use * as wildcard.",
                        nargs='*')
    parser.add_argument("-d", "--debug", dest="debug", action="store_true",
                        help="Enter debug mode (more verbose and plots).", default=False)
    parser.add_argument("-v", "--verbose", dest="verbose", action="store_true",
                        help="Enter verbose (print more stuff).", default=False)
    parser.add_argument("-o", "--output_directory", dest="output_directory", default="outputs/",
                        help="Write results in given output directory (default: ./outputs/).")
    parser.add_argument("-l", "--logbook", dest="logbook", default="./tests/data/ctiofulllogbook_jun2017_v5.csv",
                        help="CSV logbook file. (default: ./tests/data/ctiofulllogbook_jun2017_v5.csv).")
    parser.add_argument("-c", "--config", dest="config", default="config/ctio.ini",
                        help="INI config file. (default: config.ctio.ini).")
    args = parser.parse_args()

    parameters.VERBOSE = args.verbose
    if args.debug:
        parameters.DEBUG = True
        parameters.VERBOSE = True

    file_names = args.input

    load_config(args.config)
    logbook = LogBook(logbook=args.logbook)

    for file_name in file_names:
        tag = file_name.split('/')[-1]
        disperser_label, target, xpos, ypos = logbook.search_for_image(tag)
        if target is None or xpos is None or ypos is None:
            continue
        spectrum_file_name = args.output_directory + '/' + tag.replace('.fits', '_spectrum.fits')
        atmgrid = AtmosphereGrid(file_name)
        image = ImageSim(file_name, spectrum_file_name, args.output_directory, A1=1, A2=1,
                         pwv=5, ozone=300, aerosols=0.03,
                         psf_poly_params=None, with_stars=True)
        sim_file_name = args.output_directory + tag.replace('reduc_', 'sim_')
        Spectractor(sim_file_name, args.output_directory, target, [xpos, ypos], disperser_label, args.config)


import json
import re

from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QFileDialog, QListWidgetItem, QColorDialog

from models.const import *
from models import util
from uis.main_window import Ui_MainWindow

class SettingsController(object):

	def __init__(self, app=None, ui: Ui_MainWindow = None, main_controller=None):
		self.app = app
		self.ui = ui
		self.main_controller = main_controller
		self.setup_control()
		pass

	def setup_control(self):
		self.ui.cbx_settings_reader_auto_play_pgb.addItems([TRSM("No"),TRSM("Yes")])
		self.ui.cbx_settings_proxy_mode.addItems([TRSM("Disable proxy"),TRSM("Use proxy and not proxy same time"),TRSM("Only use proxy")])
		self.ui.cbx_settings_proxy_type.addItems([TRSM("https"),TRSM("http")])
		self.ui.cbx_settings_cugan_denoise.addItems([TRSM("No effect"),TRSM("Level 0"),TRSM("Level 1"),TRSM("Level 2"),TRSM("Level 3")])
		self.ui.cbx_settings_cugan_resize.addItems([TRSM("No"),TRSM("Yes")])
		self.ui.cbx_settings_when_close_window.addItems([TRSM("Minimize to system tray"),TRSM("Close window")])

		# UI Display
		self.retranslateUi()
		self.load_config()

		# action
		self.ui.btn_settings_save.clicked.connect(self.btn_settings_save_clicked)
		self.ui.btn_settings_reset.clicked.connect(self.btn_settings_reset_clicked)
		self.ui.btn_settings_general_folder.clicked.connect(self.btn_settings_general_folder_clicked)
		self.ui.btn_settings_proxy_add.clicked.connect(self.btn_settings_proxy_add_clicked)
		self.ui.btn_settings_proxy_delete.clicked.connect(self.btn_settings_proxy_delete_clicked)
		self.ui.btn_settings_cugan_browser.clicked.connect(self.btn_settings_cugan_browser_clicked)
		self.ui.btn_settings_reader_background.clicked.connect(self.btn_settings_reader_background_clicked)
		self.ui.txt_settings_reader_background.textChanged.connect(self.txt_settings_reader_background_text_changed)

	def retranslateUi(self):
		self.ui.cbx_settings_reader_auto_play_pgb.setItemText(0,TRSM("No"))
		self.ui.cbx_settings_reader_auto_play_pgb.setItemText(1,TRSM("Yes"))

		self.ui.cbx_settings_proxy_mode.setItemText(0,TRSM("Disable proxy"))
		self.ui.cbx_settings_proxy_mode.setItemText(1,TRSM("Use proxy and not proxy same time"))
		self.ui.cbx_settings_proxy_mode.setItemText(2,TRSM("Only use proxy"))

		self.ui.cbx_settings_cugan_denoise.setItemText(0,TRSM("No effect"))
		self.ui.cbx_settings_cugan_denoise.setItemText(1,TRSM("Level 0"))
		self.ui.cbx_settings_cugan_denoise.setItemText(2,TRSM("Level 1"))
		self.ui.cbx_settings_cugan_denoise.setItemText(3,TRSM("Level 2"))
		self.ui.cbx_settings_cugan_denoise.setItemText(4,TRSM("Level 3"))

		self.ui.cbx_settings_cugan_resize.setItemText(0,TRSM("No"))
		self.ui.cbx_settings_cugan_resize.setItemText(1,TRSM("Yes"))

		self.ui.cbx_settings_when_close_window.setItemText(0,TRSM("Minimize to system tray"))
		self.ui.cbx_settings_when_close_window.setItemText(1,TRSM("Close window"))

		pass

	#action
	def btn_settings_general_folder_clicked(self):
		old_folder_path = self.ui.txt_settings_general_folder.text()
		if old_folder_path == "":
			old_folder_path = "./"
		folder_path = QFileDialog.getExistingDirectory(self.main_controller,TRSM("Open folder"), old_folder_path)
		if folder_path != "":
			self.ui.txt_settings_general_folder.setText(folder_path)
		pass

	def btn_settings_reader_background_clicked(self):
		old_color = QColor(self.ui.txt_settings_reader_background.text())
		color = QColorDialog.getColor(old_color,self.main_controller,TRSM("Pick a color"))
		if color.isValid():
			color_name = color.name()
			self.ui.txt_settings_reader_background.setText(color_name)
			self.ui.lbl_settings_reader_background_preview.setStyleSheet("background-color: "+color_name+";")

	def btn_settings_cugan_browser_clicked(self):
		old_file_path = self.ui.txt_settings_cugan_location.text()
		if old_file_path == "":
			old_file_path = "./"
		file_path = QFileDialog.getOpenFileName(self.main_controller,TRSM("EXE location"), old_file_path)
		if len(file_path) >= 2 and file_path[0] != "":
			self.ui.txt_settings_cugan_location.setText(file_path[0])

	def btn_settings_proxy_add_clicked(self):
		if self.ui.txt_settings_proxy_ip.text() != "":
			proxy = self.ui.cbx_settings_proxy_type.currentText() + "://" + self.ui.txt_settings_proxy_ip.text()
			if not self.check_proxy_format(proxy):
				util.msg_box(TRSM("Please enter a proxy with ip:port format"), self.main_controller)
			elif self.check_proxy_exist_in_list(proxy):
				util.msg_box(TRSM("Proxy already exist in list"), self.main_controller)
			else:
				self.try_add_proxy(proxy)
				self.ui.txt_settings_proxy_ip.setText("")
		else:
			util.msg_box(TRSM("Please enter a proxy with ip:port format"),self.main_controller)
			pass

	def btn_settings_proxy_delete_clicked(self):
		if len(self.ui.list_settings_proxy.selectedItems()) > 0:
			if util.confirm_box(TRSM("Confirm delete these proxy?"),self.main_controller):
				for item in self.ui.list_settings_proxy.selectedItems():
					self.ui.list_settings_proxy.takeItem(self.ui.list_settings_proxy.row(item))
		else:
			util.msg_box(TRSM("Please select at least one proxy"),self.main_controller)
		pass

	def btn_settings_save_clicked(self):
		self.save_config()

	def btn_settings_reset_clicked(self):
		self.ui.spin_settings_max_retry.setValue(5)
		self.ui.spin_settings_timeout.setValue(30)

		self.ui.spin_settings_book_padding.setValue(2)
		self.ui.spin_settings_chapter_padding.setValue(3)
		self.ui.spin_settings_image_padding.setValue(3)
		self.ui.spin_settings_jpg_quality.setValue(90)
		self.ui.spin_settings_check_is_2_page.setValue(1.0)
		self.ui.txt_settings_reader_background.setText("#000000")
		self.ui.spin_settings_reader_auto_play_interval.setValue(5.0)
		self.ui.cbx_settings_reader_auto_play_pgb.setCurrentIndex(1)
		self.ui.spin_settings_reader_page_gap.setValue(0)

		self.ui.spin_settings_page_sleep.setValue(10)
		self.ui.spin_settings_image_sleep.setValue(1)
		self.ui.spin_settings_download_worker.setValue(2)
		self.ui.cbx_settings_proxy_mode.setCurrentIndex(0)

		self.ui.spin_settings_cugan_scale.setValue(2)
		self.ui.cbx_settings_cugan_denoise.setCurrentIndex(4)
		self.ui.cbx_settings_cugan_resize.setCurrentIndex(0)

		self.ui.cbx_settings_when_close_window.setCurrentIndex(0)

		pass

	def txt_settings_reader_background_text_changed(self):
		color_str = self.ui.txt_settings_reader_background.text()
		q_color = QColor(color_str)
		if q_color.isValid():
			self.ui.lbl_settings_reader_background_preview.setStyleSheet("background-color: " + color_str)

	# internal
	def load_config(self):
		#general
		download_folder = MY_CONFIG.get("general", "download_folder")
		self.ui.txt_settings_general_folder.setText(download_folder)
		max_retry = MY_CONFIG.get("general", "max_retry")
		self.ui.spin_settings_max_retry.setValue(int(max_retry))
		timeout = MY_CONFIG.get("general", "timeout")
		self.ui.spin_settings_timeout.setValue(float(timeout))

		self.ui.cbx_settings_user_agent.addItems([
			"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0",
			"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36",
		])
		# "Mozilla/5.0 (iPad; CPU OS 8_0_2 like Mac OS X) AppleWebKit/60.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A405 Safari/600.1.4",
		# "Mozilla/5.0 (iPhone; CPU iPhone OS 13_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.2 Mobile/15E148 Safari/604.1",
		# "Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.58 Mobile Safari/537.36"

		agent = MY_CONFIG.get("general", "agent")
		self.ui.cbx_settings_user_agent.setCurrentText(agent)

		book_padding = MY_CONFIG.get("general", "book_padding")
		self.ui.spin_settings_book_padding.setValue(int(book_padding))
		chapter_padding = MY_CONFIG.get("general", "chapter_padding")
		self.ui.spin_settings_chapter_padding.setValue(int(chapter_padding))
		image_padding = MY_CONFIG.get("general", "image_padding")
		self.ui.spin_settings_image_padding.setValue(int(image_padding))
		jpg_quality = MY_CONFIG.get("general", "jpg_quality")
		self.ui.spin_settings_jpg_quality.setValue(int(jpg_quality))
		check_is_2_page = MY_CONFIG.get("general", "check_is_2_page")
		self.ui.spin_settings_check_is_2_page.setValue(float(check_is_2_page))

		reader_background = MY_CONFIG.get("reader", "background")
		self.ui.txt_settings_reader_background.setText(reader_background)
		self.ui.lbl_settings_reader_background_preview.setStyleSheet("background-color:"+reader_background+";")
		reader_auto_play_interval = MY_CONFIG.get("reader", "auto_play_interval")
		self.ui.spin_settings_reader_auto_play_interval.setValue(float(reader_auto_play_interval))
		reader_auto_play_pgb = MY_CONFIG.get("reader", "auto_play_pgb")
		self.ui.cbx_settings_reader_auto_play_pgb.setCurrentIndex(int(reader_auto_play_pgb))
		reader_page_gap = MY_CONFIG.get("reader", "page_gap")
		self.ui.spin_settings_reader_page_gap.setValue(int(reader_page_gap))

		#anti ban
		page_sleep = MY_CONFIG.get("anti-ban", "page_sleep")
		self.ui.spin_settings_page_sleep.setValue(float(page_sleep))
		image_sleep = MY_CONFIG.get("anti-ban", "image_sleep")
		self.ui.spin_settings_image_sleep.setValue(float(image_sleep))
		download_worker = MY_CONFIG.get("anti-ban", "download_worker")
		self.ui.spin_settings_download_worker.setValue(int(download_worker))
		proxy_mode = MY_CONFIG.get("anti-ban", "proxy_mode")
		self.ui.cbx_settings_proxy_mode.setCurrentIndex(int(proxy_mode))
		proxy_list = MY_CONFIG.get("anti-ban", "proxy_list")
		if proxy_list != "":
			proxy_list = json.loads(proxy_list)
			for proxy in proxy_list:
				item = QListWidgetItem()
				item.setText(proxy["url"])
				item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
				if proxy["enable"]:
					item.setCheckState(QtCore.Qt.Checked)
				else:
					item.setCheckState(QtCore.Qt.Unchecked)
				self.ui.list_settings_proxy.addItem(item)

		#real-cugan
		exe_location = MY_CONFIG.get("real-cugan", "exe_location")
		self.ui.txt_settings_cugan_location.setText(exe_location)

		scale = int(MY_CONFIG.get("real-cugan", "scale"))
		self.ui.spin_settings_cugan_scale.setValue(scale)

		denoise_level = int(MY_CONFIG.get("real-cugan", "denoise_level"))
		self.ui.cbx_settings_cugan_denoise.setCurrentIndex(denoise_level+1)

		resize = int(MY_CONFIG.get("real-cugan", "resize"))
		self.ui.cbx_settings_cugan_resize.setCurrentIndex(resize)

		#misc
		display_message = MY_CONFIG.get("misc", "display_message")
		if display_message == "False":
			self.ui.radio_settings_message_no.setChecked(True)
		else:
			self.ui.radio_settings_message_yes.setChecked(True)
		play_sound = MY_CONFIG.get("misc", "play_sound")
		if play_sound == "False":
			self.ui.radio_settings_sound_no.setChecked(True)
		else:
			self.ui.radio_settings_sound_yes.setChecked(True)
		when_close_window = MY_CONFIG.get("misc", "when_close_window")
		self.ui.cbx_settings_when_close_window.setCurrentIndex(int(when_close_window))

		pass

	def save_config(self):
		global WEB_BOT, EXECUTOR
		#print("try save")
		#general
		MY_CONFIG.set("general","download_folder",self.ui.txt_settings_general_folder.text())
		MY_CONFIG.set("general","max_retry",str(self.ui.spin_settings_max_retry.value()))
		MY_CONFIG.set("general","timeout",str(self.ui.spin_settings_timeout.value()))
		MY_CONFIG.set("general","agent",self.ui.cbx_settings_user_agent.currentText())
		MY_CONFIG.set("general","book_padding",str(self.ui.spin_settings_book_padding.value()))
		MY_CONFIG.set("general","chapter_padding",str(self.ui.spin_settings_chapter_padding.value()))
		MY_CONFIG.set("general","image_padding",str(self.ui.spin_settings_image_padding.value()))
		MY_CONFIG.set("general","jpg_quality",str(self.ui.spin_settings_jpg_quality.value()))
		MY_CONFIG.set("general","check_is_2_page",str(self.ui.spin_settings_check_is_2_page.value()))
		MY_CONFIG.set("reader","background",self.ui.txt_settings_reader_background.text())
		MY_CONFIG.set("reader","auto_play_interval",str(self.ui.spin_settings_reader_auto_play_interval.value()))
		MY_CONFIG.set("reader","auto_play_pgb",str(self.ui.cbx_settings_reader_auto_play_pgb.currentIndex()))
		MY_CONFIG.set("reader","page_gap",str(self.ui.spin_settings_reader_page_gap.value()))

		#anti ban
		MY_CONFIG.set("anti-ban","page_sleep",str(self.ui.spin_settings_page_sleep.value()))
		MY_CONFIG.set("anti-ban","image_sleep",str(self.ui.spin_settings_image_sleep.value()))
		MY_CONFIG.set("anti-ban","download_worker",str(self.ui.spin_settings_download_worker.value()))
		MY_CONFIG.set("anti-ban","proxy_mode",str(self.ui.cbx_settings_proxy_mode.currentIndex()))
		MY_CONFIG.set("anti-ban","proxy_list",json.dumps(self.proxy_list_to_json()))

		#real-cugan
		MY_CONFIG.set("real-cugan","exe_location",self.ui.txt_settings_cugan_location.text())
		MY_CONFIG.set("real-cugan","scale",str(self.ui.spin_settings_cugan_scale.value()))
		MY_CONFIG.set("real-cugan","denoise_level",str(self.ui.cbx_settings_cugan_denoise.currentIndex()-1))
		MY_CONFIG.set("real-cugan","resize",str(self.ui.cbx_settings_cugan_resize.currentIndex()))

		#misc
		MY_CONFIG.set("misc","display_message",str(self.ui.radio_settings_message_yes.isChecked()))
		MY_CONFIG.set("misc","play_sound",str(self.ui.radio_settings_sound_yes.isChecked()))
		MY_CONFIG.set("misc","when_close_window",str(self.ui.cbx_settings_when_close_window.currentIndex()))

		MY_CONFIG.save()

		WEB_BOT.set_agent(MY_CONFIG.get("general", "agent"))
		WEB_BOT.set_time_out(float(MY_CONFIG.get("general", "timeout")))
		WEB_BOT.set_max_retry(int(MY_CONFIG.get("general", "max_retry")))
		WEB_BOT.set_proxy_mode(int(MY_CONFIG.get("anti-ban", "proxy_mode")))
		WEB_BOT.set_proxy_list(MY_CONFIG.get("anti-ban", "proxy_list"))

		EXECUTOR = concurrent.futures.ThreadPoolExecutor(max_workers=int(MY_CONFIG.get("anti-ban", "download_worker")))

	def try_add_proxy(self,proxy):
		if self.check_proxy_exist_in_list(proxy):
			return False
		item = QListWidgetItem()
		item.setText(proxy)
		item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
		item.setCheckState(QtCore.Qt.Checked)
		self.ui.list_settings_proxy.addItem(item)
		return True

	def check_proxy_format(self,proxy):
		pattern_proxy = re.compile(r'http([s]?)://(.*?):([0-9]*)')
		proxy_info = re.findall(pattern_proxy, proxy)
		if len(proxy_info) == 1 and len(proxy_info[0]) == 3:
			return True
		return False

	def check_proxy_exist_in_list(self,proxy):
		for i in range(self.ui.list_settings_proxy.count()):
			item = self.ui.list_settings_proxy.item(i)
			if item.text() == proxy:
				return True
		return False

	def proxy_list_to_json(self):
		result = []
		for i in range(self.ui.list_settings_proxy.count()):
			item = self.ui.list_settings_proxy.item(i)
			result.append({
				"enable": item.checkState() == QtCore.Qt.Checked,
				"url": item.text(),
			})
		return result


import os
import sys
import pathlib
import pandas as pd
import pymrio as pym
import pickle as pkl
import logging
import argparse
import json
import re
from pymrio.core.mriosystem import IOSystem

SEC_AGG_ODS_FILENAME = "exiobase3_aggregate_to_7_sectors.ods"
PARAMS_ODS_FILENAME ="exiobase3_7_sectors_params.ods"
EXIO3_MONETARY = 1000000
MAIN_INVENTORY_DURATION = 90
PARAMS = {
    # The directory to use to store results (relative to output_dir)
    "results_storage": "results",
    # This tells the model to register the evolution of the stocks
    # of every industry (the file can be quite large (2Gbytes+ for
    # a 365 days simulation with exiobase))
    "register_stocks": True,
    # Parameters of the model (we detail these in the documentation)
   "psi_param": 0.85,
   "order_type": "alt",
   # Time division of a year in the model (365 == day, 52 == week, ...)
   "year_to_temporal_unit_factor": 365,
    # Number of day|week|... of one step of the model (ie time sampling)
   "n_temporal_units_by_step": 1,
    # Charateristic time of inventory restoration
   "inventory_restoration_tau": 60,
    # Base overproduction factor
   "alpha_base": 1.0,
    # Maximum overproduction factor
   "alpha_max": 1.25,
    # Charateristic time of overproduction
   "alpha_tau": 365,
    # Charateristic time of rebuilding
   "rebuild_tau": 60,
    # Number of day|week|... to simulate
   "n_temporal_units_to_sim": 700,
    # Unused
   "min_duration": 700
}

def lexico_reindex(mrio: pym.IOSystem) -> pym.IOSystem:
    """Reindex IOSystem lexicographicaly

    Sort indexes and columns of the dataframe of a :ref:`pymrio.IOSystem` by
    lexical order.

    Parameters
    ----------
    mrio : pym.IOSystem
        The IOSystem to sort

    Returns
    -------
    pym.IOSystem
        The sorted IOSystem

    """

    mrio.Z = mrio.Z.reindex(sorted(mrio.Z.index), axis=0)
    mrio.Z = mrio.Z.reindex(sorted(mrio.Z.columns), axis=1)
    mrio.Y = mrio.Y.reindex(sorted(mrio.Y.index), axis=0)
    mrio.Y = mrio.Y.reindex(sorted(mrio.Y.columns), axis=1)
    mrio.x = mrio.x.reindex(sorted(mrio.x.index), axis=0) #type: ignore
    mrio.A = mrio.A.reindex(sorted(mrio.A.index), axis=0)
    mrio.A = mrio.A.reindex(sorted(mrio.A.columns), axis=1)

    return mrio

def full_mrio_pickle(exio3, save_path=None):
    scriptLogger.info("Removing IOSystem attributes deemed unnecessary")
    attr = ['Z', 'Y', 'x', 'A', 'L', 'unit', 'population', 'meta', '__non_agg_attributes__', '__coefficients__', '__basic__']
    tmp = list(exio3.__dict__.keys())
    for at in tmp:
        if at not in attr:
            delattr(exio3,at)
    assert isinstance(exio3, IOSystem)
    scriptLogger.info("Done")
    scriptLogger.info("Computing the missing IO components")
    exio3.calc_all()
    scriptLogger.info("Done")
    scriptLogger.info("Reindexing the dataframes lexicographicaly")
    exio3 = lexico_reindex(exio3)
    scriptLogger.info("Done")
    scriptLogger.info("Saving Full mrio pickle file to {}".format(pathlib.Path(save_path).absolute()))
    exio3 = lexico_reindex(exio3)
    with open(save_path, 'wb') as f:
        pkl.dump(exio3, f)

def aggreg_mrio_pickle(full_exio_path, sector_aggregator_path, save_path=None):
    exio_path = pathlib.Path(full_exio_path)
    if not exio_path.exists():
        raise FileNotFoundError("Exiobase file not found - {}".format(exio_path))
    with exio_path.open('rb') as f:
        scriptLogger.info("Loading EXIOBASE3 from {}".format(exio_path.resolve()))
        exio3 = pkl.load(f)
    assert isinstance(exio3, IOSystem)
    sec_agg_vec = pd.read_excel(sector_aggregator_path, sheet_name="aggreg_input", engine="odf")
    sec_agg_newnames = pd.read_excel(sector_aggregator_path, sheet_name="name_input", engine="odf", index_col=0, squeeze=True)
    sec_agg_vec = sec_agg_vec.sort_values(by="sector")
    scriptLogger.info("Reading aggregation matrix from sheet 'input' in file {}".format(pathlib.Path(sector_aggregator_path).absolute()))
    scriptLogger.info("Aggregating from {} to {} sectors".format(len(exio3.get_sectors()), len(sec_agg_vec.group.unique()))) #type:ignore
    sec_agg_vec['new_sectors'] = sec_agg_vec.group.map(sec_agg_newnames.to_dict())
    exio3.aggregate(sector_agg=sec_agg_vec.new_sectors.values)
    exio3.calc_all()
    scriptLogger.info("Done")
    scriptLogger.info("Saving to {}".format(pathlib.Path(save_path).absolute()))
    exio3 = lexico_reindex(exio3)
    with open(save_path, 'wb') as f:
        pkl.dump(exio3, f)

def params_from_ods(ods_file,monetary,main_inv_dur):
    mrio_params = {}
    mrio_params["monetary_factor"] = monetary
    mrio_params["main_inv_dur"] = main_inv_dur
    df = pd.read_excel(ods_file) #type: ignore
    mrio_params["capital_ratio_dict"] = df[["Aggregated version sector", "Capital to VA ratio"]].set_index("Aggregated version sector").to_dict()['Capital to VA ratio']
    mrio_params["inventories_dict"] = df[["Aggregated version sector", "Inventory size (days)"]].set_index("Aggregated version sector").to_dict()['Inventory size (days)']
    return mrio_params

def event_tmpl_from_ods(ods_file):
    event_params = {}
    event_params["aff_regions"] = ["FR"]
    event_params["dmg_distrib_regions"] = [1]
    event_params["dmg_distrib_sectors_type"] = "gdp"
    event_params["dmg_distrib_sectors"] = []
    event_params["duration"] = 5
    event_params["name"] = "Test-event"
    event_params["occur"] = 7
    event_params["q_dmg"] = 1000000
    df = pd.read_excel(ods_file) #type: ignore
    event_params["aff_sectors"] = df.loc[(df.Affected=="yes"),"Aggregated version sector"].to_list()
    event_params["rebuilding_sectors"] = df.loc[(df["Rebuilding factor"] > 0),["Aggregated version sector", "Rebuilding factor"]].set_index("Aggregated version sector").to_dict()['Rebuilding factor']
    return event_params

parser = argparse.ArgumentParser(description="Build a minimal example for BoARIO, from EXIOBASE3 MRIO table zip file")
parser.add_argument('source_path', type=str, help='The str path to the directory with source materials')
parser.add_argument('-o', "--output", type=str, help='The path to the example directory to create', nargs='?', default='./testing-directory/')

args = parser.parse_args()
logFormatter = logging.Formatter("%(asctime)s [%(levelname)-5.5s] %(name)s %(message)s", datefmt="%H:%M:%S")
scriptLogger = logging.getLogger("EXIOBASE3_Minimal_example_generator")
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)

scriptLogger.addHandler(consoleHandler)
scriptLogger.setLevel(logging.INFO)
scriptLogger.propagate = False

if __name__ == '__main__':
    args = parser.parse_args()
    scriptLogger.info("Make sure you use the same python environment when you use the minimal example as now.")
    scriptLogger.info("Your current environment is: {}".format(sys.executable))

    sec_agg_ods = pathlib.Path(args.source_path)/SEC_AGG_ODS_FILENAME
    params_ods = pathlib.Path(args.source_path)/PARAMS_ODS_FILENAME
    output_dir = pathlib.Path(args.output)
    # Create full mrio pickle file

    if not output_dir.exists():
        output_dir.mkdir(parents=True, exist_ok=True)
    full_exio_pickle_name = "exiobase3_full.pkl"
    minimal_exio_name = "exiobase3_minimal.pkl"
    params_file_name = "params.json"
    mrio_params_file_name = "mrio_params.json"
    event_file_name = "event.json"
    scriptLogger.info("This will create the following directory, with all required files for the minimal example : {}".format(output_dir.resolve()))

    if not sec_agg_ods.exists():
        raise FileNotFoundError("Sector aggregator ods file not found - {}".format(sec_agg_ods))

    if not params_ods.exists():
        raise FileNotFoundError("Params ods file not found - {}".format(params_ods))

    if not (output_dir/full_exio_pickle_name).exists():
        regex = re.compile(r"(IOT_\d\d\d\d_ixi.zip)")
        exio_path = None
        for root, dirs, files in os.walk(args.source_path):
            scriptLogger.info("Looking for Exiobase3 file here {}".format(args.source_path))
            for f in files:
                if regex.match(f):
                    exio_path = (pathlib.Path(args.source_path)/f).resolve()
                    scriptLogger.info("Found Exiobase3 file here {}".format(exio_path))
                    break

        if exio_path is None:
            raise FileNotFoundError("Exiobase file not found in given source directory - {}".format(args.source_path))

        scriptLogger.info("Parsing EXIOBASE3 from {} - Note that this takes a few minutes on a powerful laptop. ".format(exio_path.resolve()))
        exio3 = pym.parse_exiobase3(path=exio_path)
        full_mrio_pickle(exio3, save_path=output_dir/full_exio_pickle_name)

    # create minimal mrio pickle file
    if not (output_dir/minimal_exio_name).exists():
        aggreg_mrio_pickle(output_dir/full_exio_pickle_name, sector_aggregator_path=sec_agg_ods, save_path=output_dir/minimal_exio_name)

    # create params file
    if not (output_dir/params_file_name).exists():
        scriptLogger.info("Generating simulation parameters file : {}".format((output_dir/params_file_name).resolve()))
        params = PARAMS
        params["output_dir"] = str(output_dir.resolve())
        with (output_dir/params_file_name).open("w") as f:
            json.dump(params, f, indent=4)

    # create mrio_params_file
    if not (output_dir/mrio_params_file_name).exists():
        scriptLogger.info("Generating mrio parameters file : {}".format((output_dir/mrio_params_file_name).resolve()))
        mrio_params = params_from_ods(params_ods, EXIO3_MONETARY, MAIN_INVENTORY_DURATION)
        with (output_dir/mrio_params_file_name).open("w") as f:
            json.dump(mrio_params, f, indent=4)

    # create mrio_params_file
    if not (output_dir/event_file_name).exists():
        scriptLogger.info("Generating event file : {}".format((output_dir/event_file_name).resolve()))
        event_params = event_tmpl_from_ods(params_ods)
        with (output_dir/event_file_name).open("w") as f:
            json.dump(event_params, f, indent=4)

    scriptLogger.info("Done !")


import random
import itertools
import math
import json

from functions.counting import counting
from functions.multi_arithematic import multiple_operations_two_ops
from functions.single_arithematic import single_arithematic
from functions.avg_val import average_point_value
from functions.permutation_combination import permutations
from functions.permutation_combination import combinations
from functions.probability import probability_questions
from functions.comparisions import comparison_questions
from functions.logical import logical_questions
from functions.number_theory import number_theory_questions
from functions.graph_theory import generate_graph_theory_questions
from functions.pattern_recognition import pattern_recognition_questions
from functions.geometry import generate_shape_questions
from functions.clock import generate_clock_time_questions

from functions.algorithmic_reasoning import knapsack_questions
from functions.algorithmic_reasoning import greedy_questions
from functions.algorithmic_reasoning import sort_and_median_questions
from functions.algorithmic_reasoning import recursion_questions

from functions.temporal import temporal_questions
from functions.incomplete_question import incomplete_questions

from functions.spatial_reasoning import spatial_reasoning_questions

plural_dictionary = {
    "fruit": "fruits",
    "apple": "apples",
    "orange": "oranges",
    "banana": "bananas",
    "strawberry": "strawberries",
    "grape": "grapes",

    "vegetable": "vegetables",
    "carrot": "carrots",
    "broccoli": "broccoli",
    "tomato": "tomatoes",
    "potato": "potatoes",
    "cabbage": "cabbages",

    "animal": "animals",
    "dog": "dogs",
    "cat": "cats",
    "elephant": "elephants",
    "giraffe": "giraffes",
    "dolphin": "dolphins",

    "geometry": "geometries",
    "triangle": "triangles",
    "square": "squares",
    "pentagon": "pentagons",
    "hexagon": "hexagons",
    "octagon": "octagons",

    "clock" : "clocks",

}

object_dictionary = {
    "fruit": {
        "items": [
            "apple",
            "orange",
            # "banana",
            # "strawberry",
            # "grape",
        ],
        "range": [1]
    },

    "vegetable": {
        "items": [
            "carrot",
            "broccoli",
            # "tomato",
            # "potato",
            # "cabbage"
        ],
        "range": [1]
    },

    "animal":{
        "items": [
            "dog",
            "cat",
            # "elephant",
            # "giraffe",
            # "dolphin"
        ],
        "range": [1]
    },

    "geometry": {
        "items": [
            "triangle",
            "square",
            "pentagon",
            "hexagon",
            "octagon"
    ],
    "range": [1]
    },

    "clock": {
        "items": [
            "clock 1",
            "clock 2",
            "clock 3",
            "clock 4",
            "clock 5",
            "clock 6",
            "clock 7",
            "clock 8",
            "clock 9",
            "clock 10",
            "clock 11",
            "clock 12"
    ],
    "range": [1]
}

}

def determine_object_type(sampled_items):
    categories = set()
    for item in sampled_items:
        for category, details in object_dictionary.items():
            if item in details["items"]:
                categories.add(category)
                break

    if len(sampled_items) == 1:
        return "single_object"
    elif len(categories) == 1:
        return "intra_category"
    else:
        return "inter_category"

def test_create_QA():
    obj_to_return = []
    question_item = {'clock 1': 1, 'square':2, 'orange': 4}
    object_key = determine_object_type([item for item in question_item.keys()])
    qa_pairs = []

    # qa_pairs += counting(question_item, object_key)
    # qa_pairs += multiple_operations_two_ops(question_item, object_key)
    # qa_pairs += single_arithematic(question_item, object_key)
    # qa_pairs += average_point_value(question_item, object_key)
    # qa_pairs += permutations(question_item, object_key)
    # qa_pairs += combinations(question_item, object_key)
    # qa_pairs += probability_questions(question_item, object_key)
    # qa_pairs += comparison_questions(question_item, object_key)
    # qa_pairs += logical_questions(question_item, object_key)
    # qa_pairs += number_theory_questions(question_item, object_key)
    # qa_pairs += generate_graph_theory_questions(question_item, object_key)
    # qa_pairs += pattern_recognition_questions(question_item, object_key)
    # qa_pairs += knapsack_questions(question_item, object_key)
    # qa_pairs += greedy_questions(question_item, object_key)
    # qa_pairs += sort_and_median_questions(question_item, object_key)
    # qa_pairs += recursion_questions(question_item, object_key)
    # qa_pairs += temporal_questions(question_item, object_key)
    # qa_pairs += incomplete_questions(question_item, object_key)
    # qa_pairs += spatial_reasoning_questions(question_item, object_key)
    # qa_pairs += generate_shape_questions(question_item, object_key)
    qa_pairs += generate_clock_time_questions(question_item, object_key)

    obj_to_return.append({
        "obj_json": question_item,
        "qa_pairs": qa_pairs,
    })

    return obj_to_return

def create_QA():
    obj_to_return = []
    total_questions = 0

    # Flatten the items across all categories
    all_items = []
    for category, details in object_dictionary.items():
        all_items.extend(details["items"])

    items_range = [1, 5]  # A generic range for simplicity

    for L in range(1, len(all_items) + 1):
        if L<=9:
            for sampled_items in itertools.combinations(all_items, L):

                object_type = determine_object_type(sampled_items)
                number_of_objects = len(sampled_items)
                item_count_values = [i for i in range(items_range[0], items_range[1] + 1)]
                lists = [item_count_values] * number_of_objects

                for combination in itertools.product(*lists):
                    index = 0
                    qa_pairs = []
                    question_item = {}
                    for item in sampled_items:
                        item_count = combination[index]
                        question_item[item] = item_count
                        index += 1

                    # Now, we generate questions for these combinations
                    qa_pairs += counting(question_item, object_type)
                    # qa_pairs += multiple_operations_two_ops_extended(number_of_objects, sampled_items, question_item)

                    obj_to_return.append({
                        "obj_json": question_item,
                        "qa_pairs": qa_pairs,
                    })
                    total_questions += len(qa_pairs)

    print(f"Total questions: {total_questions}")
    return obj_to_return

if __name__ == "__main__":

    file_path = 'D:\MLMM_ASU\MLLM_Evaluation_Scale\display3.json'
    with open(file_path, 'w') as f:
        json.dump(test_create_QA(), f)


# @Author: Billy Li <billyli>
# @Date:   06-05-2022
# @Email:  li000400@umn.edu
# @Last modified by:   billyli
# @Last modified time: 06-06-2022

import sys
from pathlib import Path
import shutil

import numpy as np
from scipy.stats import uniform

data_dir = Path.cwd().parent.joinpath("data")
sys.path.insert(1, str(data_dir))

from hit_generator import stochastic
from util import plot_in_RAM, small_helix_check, hits2arc
from information import *

def discretize(x, min, max, res):
    # return the discretized index of a value given a range and resolution
    step = (max-min)/res
    result = (x-min)//step
    if result >= res:
        result = res-1
    return int(result)

def xy2map(xs, ys, res):
    # return a z-t ptcl number map
    map = np.zeros(shape=(res,res), dtype=float)
    xmin, xmax = -810, 810
    ymin, ymax = -810, 810

    for x, y in zip(xs, ys):
        xIdx = discretize(x, xmin, xmax, res)
        yIdx = discretize(y, ymin, ymax, res)
        map[res-1-yIdx, xIdx] = 1.0

    return map

# feature_dir_default =
def make_data_single_track(feature_dir):

    feature_dir.mkdir(parents=True, exist_ok=True)

    ### set dataset property
    # Number of samples
    N_data = 100
    N_generated = 0
    # quality cut
    dx_min = 100
    dy_min = 100
    res = 256

    # set track source (db files)
    track_dir = Path.cwd().parent.parent.joinpath('data').joinpath('raw')
    db_list = ["train_CeEndpoint-mix-fromCSV_1.db",
               "train_CeEndpoint-mix-fromCSV_2.db",\
               "train_CeEndpoint-mix-fromCSV_3.db"]
    file_list = [track_dir.joinpath(db) for db in db_list]

    # set track distribution
    dist = uniform(loc=1, scale=0)

    # set track generator
    gen = stochastic(dist=dist, db_files=file_list, hitNumCut=20)

    X = []
    Y = []
    while N_generated < N_data:
        hit_dict = gen.generate(mode='production')
        if small_helix_check(hit_dict,dx_min=dx_min,dy_min=dy_min):
            continue
        else:
            sys.stdout.write(t_info(f'Finding qualified track: {N_generated+1}/{N_data}', special='\r'))
            if N_generated+1 == N_data:
                sys.stdout.write('\n')
            sys.stdout.flush()

            x = plot_in_RAM(hit_dict, res)
            x = x.reshape(res,res)
            X.append(x)

            a, b, R = hits2arc(hit_dict)
            y = xy2map([a], [b], int(res/8))
            N_generated += 1
            Y.append(y)

    X = np.array(X)
    Y = np.array(Y)

    X_file = feature_dir.joinpath("X.npy")
    Y_file = feature_dir.joinpath("Y.npy")
    np.save(X_file, X)
    np.save(Y_file, Y)

    return

if __name__ == "__main__":
    data_dir = Path.cwd().parent.parent.joinpath("data")
    feature_dir = data_dir.joinpath("interm").joinpath("single_track")
    make_data_single_track(feature_dir)


from collections import defaultdict
from sys import maxint

class Solution(object):
    def getClosest(self, S, t):
        closest = None
        minDiff = maxint
        for k, x in S:
            diff = abs(t - x)
            if diff < minDiff:
                minDiff = diff
                closest = k, x
        return closest

    def minTransfers(self, transactions):
        """
        :type transactions: List[List[int]]
        :rtype: int
        """
        snd = lambda t: t[1]
        balance = defaultdict(lambda: 0)
        for x, y, z in transactions:
            balance[x] += z
            balance[y] -= z
        pos, neg = [], []
        for k, b in balance.iteritems():
            if b > 0:
                pos.append((k, b))
            elif b < 0:
                neg.append((k, -b))
        opers = 0
        while neg:
            kn, negBal = max(neg, key=snd)
            neg.remove((kn, negBal))
            kp, posBal = self.getClosest(pos, negBal)
            pos.remove((kp, posBal))
            rem = negBal - posBal
            if rem > 0:
                neg.append((kn, rem))
            elif rem < 0:
                pos.append((kp, -rem))
            opers += 1
        return opers

# trans = [[0,1,10],[2,0,5]]
# trans = [[0,1,10], [1,0,1], [1,2,5], [2,0,5]]
trans = [[1, 8, 1], [1, 13, 21], [2, 8, 10], [3, 9, 20], [4, 10, 61],
         [5, 11, 61], [6, 12, 59], [7, 13, 60]]
print(Solution().minTransfers(trans))